<commit_before>//===-- DisassemblerLLVM.cpp ------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "DisassemblerLLVM.h"

#include "llvm-c/EnhancedDisassembly.h"

#include "lldb/Core/Address.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/SymbolContext.h"

#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"

#include <memory>
#include <string>

using namespace lldb;
using namespace lldb_private;

static
int DataExtractorByteReader(uint8_t *byte, uint64_t address, void *arg)
{
    DataExtractor &extractor = *((DataExtractor *)arg);

    if (extractor.ValidOffset(address))
    {
        *byte = *(extractor.GetDataStart() + address);
        return 0;
    }
    else
    {
        return -1;
    }
}

namespace {
    struct RegisterReaderArg {
        const lldb::addr_t instructionPointer;
        const EDDisassemblerRef disassembler;

        RegisterReaderArg(lldb::addr_t ip,
                          EDDisassemblerRef dis) :
            instructionPointer(ip),
            disassembler(dis)
        {
        }
    };
}

static int IPRegisterReader(uint64_t *value, unsigned regID, void* arg)
{
    uint64_t instructionPointer = ((RegisterReaderArg*)arg)->instructionPointer;
    EDDisassemblerRef disassembler = ((RegisterReaderArg*)arg)->disassembler;

    if(EDRegisterIsProgramCounter(disassembler, regID)) {
        *value = instructionPointer;
        return 0;
    }

    return -1;
}

DisassemblerLLVM::InstructionLLVM::InstructionLLVM (EDDisassemblerRef disassembler, const Address &addr) :
    Instruction (addr),
    m_disassembler (disassembler)
{
}

DisassemblerLLVM::InstructionLLVM::~InstructionLLVM()
{
}

static void
PadString(Stream *s, const std::string &str, size_t width)
{
    int diff = width - str.length();

    if (diff > 0)
        s->Printf("%s%*.*s", str.c_str(), diff, diff, "");
    else
        s->Printf("%s ", str.c_str());
}

void
DisassemblerLLVM::InstructionLLVM::Dump
(
    Stream *s,
    bool show_address,
    const DataExtractor *bytes,
    uint32_t bytes_offset,
    const lldb_private::ExecutionContext* exe_ctx,
    bool raw
)
{
    const size_t opcodeColumnWidth = 7;
    const size_t operandColumnWidth = 25;

    ExecutionContextScope *exe_scope = NULL;
    if (exe_ctx)
        exe_scope = exe_ctx->GetBestExecutionContextScope();

    // If we have an address, print it out
    if (GetAddress().IsValid() && show_address)
    {
        if (GetAddress().Dump (s,
                               exe_scope,
                               Address::DumpStyleLoadAddress,
                               Address::DumpStyleModuleWithFileAddress,
                               0))
            s->PutCString(":  ");
    }

    // If we are supposed to show bytes, "bytes" will be non-NULL.
    if (bytes)
    {
        uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
        // Allow for 8 bytes of opcodes normally
        const uint32_t default_num_opcode_bytes = 9;
        if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
        {
            uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3);
            s->Printf("%*.*s", indent_level, indent_level, "");
        }
    }

    int numTokens = EDNumTokens(m_inst);

    int currentOpIndex = -1;

    std::auto_ptr<RegisterReaderArg> rra;

    if (!raw)
    {
        addr_t base_addr = LLDB_INVALID_ADDRESS;
        if (exe_ctx && exe_ctx->target && !exe_ctx->target->GetSectionLoadList().IsEmpty())
            base_addr = GetAddress().GetLoadAddress (exe_ctx->target);
        if (base_addr == LLDB_INVALID_ADDRESS)
            base_addr = GetAddress().GetFileAddress ();

        rra.reset(new RegisterReaderArg(base_addr + EDInstByteSize(m_inst), m_disassembler));
    }

    bool printTokenized = false;

    if (numTokens != -1)
    {
        printTokenized = true;

        // Handle the opcode column.

        StreamString opcode;

        int tokenIndex = 0;

        EDTokenRef token;
        const char *tokenStr;

        if (EDGetToken(&token, m_inst, tokenIndex))
            printTokenized = false;

        if (!printTokenized || !EDTokenIsOpcode(token))
            printTokenized = false;

        if (!printTokenized || EDGetTokenString(&tokenStr, token))
            printTokenized = false;

        // Put the token string into our opcode string
        opcode.PutCString(tokenStr);

        // If anything follows, it probably starts with some whitespace.  Skip it.

        tokenIndex++;

        if (printTokenized && tokenIndex < numTokens)
        {
            if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
                printTokenized = false;

            if(!printTokenized || !EDTokenIsWhitespace(token))
                printTokenized = false;
        }

        tokenIndex++;

        // Handle the operands and the comment.

        StreamString operands;
        StreamString comment;

        if (printTokenized)
        {
            bool show_token;

            for (; tokenIndex < numTokens; ++tokenIndex)
            {
                if (EDGetToken(&token, m_inst, tokenIndex))
                    return;

                if (raw)
                {
                    show_token = true;
                }
                else
                {
                    int operandIndex = EDOperandIndexForToken(token);

                    if (operandIndex >= 0)
                    {
                        if (operandIndex != currentOpIndex)
                        {
                            show_token = true;

                            currentOpIndex = operandIndex;
                            EDOperandRef operand;

                            if (!EDGetOperand(&operand, m_inst, currentOpIndex))
                            {
                                if (EDOperandIsMemory(operand))
                                {
                                    uint64_t operand_value;

                                    if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, rra.get()))
                                    {
                                        if (EDInstIsBranch(m_inst))
                                        {
                                            operands.Printf("0x%llx ", operand_value);
                                            show_token = false;
                                        }
                                        else
                                        {
                                            // Put the address value into the comment
                                            comment.Printf("0x%llx ", operand_value);
                                        }

                                        lldb_private::Address so_addr;
                                        if (exe_ctx && exe_ctx->target && !exe_ctx->target->GetSectionLoadList().IsEmpty())
                                        {
                                            if (exe_ctx->target->GetSectionLoadList().ResolveLoadAddress (operand_value, so_addr))
                                                so_addr.Dump(&comment, exe_scope, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset);
                                        }
                                        else
                                        {
                                            Module *module = GetAddress().GetModule();
                                            if (module)
                                            {
                                                if (module->ResolveFileAddress (operand_value, so_addr))
                                                    so_addr.Dump(&comment, exe_scope, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset);
                                            }
                                        }

                                    } // EDEvaluateOperand
                                } // EDOperandIsMemory
                            } // EDGetOperand
                        } // operandIndex != currentOpIndex
                    } // operandIndex >= 0
                } // else(raw)

                if (show_token)
                {
                    if(EDGetTokenString(&tokenStr, token))
                    {
                        printTokenized = false;
                        break;
                    }

                    operands.PutCString(tokenStr);
                }
            } // for (tokenIndex)

            if (printTokenized)
            {
                if (operands.GetString().empty())
                {
                    s->PutCString(opcode.GetString().c_str());
                }
                else
                {
                    PadString(s, opcode.GetString(), opcodeColumnWidth);

                    if (comment.GetString().empty())
                    {
                        s->PutCString(operands.GetString().c_str());
                    }
                    else
                    {
                        PadString(s, operands.GetString(), operandColumnWidth);

                        s->PutCString("; ");
                        s->PutCString(comment.GetString().c_str());
                    } // else (comment.GetString().empty())
                } // else (operands.GetString().empty())
            } // printTokenized
        } // for (tokenIndex)
    } // numTokens != -1

    if (!printTokenized)
    {
        const char *str;

        if (EDGetInstString(&str, m_inst))
            return;
        else
            s->PutCString(str);
    }
}

bool
DisassemblerLLVM::InstructionLLVM::DoesBranch() const
{
    return EDInstIsBranch(m_inst);
}

size_t
DisassemblerLLVM::InstructionLLVM::GetByteSize() const
{
    return EDInstByteSize(m_inst);
}

size_t
DisassemblerLLVM::InstructionLLVM::Extract(const DataExtractor &data, uint32_t data_offset)
{
    if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
        return EDInstByteSize(m_inst);
    else
        return 0;
}

static inline const char *
TripleForArchSpec (const ArchSpec &arch, char *triple, size_t triple_len)
{
    const char *arch_name = arch.AsCString();

    if (arch_name)
    {
        snprintf(triple, triple_len, "%s-unknown-unknown", arch_name);
        return triple;
    }
    return NULL;
}

static inline EDAssemblySyntax_t
SyntaxForArchSpec (const ArchSpec &arch)
{
    const char *arch_name = arch.AsCString();

    if (arch_name != NULL &&
       ((strcasestr (arch_name, "i386") == arch_name) ||
        (strcasestr (arch_name, "x86_64") == arch_name)))
        return kEDAssemblySyntaxX86ATT;

    return (EDAssemblySyntax_t)0;   // default
}

Disassembler *
DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
{
    char triple[256];

    if (TripleForArchSpec (arch, triple, sizeof(triple)))
        return new DisassemblerLLVM(arch);
    return NULL;
}

DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
    Disassembler(arch)
{
    char triple[256];
    if (TripleForArchSpec (arch, triple, sizeof(triple)))
    {
        assert(!EDGetDisassembler(&m_disassembler, triple, SyntaxForArchSpec (arch)) && "No disassembler created!");
    }
}

DisassemblerLLVM::~DisassemblerLLVM()
{
}

size_t
DisassemblerLLVM::DecodeInstructions
(
    const Address &base_addr,
    const DataExtractor& data,
    uint32_t data_offset,
    uint32_t num_instructions
)
{
    size_t total_inst_byte_size = 0;

    m_instruction_list.Clear();

    while (data.ValidOffset(data_offset) && num_instructions)
    {
        Address inst_addr (base_addr);
        inst_addr.Slide(data_offset);
        InstructionSP inst_sp (new InstructionLLVM(m_disassembler, inst_addr));

        size_t inst_byte_size = inst_sp->Extract (data, data_offset);

        if (inst_byte_size == 0)
            break;

        m_instruction_list.Append (inst_sp);

        total_inst_byte_size += inst_byte_size;
        data_offset += inst_byte_size;
        num_instructions--;
    }

    return total_inst_byte_size;
}

void
DisassemblerLLVM::Initialize()
{
    PluginManager::RegisterPlugin (GetPluginNameStatic(),
                                   GetPluginDescriptionStatic(),
                                   CreateInstance);
}

void
DisassemblerLLVM::Terminate()
{
    PluginManager::UnregisterPlugin (CreateInstance);
}

const char *
DisassemblerLLVM::GetPluginNameStatic()
{
    return "disassembler.llvm";
}

const char *
DisassemblerLLVM::GetPluginDescriptionStatic()
{
    return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
}

//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
const char *
DisassemblerLLVM::GetPluginName()
{
    return "DisassemblerLLVM";
}

const char *
DisassemblerLLVM::GetShortPluginName()
{
    return GetPluginNameStatic();
}

uint32_t
DisassemblerLLVM::GetPluginVersion()
{
    return 1;
}

void
DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
{
}

Error
DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
{
    Error error;
    error.SetErrorString("No plug-in command are currently supported.");
    return error;
}

Log *
DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
{
    return NULL;
}

<commit_msg>Fixed the "-b" option on disassembly to always pad out the bytes with for i386 and for x86_64 to allow 15 byte opcodes to be displayed. This outputs clean looking disassembly when the bytes are shown.<commit_after>//===-- DisassemblerLLVM.cpp ------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "DisassemblerLLVM.h"

#include "llvm-c/EnhancedDisassembly.h"

#include "lldb/Core/Address.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/SymbolContext.h"

#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"

#include <memory>
#include <string>

using namespace lldb;
using namespace lldb_private;

static
int DataExtractorByteReader(uint8_t *byte, uint64_t address, void *arg)
{
    DataExtractor &extractor = *((DataExtractor *)arg);

    if (extractor.ValidOffset(address))
    {
        *byte = *(extractor.GetDataStart() + address);
        return 0;
    }
    else
    {
        return -1;
    }
}

namespace {
    struct RegisterReaderArg {
        const lldb::addr_t instructionPointer;
        const EDDisassemblerRef disassembler;

        RegisterReaderArg(lldb::addr_t ip,
                          EDDisassemblerRef dis) :
            instructionPointer(ip),
            disassembler(dis)
        {
        }
    };
}

static int IPRegisterReader(uint64_t *value, unsigned regID, void* arg)
{
    uint64_t instructionPointer = ((RegisterReaderArg*)arg)->instructionPointer;
    EDDisassemblerRef disassembler = ((RegisterReaderArg*)arg)->disassembler;

    if(EDRegisterIsProgramCounter(disassembler, regID)) {
        *value = instructionPointer;
        return 0;
    }

    return -1;
}

DisassemblerLLVM::InstructionLLVM::InstructionLLVM (EDDisassemblerRef disassembler, const Address &addr) :
    Instruction (addr),
    m_disassembler (disassembler)
{
}

DisassemblerLLVM::InstructionLLVM::~InstructionLLVM()
{
}

static void
PadString(Stream *s, const std::string &str, size_t width)
{
    int diff = width - str.length();

    if (diff > 0)
        s->Printf("%s%*.*s", str.c_str(), diff, diff, "");
    else
        s->Printf("%s ", str.c_str());
}

void
DisassemblerLLVM::InstructionLLVM::Dump
(
    Stream *s,
    bool show_address,
    const DataExtractor *bytes,
    uint32_t bytes_offset,
    const lldb_private::ExecutionContext* exe_ctx,
    bool raw
)
{
    const size_t opcodeColumnWidth = 7;
    const size_t operandColumnWidth = 25;

    ExecutionContextScope *exe_scope = NULL;
    if (exe_ctx)
        exe_scope = exe_ctx->GetBestExecutionContextScope();

    // If we have an address, print it out
    if (GetAddress().IsValid() && show_address)
    {
        if (GetAddress().Dump (s,
                               exe_scope,
                               Address::DumpStyleLoadAddress,
                               Address::DumpStyleModuleWithFileAddress,
                               0))
            s->PutCString(":  ");
    }

    // If we are supposed to show bytes, "bytes" will be non-NULL.
    if (bytes)
    {
        uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
        // Allow for 15 bytes of opcodes since this is the max for x86_64.
        // TOOD: We need to taylor this better for different architectures. For
        // ARM we would want to show 16 bit opcodes for Thumb as properly byte
        // swapped uint16_t values, or 32 bit values swapped values for ARM.
        const uint32_t default_num_opcode_bytes = 15;
        if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
        {
            uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3) + 1;
            s->Printf("%*.*s", indent_level, indent_level, "");
        }
    }

    int numTokens = EDNumTokens(m_inst);

    int currentOpIndex = -1;

    std::auto_ptr<RegisterReaderArg> rra;

    if (!raw)
    {
        addr_t base_addr = LLDB_INVALID_ADDRESS;
        if (exe_ctx && exe_ctx->target && !exe_ctx->target->GetSectionLoadList().IsEmpty())
            base_addr = GetAddress().GetLoadAddress (exe_ctx->target);
        if (base_addr == LLDB_INVALID_ADDRESS)
            base_addr = GetAddress().GetFileAddress ();

        rra.reset(new RegisterReaderArg(base_addr + EDInstByteSize(m_inst), m_disassembler));
    }

    bool printTokenized = false;

    if (numTokens != -1)
    {
        printTokenized = true;

        // Handle the opcode column.

        StreamString opcode;

        int tokenIndex = 0;

        EDTokenRef token;
        const char *tokenStr;

        if (EDGetToken(&token, m_inst, tokenIndex))
            printTokenized = false;

        if (!printTokenized || !EDTokenIsOpcode(token))
            printTokenized = false;

        if (!printTokenized || EDGetTokenString(&tokenStr, token))
            printTokenized = false;

        // Put the token string into our opcode string
        opcode.PutCString(tokenStr);

        // If anything follows, it probably starts with some whitespace.  Skip it.

        tokenIndex++;

        if (printTokenized && tokenIndex < numTokens)
        {
            if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
                printTokenized = false;

            if(!printTokenized || !EDTokenIsWhitespace(token))
                printTokenized = false;
        }

        tokenIndex++;

        // Handle the operands and the comment.

        StreamString operands;
        StreamString comment;

        if (printTokenized)
        {
            bool show_token;

            for (; tokenIndex < numTokens; ++tokenIndex)
            {
                if (EDGetToken(&token, m_inst, tokenIndex))
                    return;

                if (raw)
                {
                    show_token = true;
                }
                else
                {
                    int operandIndex = EDOperandIndexForToken(token);

                    if (operandIndex >= 0)
                    {
                        if (operandIndex != currentOpIndex)
                        {
                            show_token = true;

                            currentOpIndex = operandIndex;
                            EDOperandRef operand;

                            if (!EDGetOperand(&operand, m_inst, currentOpIndex))
                            {
                                if (EDOperandIsMemory(operand))
                                {
                                    uint64_t operand_value;

                                    if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, rra.get()))
                                    {
                                        if (EDInstIsBranch(m_inst))
                                        {
                                            operands.Printf("0x%llx ", operand_value);
                                            show_token = false;
                                        }
                                        else
                                        {
                                            // Put the address value into the comment
                                            comment.Printf("0x%llx ", operand_value);
                                        }

                                        lldb_private::Address so_addr;
                                        if (exe_ctx && exe_ctx->target && !exe_ctx->target->GetSectionLoadList().IsEmpty())
                                        {
                                            if (exe_ctx->target->GetSectionLoadList().ResolveLoadAddress (operand_value, so_addr))
                                                so_addr.Dump(&comment, exe_scope, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset);
                                        }
                                        else
                                        {
                                            Module *module = GetAddress().GetModule();
                                            if (module)
                                            {
                                                if (module->ResolveFileAddress (operand_value, so_addr))
                                                    so_addr.Dump(&comment, exe_scope, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset);
                                            }
                                        }

                                    } // EDEvaluateOperand
                                } // EDOperandIsMemory
                            } // EDGetOperand
                        } // operandIndex != currentOpIndex
                    } // operandIndex >= 0
                } // else(raw)

                if (show_token)
                {
                    if(EDGetTokenString(&tokenStr, token))
                    {
                        printTokenized = false;
                        break;
                    }

                    operands.PutCString(tokenStr);
                }
            } // for (tokenIndex)

            if (printTokenized)
            {
                if (operands.GetString().empty())
                {
                    s->PutCString(opcode.GetString().c_str());
                }
                else
                {
                    PadString(s, opcode.GetString(), opcodeColumnWidth);

                    if (comment.GetString().empty())
                    {
                        s->PutCString(operands.GetString().c_str());
                    }
                    else
                    {
                        PadString(s, operands.GetString(), operandColumnWidth);

                        s->PutCString("; ");
                        s->PutCString(comment.GetString().c_str());
                    } // else (comment.GetString().empty())
                } // else (operands.GetString().empty())
            } // printTokenized
        } // for (tokenIndex)
    } // numTokens != -1

    if (!printTokenized)
    {
        const char *str;

        if (EDGetInstString(&str, m_inst))
            return;
        else
            s->PutCString(str);
    }
}

bool
DisassemblerLLVM::InstructionLLVM::DoesBranch() const
{
    return EDInstIsBranch(m_inst);
}

size_t
DisassemblerLLVM::InstructionLLVM::GetByteSize() const
{
    return EDInstByteSize(m_inst);
}

size_t
DisassemblerLLVM::InstructionLLVM::Extract(const DataExtractor &data, uint32_t data_offset)
{
    if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
        return EDInstByteSize(m_inst);
    else
        return 0;
}

static inline const char *
TripleForArchSpec (const ArchSpec &arch, char *triple, size_t triple_len)
{
    const char *arch_name = arch.AsCString();

    if (arch_name)
    {
        snprintf(triple, triple_len, "%s-unknown-unknown", arch_name);
        return triple;
    }
    return NULL;
}

static inline EDAssemblySyntax_t
SyntaxForArchSpec (const ArchSpec &arch)
{
    const char *arch_name = arch.AsCString();

    if (arch_name != NULL &&
       ((strcasestr (arch_name, "i386") == arch_name) ||
        (strcasestr (arch_name, "x86_64") == arch_name)))
        return kEDAssemblySyntaxX86ATT;

    return (EDAssemblySyntax_t)0;   // default
}

Disassembler *
DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
{
    char triple[256];

    if (TripleForArchSpec (arch, triple, sizeof(triple)))
        return new DisassemblerLLVM(arch);
    return NULL;
}

DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
    Disassembler(arch)
{
    char triple[256];
    if (TripleForArchSpec (arch, triple, sizeof(triple)))
    {
        assert(!EDGetDisassembler(&m_disassembler, triple, SyntaxForArchSpec (arch)) && "No disassembler created!");
    }
}

DisassemblerLLVM::~DisassemblerLLVM()
{
}

size_t
DisassemblerLLVM::DecodeInstructions
(
    const Address &base_addr,
    const DataExtractor& data,
    uint32_t data_offset,
    uint32_t num_instructions
)
{
    size_t total_inst_byte_size = 0;

    m_instruction_list.Clear();

    while (data.ValidOffset(data_offset) && num_instructions)
    {
        Address inst_addr (base_addr);
        inst_addr.Slide(data_offset);
        InstructionSP inst_sp (new InstructionLLVM(m_disassembler, inst_addr));

        size_t inst_byte_size = inst_sp->Extract (data, data_offset);

        if (inst_byte_size == 0)
            break;

        m_instruction_list.Append (inst_sp);

        total_inst_byte_size += inst_byte_size;
        data_offset += inst_byte_size;
        num_instructions--;
    }

    return total_inst_byte_size;
}

void
DisassemblerLLVM::Initialize()
{
    PluginManager::RegisterPlugin (GetPluginNameStatic(),
                                   GetPluginDescriptionStatic(),
                                   CreateInstance);
}

void
DisassemblerLLVM::Terminate()
{
    PluginManager::UnregisterPlugin (CreateInstance);
}

const char *
DisassemblerLLVM::GetPluginNameStatic()
{
    return "disassembler.llvm";
}

const char *
DisassemblerLLVM::GetPluginDescriptionStatic()
{
    return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
}

//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
const char *
DisassemblerLLVM::GetPluginName()
{
    return "DisassemblerLLVM";
}

const char *
DisassemblerLLVM::GetShortPluginName()
{
    return GetPluginNameStatic();
}

uint32_t
DisassemblerLLVM::GetPluginVersion()
{
    return 1;
}

void
DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
{
}

Error
DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
{
    Error error;
    error.SetErrorString("No plug-in command are currently supported.");
    return error;
}

Log *
DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
{
    return NULL;
}

<|endoftext|>


<commit_before>#include <cstring>
#include <string>
#include "halley/bytes/byte_serializer.h"

#include "halley/text/halleystring.h"

using namespace Halley;

SerializerState* ByteSerializationBase::setState(SerializerState* s)
{
	const auto oldState = state;
	state = s;
	return oldState;
}

Serializer::Serializer(SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, dryRun(true)
{}

Serializer::Serializer(gsl::span<gsl::byte> dst, SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, dst(dst)
	, dryRun(false)
{}

Serializer& Serializer::operator<<(const std::string& str)
{
	return *this << String(str);
}

Serializer& Serializer::operator<<(const String& str)
{
	if (options.version == 0) {
		const uint32_t sz = static_cast<uint32_t>(str.size());
		*this << sz;
		*this << gsl::as_bytes(gsl::span<const char>(str.c_str(), sz));
	} else {
		if (options.stringToIndex) {
			auto idx = options.stringToIndex(str);
			if (idx) {
				// Found, store index with bit 0 set to 1
				const uint64_t value = uint64_t(options.exhaustiveDictionary ? idx.value() : (size_t(1) | (idx.value() << 1)));
				*this << value;
			} else {
				if (options.exhaustiveDictionary) {
					throw Exception("String \"" + str + "\" not found in serialization dictionary, but it's marked as exhaustive.", HalleyExceptions::Utils);
				}

				// Not found, store it with bit 0 set to 0
				const uint64_t sz = uint64_t(str.size());
				*this << (sz << 1);
				*this << gsl::as_bytes(gsl::span<const char>(str.c_str(), sz));
			}
		} else {
			// No dictionary, just store it old style
			const uint64_t sz = str.size();
			*this << sz;
			*this << gsl::as_bytes(gsl::span<const char>(str.c_str(), sz));
		}
	}
	return *this;
}

Serializer& Serializer::operator<<(const Path& path)
{
	return (*this << path.string());
}

Serializer& Serializer::operator<<(gsl::span<const gsl::byte> span)
{
	if (!dryRun) {
		memcpy(dst.data() + size, span.data(), span.size_bytes());
	}
	size += span.size_bytes();
	return *this;
}

Serializer& Serializer::operator<<(const Bytes& bytes)
{
	const uint32_t byteSize = static_cast<uint32_t>(bytes.size());
	*this << byteSize;

	if (!dryRun) {
		memcpy(dst.data() + size, bytes.data(), bytes.size());
	}
	size += bytes.size();
	return *this;
}

void Serializer::serializeVariableInteger(uint64_t val, std::optional<bool> sign)
{
	// 7  0sxxxxxx
	// 14 10sxxxxx xxxxxxxx
	// 21 110sxxxx xxxxxxxx xxxxxxxx
	// 28 1110sxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 35 11110sxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 42 111110sx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 49 1111110s xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 56 11111110 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 64 11111111 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

	const size_t nBits = size_t(std::max(fastLog2Ceil(val), 1)) + (sign ? 1 : 0);
	const size_t nBytes = std::min((nBits - 1) / 7, size_t(8)) + 1; // Total length of this sequence
	std::array<uint8_t, 9> buffer;
	buffer.fill(0);

	if (val == 0) {
		int a = 0;
	}

	// Combine sign into value
	uint64_t toWrite = val;
	if (sign) {
		const size_t signPos = nBytes * 7 + (nBytes == 9 ? 0 : -1); // 9-byte version places it on pos 63, not 62
		toWrite |= uint64_t(sign.value() ? 1 : 0) << signPos;
	}

	// Write header
	// To generate the mask, we get 9 - nBytes to see how many zeroes we need (8 at 1 byte, 7 at 2 bytes, etc), generate that many "1"s, then xor that with 255 (0b11111111) to flip those bits
	const size_t headerBits = std::min(nBytes, size_t(7));
	buffer[0] = uint8_t(255) ^ (uint8_t((1 << (9 - headerBits)) - 1));

	// Write bits
	size_t bitsAvailableOnByte = 8 - headerBits;
	size_t bitsToWrite = nBits;
	size_t curPos = 0;

	while (bitsToWrite > 0) {
		const size_t nBits = std::min(bitsToWrite, bitsAvailableOnByte);
		const uint64_t mask = (uint64_t(1) << bitsAvailableOnByte) - 1;

		buffer[curPos] |= toWrite & mask;

		toWrite >>= nBits;
		bitsAvailableOnByte = 8;
		curPos++;
		bitsToWrite -= nBits;
	}

	*this << gsl::as_bytes(gsl::span<const uint8_t>(buffer.data(), curPos));
}

Deserializer::Deserializer(gsl::span<const gsl::byte> src, SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, src(src)
{
}

Deserializer::Deserializer(const Bytes& src, SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, src(gsl::as_bytes(gsl::span<const Halley::Byte>(src)))
{
}

Deserializer& Deserializer::operator>>(std::string& str)
{
	String s;
	*this >> s;
	str = s.cppStr();
	return *this;
}

Deserializer& Deserializer::operator>>(String& str)
{
	auto readRawString = [&] (size_t size)
	{
		ensureSufficientBytesRemaining(size);
		str = String(reinterpret_cast<const char*>(src.data() + pos), size);
		pos += size;
	};

	if (options.version == 0) {
		uint32_t size;
		*this >> size;
		readRawString(size);
	} else {
		uint64_t value;
		*this >> value;

		if (options.indexToString) {
			if (options.exhaustiveDictionary || (value & 0x1) != 0) {
				// Indexed string
				int shift = options.exhaustiveDictionary ? 0 : 1;
				str = options.indexToString(value >> shift);
			} else {
				// Not indexed
				readRawString(value >> 1);
			}
		} else {
			// No dictionary
			readRawString(value);
		}
	}

	return *this;
}

Deserializer& Deserializer::operator>>(Path& p)
{
	std::string s;
	*this >> s;
	p = s;
	return *this;
}

Deserializer& Deserializer::operator>>(gsl::span<gsl::byte> span)
{
	if (span.empty()) {
		return *this;
	}
	Expects(span.size_bytes() > 0);

	ensureSufficientBytesRemaining(size_t(span.size_bytes()));

	memcpy(span.data(), src.data() + pos, span.size_bytes());
	pos += span.size_bytes();
	return *this;
}

Deserializer& Deserializer::operator>>(Bytes& bytes)
{
	uint32_t sz;
	*this >> sz;
	ensureSufficientBytesRemaining(sz);
	bytes.resize(sz);

	auto dst = gsl::as_writable_bytes(gsl::span<Byte>(bytes));
	*this >> dst;
	return *this;
}

void Deserializer::deserializeVariableInteger(uint64_t& val, bool& sign, bool isSigned)
{
	// 7  0sxxxxxx
	// 14 10sxxxxx xxxxxxxx
	// 21 110sxxxx xxxxxxxx xxxxxxxx
	// 28 1110sxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 35 11110sxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 42 111110sx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 49 1111110s xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 56 11111110 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 64 11111111 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

	// Read header
	std::array<uint8_t, 9> buffer;
	*this >> gsl::as_writable_bytes(gsl::span<uint8_t>(buffer.data(), 1));
	uint8_t& header = buffer[0];

	// Figure out which pattern we're dealing with
	size_t nBytes = 0;
	if ((header & 0x80) != 0x80) {
		nBytes = 1;
	} else if ((header & 0xC0) != 0xC0) {
		nBytes = 2;
	} else if ((header & 0xE0) != 0xE0) {
		nBytes = 3;
	} else if ((header & 0xF0) != 0xF0) {
		nBytes = 4;
	} else if ((header & 0xF8) != 0xF8) {
		nBytes = 5;
	} else if ((header & 0xFC) != 0xFC) {
		nBytes = 6;
	} else if ((header & 0xFE) != 0xFE) {
		nBytes = 7;
	} else if ((header & 0xFF) != 0xFF) {
		nBytes = 8;
	} else {
		nBytes = 9;
	}
	const size_t headerBits = std::min(nBytes, size_t(7));

	// Read rest of the data
	if (nBytes > 1) {
		*this >> gsl::as_writable_bytes(gsl::span<uint8_t>(buffer.data() + 1, nBytes - 1));
	}

	// Convert to uint64_t
	size_t bitsAvailableOnByte = 8 - headerBits;
	size_t bitsRead = 0;
	uint64_t value = 0;
	for (size_t i = 0; i < nBytes; ++i) {
		const uint64_t byteMask = (uint64_t(1) << bitsAvailableOnByte) - 1;
		value |= (uint64_t(buffer[i]) & byteMask) << bitsRead;
		bitsRead += bitsAvailableOnByte;
		bitsAvailableOnByte = 8;
	}

	// Restore sign
	if (isSigned) {
		const size_t signPos = nBytes * 7 + (nBytes == 9 ? 0 : -1); // 9-byte version places it on pos 63, not 62
		const uint64_t signMask = uint64_t(1) << signPos;
		sign = (value & signMask) != 0;
		value &= ~signMask;
	} else {
		sign = false;
	}

	// Output value
	val = value;
}

void Deserializer::ensureSufficientBytesRemaining(size_t bytes)
{
	if (bytes > getBytesRemaining()) {
		throw Exception("Attempt to deserialize out of bounds", HalleyExceptions::File);
	}
}

size_t Deserializer::getBytesRemaining() const
{
	if (pos > size_t(src.size_bytes())) {
		return 0;
	} else {
		return size_t(src.size_bytes()) - pos;
	}
}
<commit_msg>Remove debug code<commit_after>#include <cstring>
#include <string>
#include "halley/bytes/byte_serializer.h"

#include "halley/text/halleystring.h"

using namespace Halley;

SerializerState* ByteSerializationBase::setState(SerializerState* s)
{
	const auto oldState = state;
	state = s;
	return oldState;
}

Serializer::Serializer(SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, dryRun(true)
{}

Serializer::Serializer(gsl::span<gsl::byte> dst, SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, dst(dst)
	, dryRun(false)
{}

Serializer& Serializer::operator<<(const std::string& str)
{
	return *this << String(str);
}

Serializer& Serializer::operator<<(const String& str)
{
	if (options.version == 0) {
		const uint32_t sz = static_cast<uint32_t>(str.size());
		*this << sz;
		*this << gsl::as_bytes(gsl::span<const char>(str.c_str(), sz));
	} else {
		if (options.stringToIndex) {
			auto idx = options.stringToIndex(str);
			if (idx) {
				// Found, store index with bit 0 set to 1
				const uint64_t value = uint64_t(options.exhaustiveDictionary ? idx.value() : (size_t(1) | (idx.value() << 1)));
				*this << value;
			} else {
				if (options.exhaustiveDictionary) {
					throw Exception("String \"" + str + "\" not found in serialization dictionary, but it's marked as exhaustive.", HalleyExceptions::Utils);
				}

				// Not found, store it with bit 0 set to 0
				const uint64_t sz = uint64_t(str.size());
				*this << (sz << 1);
				*this << gsl::as_bytes(gsl::span<const char>(str.c_str(), sz));
			}
		} else {
			// No dictionary, just store it old style
			const uint64_t sz = str.size();
			*this << sz;
			*this << gsl::as_bytes(gsl::span<const char>(str.c_str(), sz));
		}
	}
	return *this;
}

Serializer& Serializer::operator<<(const Path& path)
{
	return (*this << path.string());
}

Serializer& Serializer::operator<<(gsl::span<const gsl::byte> span)
{
	if (!dryRun) {
		memcpy(dst.data() + size, span.data(), span.size_bytes());
	}
	size += span.size_bytes();
	return *this;
}

Serializer& Serializer::operator<<(const Bytes& bytes)
{
	const uint32_t byteSize = static_cast<uint32_t>(bytes.size());
	*this << byteSize;

	if (!dryRun) {
		memcpy(dst.data() + size, bytes.data(), bytes.size());
	}
	size += bytes.size();
	return *this;
}

void Serializer::serializeVariableInteger(uint64_t val, std::optional<bool> sign)
{
	// 7  0sxxxxxx
	// 14 10sxxxxx xxxxxxxx
	// 21 110sxxxx xxxxxxxx xxxxxxxx
	// 28 1110sxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 35 11110sxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 42 111110sx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 49 1111110s xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 56 11111110 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 64 11111111 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

	const size_t nBits = size_t(std::max(fastLog2Ceil(val), 1)) + (sign ? 1 : 0);
	const size_t nBytes = std::min((nBits - 1) / 7, size_t(8)) + 1; // Total length of this sequence
	std::array<uint8_t, 9> buffer;
	buffer.fill(0);

	// Combine sign into value
	uint64_t toWrite = val;
	if (sign) {
		const size_t signPos = nBytes * 7 + (nBytes == 9 ? 0 : -1); // 9-byte version places it on pos 63, not 62
		toWrite |= uint64_t(sign.value() ? 1 : 0) << signPos;
	}

	// Write header
	// To generate the mask, we get 9 - nBytes to see how many zeroes we need (8 at 1 byte, 7 at 2 bytes, etc), generate that many "1"s, then xor that with 255 (0b11111111) to flip those bits
	const size_t headerBits = std::min(nBytes, size_t(7));
	buffer[0] = uint8_t(255) ^ (uint8_t((1 << (9 - headerBits)) - 1));

	// Write bits
	size_t bitsAvailableOnByte = 8 - headerBits;
	size_t bitsToWrite = nBits;
	size_t curPos = 0;

	while (bitsToWrite > 0) {
		const size_t nBits = std::min(bitsToWrite, bitsAvailableOnByte);
		const uint64_t mask = (uint64_t(1) << bitsAvailableOnByte) - 1;

		buffer[curPos] |= toWrite & mask;

		toWrite >>= nBits;
		bitsAvailableOnByte = 8;
		curPos++;
		bitsToWrite -= nBits;
	}

	*this << gsl::as_bytes(gsl::span<const uint8_t>(buffer.data(), curPos));
}

Deserializer::Deserializer(gsl::span<const gsl::byte> src, SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, src(src)
{
}

Deserializer::Deserializer(const Bytes& src, SerializerOptions options)
	: ByteSerializationBase(std::move(options))
	, src(gsl::as_bytes(gsl::span<const Halley::Byte>(src)))
{
}

Deserializer& Deserializer::operator>>(std::string& str)
{
	String s;
	*this >> s;
	str = s.cppStr();
	return *this;
}

Deserializer& Deserializer::operator>>(String& str)
{
	auto readRawString = [&] (size_t size)
	{
		ensureSufficientBytesRemaining(size);
		str = String(reinterpret_cast<const char*>(src.data() + pos), size);
		pos += size;
	};

	if (options.version == 0) {
		uint32_t size;
		*this >> size;
		readRawString(size);
	} else {
		uint64_t value;
		*this >> value;

		if (options.indexToString) {
			if (options.exhaustiveDictionary || (value & 0x1) != 0) {
				// Indexed string
				int shift = options.exhaustiveDictionary ? 0 : 1;
				str = options.indexToString(value >> shift);
			} else {
				// Not indexed
				readRawString(value >> 1);
			}
		} else {
			// No dictionary
			readRawString(value);
		}
	}

	return *this;
}

Deserializer& Deserializer::operator>>(Path& p)
{
	std::string s;
	*this >> s;
	p = s;
	return *this;
}

Deserializer& Deserializer::operator>>(gsl::span<gsl::byte> span)
{
	if (span.empty()) {
		return *this;
	}
	Expects(span.size_bytes() > 0);

	ensureSufficientBytesRemaining(size_t(span.size_bytes()));

	memcpy(span.data(), src.data() + pos, span.size_bytes());
	pos += span.size_bytes();
	return *this;
}

Deserializer& Deserializer::operator>>(Bytes& bytes)
{
	uint32_t sz;
	*this >> sz;
	ensureSufficientBytesRemaining(sz);
	bytes.resize(sz);

	auto dst = gsl::as_writable_bytes(gsl::span<Byte>(bytes));
	*this >> dst;
	return *this;
}

void Deserializer::deserializeVariableInteger(uint64_t& val, bool& sign, bool isSigned)
{
	// 7  0sxxxxxx
	// 14 10sxxxxx xxxxxxxx
	// 21 110sxxxx xxxxxxxx xxxxxxxx
	// 28 1110sxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 35 11110sxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 42 111110sx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 49 1111110s xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 56 11111110 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
	// 64 11111111 sxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

	// Read header
	std::array<uint8_t, 9> buffer;
	*this >> gsl::as_writable_bytes(gsl::span<uint8_t>(buffer.data(), 1));
	uint8_t& header = buffer[0];

	// Figure out which pattern we're dealing with
	size_t nBytes = 0;
	if ((header & 0x80) != 0x80) {
		nBytes = 1;
	} else if ((header & 0xC0) != 0xC0) {
		nBytes = 2;
	} else if ((header & 0xE0) != 0xE0) {
		nBytes = 3;
	} else if ((header & 0xF0) != 0xF0) {
		nBytes = 4;
	} else if ((header & 0xF8) != 0xF8) {
		nBytes = 5;
	} else if ((header & 0xFC) != 0xFC) {
		nBytes = 6;
	} else if ((header & 0xFE) != 0xFE) {
		nBytes = 7;
	} else if ((header & 0xFF) != 0xFF) {
		nBytes = 8;
	} else {
		nBytes = 9;
	}
	const size_t headerBits = std::min(nBytes, size_t(7));

	// Read rest of the data
	if (nBytes > 1) {
		*this >> gsl::as_writable_bytes(gsl::span<uint8_t>(buffer.data() + 1, nBytes - 1));
	}

	// Convert to uint64_t
	size_t bitsAvailableOnByte = 8 - headerBits;
	size_t bitsRead = 0;
	uint64_t value = 0;
	for (size_t i = 0; i < nBytes; ++i) {
		const uint64_t byteMask = (uint64_t(1) << bitsAvailableOnByte) - 1;
		value |= (uint64_t(buffer[i]) & byteMask) << bitsRead;
		bitsRead += bitsAvailableOnByte;
		bitsAvailableOnByte = 8;
	}

	// Restore sign
	if (isSigned) {
		const size_t signPos = nBytes * 7 + (nBytes == 9 ? 0 : -1); // 9-byte version places it on pos 63, not 62
		const uint64_t signMask = uint64_t(1) << signPos;
		sign = (value & signMask) != 0;
		value &= ~signMask;
	} else {
		sign = false;
	}

	// Output value
	val = value;
}

void Deserializer::ensureSufficientBytesRemaining(size_t bytes)
{
	if (bytes > getBytesRemaining()) {
		throw Exception("Attempt to deserialize out of bounds", HalleyExceptions::File);
	}
}

size_t Deserializer::getBytesRemaining() const
{
	if (pos > size_t(src.size_bytes())) {
		return 0;
	} else {
		return size_t(src.size_bytes()) - pos;
	}
}
<|endoftext|>


<commit_before>#include "meshoptimizer.hpp"

#include <algorithm>
#include <cassert>
#include <cfloat>
#include <cstring>

namespace
{
	const int kViewport = 256;

	struct Vector3
	{
		float x, y, z;
	};

	struct OverdrawBuffer
	{
		float z[kViewport][kViewport][2];
		unsigned int overdraw[kViewport][kViewport][2];
	};

	inline float det2x2(float a, float b, float c, float d)
	{
		// (a b)
		// (c d)
		return a * d - b * c;
	}

	inline float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
	{
		// z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1)
		// z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1)
		// (x2-x1 y2-y1)(dzdx) = (z2-z1)
		// (x3-x1 y3-y1)(dzdy)   (z3-z1)
		// we'll solve it with Cramer's rule
		float det = det2x2(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
		float invdet = (det == 0) ? 0 : 1 / det;

		dzdx = det2x2(z2 - z1, y2 - y1, z3 - z1, y3 - y1) * invdet;
		dzdy = det2x2(x2 - x1, z2 - z1, x3 - x1, z3 - z1) * invdet;

		return det;
	}

	// half-space fixed point triangle rasterizer
	// adapted from http://forum.devmaster.net/t/advanced-rasterization/6145
	void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z)
	{
		// compute depth gradients
		float DZx, DZy;
		float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
		int sign = det > 0;

		// flip backfacing triangles to simplify rasterization logic
		if (sign)
		{
			std::swap(v2x, v3x);
			std::swap(v2y, v3y);
			std::swap(v2z, v3z);
		}

		// coordinates, 28.4 fixed point
		int X1 = int(16.0f * v1x + 0.5f);
		int X2 = int(16.0f * v2x + 0.5f);
		int X3 = int(16.0f * v3x + 0.5f);

		int Y1 = int(16.0f * v1y + 0.5f);
		int Y2 = int(16.0f * v2y + 0.5f);
		int Y3 = int(16.0f * v3y + 0.5f);

		// bounding rectangle, clipped against viewport
		int minx = std::max((std::min(X1, std::min(X2, X3)) + 0xF) >> 4, 0);
		int maxx = std::min((std::max(X1, std::max(X2, X3)) + 0xF) >> 4, kViewport);
		int miny = std::max((std::min(Y1, std::min(Y2, Y3)) + 0xF) >> 4, 0);
		int maxy = std::min((std::max(Y1, std::max(Y2, Y3)) + 0xF) >> 4, kViewport);

		// deltas, 28.4 fixed point
		int DX12 = X1 - X2;
		int DX23 = X2 - X3;
		int DX31 = X3 - X1;

		int DY12 = Y1 - Y2;
		int DY23 = Y2 - Y3;
		int DY31 = Y3 - Y1;

		// fill convention correction
		int TL1 = DY12 < 0 || (DY12 == 0 && DX12 > 0);
		int TL2 = DY23 < 0 || (DY23 == 0 && DX23 > 0);
		int TL3 = DY31 < 0 || (DY31 == 0 && DX31 > 0);

		// half edge equations, 24.8 fixed point
		int CY1 = DX12 * ((miny << 4) - Y1) - DY12 * ((minx << 4) - X1) + TL1 - 1;
		int CY2 = DX23 * ((miny << 4) - Y2) - DY23 * ((minx << 4) - X2) + TL2 - 1;
		int CY3 = DX31 * ((miny << 4) - Y3) - DY31 * ((minx << 4) - X3) + TL3 - 1;
		float ZY = v1z + (DZx * float((minx << 4) - X1) + DZy * float((miny << 4) - Y1)) * (1 / 16.f);

		for (int y = miny; y < maxy; y++)
		{
			int CX1 = CY1;
			int CX2 = CY2;
			int CX3 = CY3;
			float ZX = ZY;

			for (int x = minx; x < maxx; x++)
			{
				// check if all CXn are non-negative
				if ((CX1 | CX2 | CX3) >= 0)
				{
					float z = sign ? kViewport - ZX : ZX;

					if (z >= buffer->z[y][x][sign])
					{
						buffer->z[y][x][sign] = z;
						buffer->overdraw[y][x][sign]++;
					}
				}

				CX1 -= DY12 << 4;
				CX2 -= DY23 << 4;
				CX3 -= DY31 << 4;
				ZX += DZx;
			}

			CY1 += DX12 << 4;
			CY2 += DX23 << 4;
			CY3 += DX31 << 4;
			ZY += DZy;
		}
	}

	template <typename T>
	OverdrawStatistics analyzeOverdrawImpl(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, size_t vertex_count)
	{
		assert(vertex_positions_stride > 0);
		assert(vertex_positions_stride % sizeof(float) == 0);

		size_t vertex_stride_float = vertex_positions_stride / sizeof(float);

		OverdrawStatistics result = {};

		float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
		float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};

		for (size_t i = 0; i < vertex_count; ++i)
		{
			const float* v = vertex_positions + i * vertex_stride_float;

			for (int j = 0; j < 3; ++j)
			{
				minv[j] = std::min(minv[j], v[j]);
				maxv[j] = std::max(maxv[j], v[j]);
			}
		}

		float extent = std::max(maxv[0] - minv[0], std::max(maxv[1] - minv[1], maxv[2] - minv[2]));
		float scale = kViewport / extent;

		std::vector<Vector3> triangles(index_count);

		for (size_t i = 0; i < index_count; i += 3)
		{
			const float* v0 = vertex_positions + indices[i + 0] * vertex_stride_float;
			const float* v1 = vertex_positions + indices[i + 1] * vertex_stride_float;
			const float* v2 = vertex_positions + indices[i + 2] * vertex_stride_float;

			Vector3 vn0 = {(v0[0] - minv[0]) * scale, (v0[1] - minv[1]) * scale, (v0[2] - minv[2]) * scale};
			Vector3 vn1 = {(v1[0] - minv[0]) * scale, (v1[1] - minv[1]) * scale, (v1[2] - minv[2]) * scale};
			Vector3 vn2 = {(v2[0] - minv[0]) * scale, (v2[1] - minv[1]) * scale, (v2[2] - minv[2]) * scale};

			triangles[i + 0] = vn0;
			triangles[i + 1] = vn1;
			triangles[i + 2] = vn2;
		}

		OverdrawBuffer* buffer = new OverdrawBuffer();

		for (int axis = 0; axis < 3; ++axis)
		{
			memset(buffer, 0, sizeof(OverdrawBuffer));

			for (size_t i = 0; i < index_count; i += 3)
			{
				const float* vn0 = &triangles[i + 0].x;
				const float* vn1 = &triangles[i + 1].x;
				const float* vn2 = &triangles[i + 2].x;

				switch (axis)
				{
				case 0:
					rasterize(buffer, vn0[2], vn0[1], vn0[0], vn1[2], vn1[1], vn1[0], vn2[2], vn2[1], vn2[0]);
					break;
				case 1:
					rasterize(buffer, vn0[0], vn0[2], vn0[1], vn1[0], vn1[2], vn1[1], vn2[0], vn2[2], vn2[1]);
					break;
				case 2:
					rasterize(buffer, vn0[1], vn0[0], vn0[2], vn1[1], vn1[0], vn1[2], vn2[1], vn2[0], vn2[2]);
					break;
				}
			}

			for (int y = 0; y < kViewport; ++y)
				for (int x = 0; x < kViewport; ++x)
					for (int s = 0; s < 2; ++s)
					{
						unsigned int overdraw = buffer->overdraw[y][x][s];

						result.pixels_covered += overdraw > 0;
						result.pixels_shaded += overdraw;
					}
		}

		delete buffer;

		result.overdraw = static_cast<float>(result.pixels_shaded) / static_cast<float>(result.pixels_covered);

		return result;
	}
}

OverdrawStatistics analyzeOverdraw(const unsigned short* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, size_t vertex_count)
{
	return analyzeOverdrawImpl(indices, index_count, vertex_positions, vertex_positions_stride, vertex_count);
}

OverdrawStatistics analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, size_t vertex_count)
{
	return analyzeOverdrawImpl(indices, index_count, vertex_positions, vertex_positions_stride, vertex_count);
}
<commit_msg>overdrawanalyzer: Simplify depth code<commit_after>#include "meshoptimizer.hpp"

#include <algorithm>
#include <cassert>
#include <cfloat>
#include <cstring>

namespace
{
	const int kViewport = 256;

	struct Vector3
	{
		float x, y, z;
	};

	struct OverdrawBuffer
	{
		float z[kViewport][kViewport][2];
		unsigned int overdraw[kViewport][kViewport][2];
	};

	inline float det2x2(float a, float b, float c, float d)
	{
		// (a b)
		// (c d)
		return a * d - b * c;
	}

	inline float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
	{
		// z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1)
		// z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1)
		// (x2-x1 y2-y1)(dzdx) = (z2-z1)
		// (x3-x1 y3-y1)(dzdy)   (z3-z1)
		// we'll solve it with Cramer's rule
		float det = det2x2(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
		float invdet = (det == 0) ? 0 : 1 / det;

		dzdx = det2x2(z2 - z1, y2 - y1, z3 - z1, y3 - y1) * invdet;
		dzdy = det2x2(x2 - x1, z2 - z1, x3 - x1, z3 - z1) * invdet;

		return det;
	}

	// half-space fixed point triangle rasterizer
	// adapted from http://forum.devmaster.net/t/advanced-rasterization/6145
	void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z)
	{
		// compute depth gradients
		float DZx, DZy;
		float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
		int sign = det > 0;

		// flip backfacing triangles to simplify rasterization logic
		if (sign)
		{
			// flipping v2 & v3 preserves depth gradients since they're based on v1
			std::swap(v2x, v3x);
			std::swap(v2y, v3y);
			std::swap(v2z, v3z);

			// flip depth since we rasterize backfacing triangles to second buffer with reverse Z; only v1z is used below
			v1z = kViewport - v1z;
			DZx = -DZx;
			DZy = -DZy;
		}

		// coordinates, 28.4 fixed point
		int X1 = int(16.0f * v1x + 0.5f);
		int X2 = int(16.0f * v2x + 0.5f);
		int X3 = int(16.0f * v3x + 0.5f);

		int Y1 = int(16.0f * v1y + 0.5f);
		int Y2 = int(16.0f * v2y + 0.5f);
		int Y3 = int(16.0f * v3y + 0.5f);

		// bounding rectangle, clipped against viewport
		int minx = std::max((std::min(X1, std::min(X2, X3)) + 0xF) >> 4, 0);
		int maxx = std::min((std::max(X1, std::max(X2, X3)) + 0xF) >> 4, kViewport);
		int miny = std::max((std::min(Y1, std::min(Y2, Y3)) + 0xF) >> 4, 0);
		int maxy = std::min((std::max(Y1, std::max(Y2, Y3)) + 0xF) >> 4, kViewport);

		// deltas, 28.4 fixed point
		int DX12 = X1 - X2;
		int DX23 = X2 - X3;
		int DX31 = X3 - X1;

		int DY12 = Y1 - Y2;
		int DY23 = Y2 - Y3;
		int DY31 = Y3 - Y1;

		// fill convention correction
		int TL1 = DY12 < 0 || (DY12 == 0 && DX12 > 0);
		int TL2 = DY23 < 0 || (DY23 == 0 && DX23 > 0);
		int TL3 = DY31 < 0 || (DY31 == 0 && DX31 > 0);

		// half edge equations, 24.8 fixed point
		int CY1 = DX12 * ((miny << 4) - Y1) - DY12 * ((minx << 4) - X1) + TL1 - 1;
		int CY2 = DX23 * ((miny << 4) - Y2) - DY23 * ((minx << 4) - X2) + TL2 - 1;
		int CY3 = DX31 * ((miny << 4) - Y3) - DY31 * ((minx << 4) - X3) + TL3 - 1;
		float ZY = v1z + (DZx * float((minx << 4) - X1) + DZy * float((miny << 4) - Y1)) * (1 / 16.f);

		for (int y = miny; y < maxy; y++)
		{
			int CX1 = CY1;
			int CX2 = CY2;
			int CX3 = CY3;
			float ZX = ZY;

			for (int x = minx; x < maxx; x++)
			{
				// check if all CXn are non-negative
				if ((CX1 | CX2 | CX3) >= 0)
				{
					if (ZX >= buffer->z[y][x][sign])
					{
						buffer->z[y][x][sign] = ZX;
						buffer->overdraw[y][x][sign]++;
					}
				}

				CX1 -= DY12 << 4;
				CX2 -= DY23 << 4;
				CX3 -= DY31 << 4;
				ZX += DZx;
			}

			CY1 += DX12 << 4;
			CY2 += DX23 << 4;
			CY3 += DX31 << 4;
			ZY += DZy;
		}
	}

	template <typename T>
	OverdrawStatistics analyzeOverdrawImpl(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, size_t vertex_count)
	{
		assert(vertex_positions_stride > 0);
		assert(vertex_positions_stride % sizeof(float) == 0);

		size_t vertex_stride_float = vertex_positions_stride / sizeof(float);

		OverdrawStatistics result = {};

		float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
		float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};

		for (size_t i = 0; i < vertex_count; ++i)
		{
			const float* v = vertex_positions + i * vertex_stride_float;

			for (int j = 0; j < 3; ++j)
			{
				minv[j] = std::min(minv[j], v[j]);
				maxv[j] = std::max(maxv[j], v[j]);
			}
		}

		float extent = std::max(maxv[0] - minv[0], std::max(maxv[1] - minv[1], maxv[2] - minv[2]));
		float scale = kViewport / extent;

		std::vector<Vector3> triangles(index_count);

		for (size_t i = 0; i < index_count; i += 3)
		{
			const float* v0 = vertex_positions + indices[i + 0] * vertex_stride_float;
			const float* v1 = vertex_positions + indices[i + 1] * vertex_stride_float;
			const float* v2 = vertex_positions + indices[i + 2] * vertex_stride_float;

			Vector3 vn0 = {(v0[0] - minv[0]) * scale, (v0[1] - minv[1]) * scale, (v0[2] - minv[2]) * scale};
			Vector3 vn1 = {(v1[0] - minv[0]) * scale, (v1[1] - minv[1]) * scale, (v1[2] - minv[2]) * scale};
			Vector3 vn2 = {(v2[0] - minv[0]) * scale, (v2[1] - minv[1]) * scale, (v2[2] - minv[2]) * scale};

			triangles[i + 0] = vn0;
			triangles[i + 1] = vn1;
			triangles[i + 2] = vn2;
		}

		OverdrawBuffer* buffer = new OverdrawBuffer();

		for (int axis = 0; axis < 3; ++axis)
		{
			memset(buffer, 0, sizeof(OverdrawBuffer));

			for (size_t i = 0; i < index_count; i += 3)
			{
				const float* vn0 = &triangles[i + 0].x;
				const float* vn1 = &triangles[i + 1].x;
				const float* vn2 = &triangles[i + 2].x;

				switch (axis)
				{
				case 0:
					rasterize(buffer, vn0[2], vn0[1], vn0[0], vn1[2], vn1[1], vn1[0], vn2[2], vn2[1], vn2[0]);
					break;
				case 1:
					rasterize(buffer, vn0[0], vn0[2], vn0[1], vn1[0], vn1[2], vn1[1], vn2[0], vn2[2], vn2[1]);
					break;
				case 2:
					rasterize(buffer, vn0[1], vn0[0], vn0[2], vn1[1], vn1[0], vn1[2], vn2[1], vn2[0], vn2[2]);
					break;
				}
			}

			for (int y = 0; y < kViewport; ++y)
				for (int x = 0; x < kViewport; ++x)
					for (int s = 0; s < 2; ++s)
					{
						unsigned int overdraw = buffer->overdraw[y][x][s];

						result.pixels_covered += overdraw > 0;
						result.pixels_shaded += overdraw;
					}
		}

		delete buffer;

		result.overdraw = static_cast<float>(result.pixels_shaded) / static_cast<float>(result.pixels_covered);

		return result;
	}
}

OverdrawStatistics analyzeOverdraw(const unsigned short* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, size_t vertex_count)
{
	return analyzeOverdrawImpl(indices, index_count, vertex_positions, vertex_positions_stride, vertex_count);
}

OverdrawStatistics analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, size_t vertex_count)
{
	return analyzeOverdrawImpl(indices, index_count, vertex_positions, vertex_positions_stride, vertex_count);
}
<|endoftext|>


<commit_before>#include <tools/log.hpp>
#include <hardware/device/FWiegandReader.hpp>
#include "RplethModule.hpp"
#include "rplethprotocol.hpp"

using namespace Leosac::Module::Rpleth;

RplethModule::RplethModule(zmqpp::context &ctx,
        zmqpp::socket *pipe,
        const boost::property_tree::ptree &cfg) :
        BaseModule(ctx, pipe, cfg),
        ctx_(ctx),
        server_(ctx, zmqpp::socket_type::stream),
        bus_sub_(ctx, zmqpp::socket_type::sub),
        reader_(nullptr),
        stream_mode_(false)
{
    process_config();
    bus_sub_.connect("inproc://zmq-bus-pub");
    bus_sub_.subscribe("S_" + reader_->name());
    reactor_.add(server_, std::bind(&RplethModule::handle_socket, this));
    reactor_.add(bus_sub_, std::bind(&RplethModule::handle_wiegand_event, this));
}

RplethModule::~RplethModule()
{
    delete reader_;
}

void RplethModule::process_config()
{
    boost::property_tree::ptree module_config = config_.get_child("module_config");

    uint16_t port = module_config.get<uint16_t>("port", 4242);
    std::string reader_name = module_config.get_child("reader").data();
    stream_mode_ = module_config.get<bool>("stream_mode", false);

    LOG() << "Rpleth module will bind to " << port << " and will control the device nammed " << reader_name
            << "Stream mode = " << stream_mode_;
    reader_ = new FWiegandReader(ctx_, reader_name);
    assert(reader_);
    server_.bind("tcp://*:" + std::to_string(port));
    LOG() << "bind ok";
}

void RplethModule::handle_socket()
{
    zmqpp::message msg;
    std::string identity;
    std::string content;

    server_.receive(msg);
    msg >> identity >> content;

    if (content.size() == 0)
    {
        // handle special 0 length message that indicates connection / disconnection.
        if (client_connected(identity)) // client exists so this is a disconnection message.
        {
            LOG() << "client disconnected";
            clients_.erase(identity);
            if (client_failed(identity))
                failed_clients_.erase(std::remove(failed_clients_.begin(), failed_clients_.end(), identity), failed_clients_.end());
        }
        else
        {
            LOG() << "Client connected";
            clients_[identity];
        }
        return;
    }
    if (client_failed(identity))
        return;
    assert(clients_.count(identity) && !client_failed(identity));
    clients_[identity].write(reinterpret_cast<const uint8_t *> (content.c_str()), content.size());
    if (handle_client_msg(identity, clients_[identity]) == false)
        failed_clients_.push_back(identity);
}

bool RplethModule::handle_client_msg(const std::string &client_identity, CircularBuffer &buf)
{
    RplethPacket packet(RplethPacket::Sender::Client);

    do
    {
        std::array<uint8_t, buffer_size> buffer;
        packet = RplethProtocol::decodeCommand(buf);
        if (!packet.isGood)
            break;
        RplethPacket response = handle_client_packet(packet);
        std::size_t size = RplethProtocol::encodeCommand(response, &buffer[0], buffer_size);

        zmqpp::message msg;
        msg << client_identity;
        msg.add_raw(&buffer[0], size);
        if (!server_.send(msg, true))
        {
            // would block: peer is probably disconnected already.
            return false;
        }
    }
    while (packet.isGood && buf.toRead());
    return true;
}

RplethPacket RplethModule::handle_client_packet(RplethPacket packet)
{
    RplethPacket response = packet;

    LOG() << "received client packet: " << (int) packet.command;
    response.sender = RplethPacket::Sender::Server;
    if (response.type == RplethProtocol::Rpleth && response.command == RplethProtocol::Ping)
    {
        response.status = RplethProtocol::Success;
    }
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Greenled)
        rpleth_greenled(packet);
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Beep)
        rpleth_beep(packet);
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::SendCards)
        rpleth_send_cards(packet);
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::ReceiveCardsWaited)
        response = rpleth_receive_cards(response);
    else
    {
        LOG() << "Unhandled packet.";
        response.status = RplethProtocol::Success; // Default response
    }
    return (response);
}

void RplethModule::handle_wiegand_event()
{
    zmqpp::message msg;
    std::string card_id;

    bus_sub_.receive(msg);
    msg >> card_id >> card_id;

    LOG() << "Rpleth module register card {" << card_id << "}";

    if (stream_mode_)
        cards_read_stream_.push_back(card_id);

    card_id.erase(std::remove(card_id.begin(), card_id.end(), ':'), card_id.end());
    if (std::find(cards_pushed_.begin(), cards_pushed_.end(), card_id) != cards_pushed_.end())
    {
        cards_read_.push_back(card_id);
    }
    else
    {
        // card not found
        LOG() << "This card shouldnt register {" << card_id << "}";
        reader_->beep(1000);
    }

    cards_read_.unique();
    rpleth_publish_card();
}

void RplethModule::rpleth_send_cards(const RplethPacket &packet)
{
    auto itr_start = packet.data.begin();
    std::vector<Byte>::const_iterator my_start = itr_start;
    std::vector<Byte>::const_iterator it;

    LOG() << "Handle_send_cards";
    cards_pushed_.clear();
    cards_read_.clear();

    while (my_start != packet.data.end())
    {
        it = std::find(itr_start, packet.data.end(), '|');
        std::string card;
        while (my_start != packet.data.end() && my_start != it)
        {
            card += *my_start;
            my_start++;
        }
        LOG() << "FOUND CARD {" << card << "}";
        cards_pushed_.push_back(card);
        if (my_start == packet.data.end())
            break;
        else
            my_start++;
        itr_start = ++it;
    }
    cards_pushed_.unique();
}

RplethPacket RplethModule::rpleth_receive_cards(const RplethPacket &packet)
{
    std::list<std::string> to_send;
    RplethPacket response = packet;

    LOG() << "Packet size = " << packet.data.size();
    if (packet.data.size() != 1)
    {
        LOG() << "Invalid Packet";
        return response;
    }
    if (packet.data[0] == 0x01)
    {
        LOG() << "Present list";
        // send present list
        to_send = cards_read_;
    }
    else
    {
        LOG() << "Absent list";
        // send absent list
        to_send = cards_pushed_;
        auto lambda = [this](const std::string &str) -> bool
        {
            // if entry is not in cards_read_ means user was absent, do not remove him
            bool found = std::find(cards_read_.begin(), cards_read_.end(), str) != cards_read_.end();
            return found;
        };
        to_send.erase(std::remove_if(to_send.begin(), to_send.end(), lambda), to_send.end());
    }
    // we reserve approximately what we need, just to avoid useless memory allocations.
    std::vector<Byte> data;
    data.reserve(to_send.size() * 8);
    for (auto &card : to_send)
    {
        LOG() << "Current size of data vector = " << data.size();
        LOG() << "Will store the card {" << card << "} into the rplet packet to send.";
        // we need to convert the card (ff:ae:32:00) to something like "ffae3200"
        card.erase(std::remove(card.begin(), card.end(), ':'), card.end());
        data.insert(data.end(), card.begin(), card.end());
        LOG() << "Card {" << card << "} has been stored into the rplet packet";
        data.push_back('|');
    }
    LOG() << "Built data vector (size = " << data.size() << ")";
    response.data = data;
    response.dataLen = data.size();
    return response;
}

void RplethModule::rpleth_beep(const RplethPacket &packet)
{
    assert(packet.data.size() > 0);
    if (packet.data[0] == 0x01)
        reader_->buzzerOn();
    else if (packet.data[0] == 0x00)
        reader_->buzzerOff();
    else
        LOG() << "Invalid packet";
}

void RplethModule::rpleth_greenled(const RplethPacket &packet)
{
    assert(packet.data.size() > 0);
    if (packet.data[0] == 0x01)
        reader_->greenLedOn();
    else if (packet.data[0] == 0x00)
        reader_->greenLedOff();
    else
        LOG() << "Invalid packet";
}

bool RplethModule::client_connected(const std::string &identity) const
{
    return clients_.count(identity);
}

bool RplethModule::client_failed(const std::string &identity) const
{
    return (std::find(failed_clients_.begin(), failed_clients_.end(), identity) != failed_clients_.end());
}

void RplethModule::rpleth_publish_card()
{
    for (auto const &card : cards_read_stream_)
    {
        for (auto &client : clients_)
        {
            zmqpp::message msg;
            RplethPacket packet(RplethPacket::Sender::Server);

            msg << client.first;
            packet.data = card_convert_from_text(card);
            packet.status = RplethProtocol::Success;
            packet.type = RplethProtocol::HID;
            packet.command = RplethProtocol::Badge;
            packet.dataLen = packet.data.size();

            std::array<uint8_t, 64> buf;
            std::size_t size;
            size = RplethProtocol::encodeCommand(packet, &buf[0], buf.size());
            msg.add_raw(&buf, size);
            if (!server_.send(msg, true))
                failed_clients_.push_back(client.first);
        }
    }
    cards_read_stream_.clear();
}

std::vector<uint8_t> RplethModule::card_convert_from_text(const std::string &card)
{
    std::vector<uint8_t> data;
    std::istringstream iss(card);

    while (!iss.eof())
    {
        unsigned int byte;
        iss >> std::hex >> byte;
        assert(byte <= 255);
        data.push_back(byte);
        // drop the colon delimeter
        char trash;
        iss >> trash;
        assert(trash == ':');
    }
    return data;
}
<commit_msg>Rpleth, do not respond to GreenLed and Beep command.<commit_after>#include <tools/log.hpp>
#include <hardware/device/FWiegandReader.hpp>
#include "RplethModule.hpp"
#include "rplethprotocol.hpp"

using namespace Leosac::Module::Rpleth;

RplethModule::RplethModule(zmqpp::context &ctx,
        zmqpp::socket *pipe,
        const boost::property_tree::ptree &cfg) :
        BaseModule(ctx, pipe, cfg),
        ctx_(ctx),
        server_(ctx, zmqpp::socket_type::stream),
        bus_sub_(ctx, zmqpp::socket_type::sub),
        reader_(nullptr),
        stream_mode_(false)
{
    process_config();
    bus_sub_.connect("inproc://zmq-bus-pub");
    bus_sub_.subscribe("S_" + reader_->name());
    reactor_.add(server_, std::bind(&RplethModule::handle_socket, this));
    reactor_.add(bus_sub_, std::bind(&RplethModule::handle_wiegand_event, this));
}

RplethModule::~RplethModule()
{
    delete reader_;
}

void RplethModule::process_config()
{
    boost::property_tree::ptree module_config = config_.get_child("module_config");

    uint16_t port = module_config.get<uint16_t>("port", 4242);
    std::string reader_name = module_config.get_child("reader").data();
    stream_mode_ = module_config.get<bool>("stream_mode", false);

    LOG() << "Rpleth module will bind to " << port << " and will control the device nammed " << reader_name
            << "Stream mode = " << stream_mode_;
    reader_ = new FWiegandReader(ctx_, reader_name);
    assert(reader_);
    server_.bind("tcp://*:" + std::to_string(port));
    LOG() << "bind ok";
}

void RplethModule::handle_socket()
{
    zmqpp::message msg;
    std::string identity;
    std::string content;

    server_.receive(msg);
    msg >> identity >> content;

    if (content.size() == 0)
    {
        // handle special 0 length message that indicates connection / disconnection.
        if (client_connected(identity)) // client exists so this is a disconnection message.
        {
            LOG() << "client disconnected";
            clients_.erase(identity);
            if (client_failed(identity))
                failed_clients_.erase(std::remove(failed_clients_.begin(), failed_clients_.end(), identity), failed_clients_.end());
        }
        else
        {
            LOG() << "Client connected";
            clients_[identity];
        }
        return;
    }
    if (client_failed(identity))
        return;
    assert(clients_.count(identity) && !client_failed(identity));
    clients_[identity].write(reinterpret_cast<const uint8_t *> (content.c_str()), content.size());
    if (handle_client_msg(identity, clients_[identity]) == false)
        failed_clients_.push_back(identity);
}

bool RplethModule::handle_client_msg(const std::string &client_identity, CircularBuffer &buf)
{
    RplethPacket packet(RplethPacket::Sender::Client);

    do
    {
        std::array<uint8_t, buffer_size> buffer;
        packet = RplethProtocol::decodeCommand(buf);
        if (!packet.isGood)
            break;
        RplethPacket response = handle_client_packet(packet);
        if (response.command == RplethProtocol::HIDCommands::Greenled ||
                response.command == RplethProtocol::HIDCommands::Beep)
            continue;
        std::size_t size = RplethProtocol::encodeCommand(response, &buffer[0], buffer_size);

        zmqpp::message msg;
        msg << client_identity;
        msg.add_raw(&buffer[0], size);
        if (!server_.send(msg, true))
        {
            // would block: peer is probably disconnected already.
            return false;
        }
    }
    while (packet.isGood && buf.toRead());
    return true;
}

RplethPacket RplethModule::handle_client_packet(RplethPacket packet)
{
    RplethPacket response = packet;

    LOG() << "received client packet: " << (int) packet.command;
    response.sender = RplethPacket::Sender::Server;
    if (response.type == RplethProtocol::Rpleth && response.command == RplethProtocol::Ping)
    {
        response.status = RplethProtocol::Success;
    }
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Greenled)
        rpleth_greenled(packet);
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Beep)
        rpleth_beep(packet);
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::SendCards)
        rpleth_send_cards(packet);
    else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::ReceiveCardsWaited)
        response = rpleth_receive_cards(response);
    else
    {
        LOG() << "Unhandled packet.";
        response.status = RplethProtocol::Success; // Default response
    }
    return (response);
}

void RplethModule::handle_wiegand_event()
{
    zmqpp::message msg;
    std::string card_id;

    bus_sub_.receive(msg);
    msg >> card_id >> card_id;

    LOG() << "Rpleth module register card {" << card_id << "}";

    if (stream_mode_)
        cards_read_stream_.push_back(card_id);

    card_id.erase(std::remove(card_id.begin(), card_id.end(), ':'), card_id.end());
    if (std::find(cards_pushed_.begin(), cards_pushed_.end(), card_id) != cards_pushed_.end())
    {
        cards_read_.push_back(card_id);
    }
    else
    {
        // card not found
        LOG() << "This card shouldnt register {" << card_id << "}";
        reader_->beep(1000);
    }

    cards_read_.unique();
    rpleth_publish_card();
}

void RplethModule::rpleth_send_cards(const RplethPacket &packet)
{
    auto itr_start = packet.data.begin();
    std::vector<Byte>::const_iterator my_start = itr_start;
    std::vector<Byte>::const_iterator it;

    LOG() << "Handle_send_cards";
    cards_pushed_.clear();
    cards_read_.clear();

    while (my_start != packet.data.end())
    {
        it = std::find(itr_start, packet.data.end(), '|');
        std::string card;
        while (my_start != packet.data.end() && my_start != it)
        {
            card += *my_start;
            my_start++;
        }
        LOG() << "FOUND CARD {" << card << "}";
        cards_pushed_.push_back(card);
        if (my_start == packet.data.end())
            break;
        else
            my_start++;
        itr_start = ++it;
    }
    cards_pushed_.unique();
}

RplethPacket RplethModule::rpleth_receive_cards(const RplethPacket &packet)
{
    std::list<std::string> to_send;
    RplethPacket response = packet;

    LOG() << "Packet size = " << packet.data.size();
    if (packet.data.size() != 1)
    {
        LOG() << "Invalid Packet";
        return response;
    }
    if (packet.data[0] == 0x01)
    {
        LOG() << "Present list";
        // send present list
        to_send = cards_read_;
    }
    else
    {
        LOG() << "Absent list";
        // send absent list
        to_send = cards_pushed_;
        auto lambda = [this](const std::string &str) -> bool
        {
            // if entry is not in cards_read_ means user was absent, do not remove him
            bool found = std::find(cards_read_.begin(), cards_read_.end(), str) != cards_read_.end();
            return found;
        };
        to_send.erase(std::remove_if(to_send.begin(), to_send.end(), lambda), to_send.end());
    }
    // we reserve approximately what we need, just to avoid useless memory allocations.
    std::vector<Byte> data;
    data.reserve(to_send.size() * 8);
    for (auto &card : to_send)
    {
        LOG() << "Current size of data vector = " << data.size();
        LOG() << "Will store the card {" << card << "} into the rplet packet to send.";
        // we need to convert the card (ff:ae:32:00) to something like "ffae3200"
        card.erase(std::remove(card.begin(), card.end(), ':'), card.end());
        data.insert(data.end(), card.begin(), card.end());
        LOG() << "Card {" << card << "} has been stored into the rplet packet";
        data.push_back('|');
    }
    LOG() << "Built data vector (size = " << data.size() << ")";
    response.data = data;
    response.dataLen = data.size();
    return response;
}

void RplethModule::rpleth_beep(const RplethPacket &packet)
{
    assert(packet.data.size() > 0);
    if (packet.data[0] == 0x01)
        reader_->buzzerOn();
    else if (packet.data[0] == 0x00)
        reader_->buzzerOff();
    else
        LOG() << "Invalid packet";
}

void RplethModule::rpleth_greenled(const RplethPacket &packet)
{
    assert(packet.data.size() > 0);
    if (packet.data[0] == 0x01)
        reader_->greenLedOn();
    else if (packet.data[0] == 0x00)
        reader_->greenLedOff();
    else
        LOG() << "Invalid packet";
}

bool RplethModule::client_connected(const std::string &identity) const
{
    return clients_.count(identity);
}

bool RplethModule::client_failed(const std::string &identity) const
{
    return (std::find(failed_clients_.begin(), failed_clients_.end(), identity) != failed_clients_.end());
}

void RplethModule::rpleth_publish_card()
{
    for (auto const &card : cards_read_stream_)
    {
        for (auto &client : clients_)
        {
            zmqpp::message msg;
            RplethPacket packet(RplethPacket::Sender::Server);

            msg << client.first;
            packet.data = card_convert_from_text(card);
            packet.status = RplethProtocol::Success;
            packet.type = RplethProtocol::HID;
            packet.command = RplethProtocol::Badge;
            packet.dataLen = packet.data.size();

            std::array<uint8_t, 64> buf;
            std::size_t size;
            size = RplethProtocol::encodeCommand(packet, &buf[0], buf.size());
            msg.add_raw(&buf, size);
            if (!server_.send(msg, true))
                failed_clients_.push_back(client.first);
        }
    }
    cards_read_stream_.clear();
}

std::vector<uint8_t> RplethModule::card_convert_from_text(const std::string &card)
{
    std::vector<uint8_t> data;
    std::istringstream iss(card);

    while (!iss.eof())
    {
        unsigned int byte;
        iss >> std::hex >> byte;
        assert(byte <= 255);
        data.push_back(byte);
        // drop the colon delimeter
        char trash;
        iss >> trash;
        assert(trash == ':');
    }
    return data;
}
<|endoftext|>


<commit_before><commit_msg>Fix linking error of app for iOS in optimized build<commit_after><|endoftext|>


<commit_before><commit_msg>Fix fdo#50703 clamp ODF1.2 compatibility-mode to use old encryption.<commit_after><|endoftext|>


<commit_before>#include "IncludeMap.h"

#include <cplusplus/CppDocument.h>

using namespace CPlusPlus;

namespace QtcUtilities {
namespace Internal {
namespace OrganizeIncludes {

Includes intersected (const QSet<QString> &lhs, const Includes &rhs)
{
  Includes result;
  for (const auto &i: rhs) {
    if (lhs.contains (i.file)) {
      result << i;
    }
  }
  return result;
}

IncludeMap::IncludeMap (const Snapshot &snapshot, const Includes &includers,
                        const Includes &includes)
{
  for (const auto &includer: includers) {
    auto interesting = snapshot.allIncludesForDocument (includer.file);
    interesting.insert (includer.file);
    includers_.insert (includer, intersected (interesting, includes));

    for (const auto &included: includers_[includer]) {
      auto &names = includes_[included];
      names <<  (includer);
    }
  }

  for (const auto &i: includes) {
    if (!includes_.contains (i)) {
      includes_.insert (i, {});
    }
  }
}

Includes IncludeMap::includes () const
{
  return includes_.keys ();
}

Includes IncludeMap::includers () const
{
  return includers_.keys ();
}

void IncludeMap::organize (Policy policy)
{
  //TODO do not include internal headers
  switch (policy) {
    case MinimalDepth:
      for (const auto &i: includes ()) {
        removeIncluder (i);
      }
      break;

    case MinimalEntries:
      for (const auto &i: exclusiveIncluders ()) {
        removeIncluder (i);
      }
      while (true) {
        auto biggest = biggestIncluder ();
        if (biggest.file.isEmpty ()) {
          break;
        }
        removeIncluder (biggest);
      }
      break;

    default:
      qCritical () << "Unhandled policy switch";
      break;
  }
}

Includes IncludeMap::exclusiveIncluders () const
{
  Includes result;
  for (const auto &i: includes_.keys ()) {
    auto includers = includersOf (i);
    if (includers.size () == 1) {
      result <<  (*includers.begin ());
    }
  }
  return result;
}

Include IncludeMap::biggestIncluder () const
{
  auto keys = includers_.keys ();
  if (keys.isEmpty ()) {
    return {};
  }
  auto biggest = std::max_element (keys.cbegin (), keys.cend (),
                                   [this](const Include &l, const Include &r) {
          return includers_[l].size () < includers_[r].size ();
        });
  if (includers_[*biggest].isEmpty ()) {
    return {};
  }
  return *biggest;
}

Includes IncludeMap::includersOf (const Include &file) const
{
  return includes_.value (file);
}

void IncludeMap::removeIncluder (const Include &file)
{
  for (const auto &i: includers_.value (file)) {
    for (const auto &ii: includes_[i]) {
      includers_[ii].removeAll (i);
    }
    includes_.remove (i);
  }
  includers_.remove (file);
}

} // namespace OrganizeIncludes
} // namespace Internal
} // namespace QtcUtilities
<commit_msg>Added support of duplicate includers.<commit_after>#include "IncludeMap.h"

#include <cplusplus/CppDocument.h>

using namespace CPlusPlus;

namespace QtcUtilities {
namespace Internal {
namespace OrganizeIncludes {

Includes intersected (const QSet<QString> &lhs, const Includes &rhs)
{
  Includes result;
  for (const auto &i: rhs) {
    if (lhs.contains (i.file)) {
      result << i;
    }
  }
  return result;
}

IncludeMap::IncludeMap (const Snapshot &snapshot, const Includes &includers,
                        const Includes &includes)
{
  for (const auto &includer: includers) {
    auto interesting = snapshot.allIncludesForDocument (includer.file);
    interesting.insert (includer.file);
    includers_.insertMulti (includer, intersected (interesting, includes));

    for (const auto &included: includers_[includer]) {
      auto &names = includes_[included];
      names <<  (includer);
    }
  }

  for (const auto &i: includes) {
    if (!includes_.contains (i)) {
      includes_.insert (i, {});
    }
  }
}

Includes IncludeMap::includes () const
{
  return includes_.keys ();
}

Includes IncludeMap::includers () const
{
  return includers_.keys ();
}

void IncludeMap::organize (Policy policy)
{
  //TODO do not include internal headers
  switch (policy) {
    case MinimalDepth:
      for (const auto &i: includes ()) {
        removeIncluder (i);
      }
      break;

    case MinimalEntries:
      for (const auto &i: exclusiveIncluders ()) {
        removeIncluder (i);
      }
      while (true) {
        auto biggest = biggestIncluder ();
        if (biggest.file.isEmpty ()) {
          break;
        }
        removeIncluder (biggest);
      }
      break;

    default:
      qCritical () << "Unhandled policy switch";
      break;
  }
}

Includes IncludeMap::exclusiveIncluders () const
{
  Includes result;
  for (const auto &i: includes_.keys ()) {
    auto includers = includersOf (i);
    if (includers.size () == 1) {
      result <<  (*includers.begin ());
    }
  }
  return result;
}

Include IncludeMap::biggestIncluder () const
{
  auto keys = includers_.keys ();
  if (keys.isEmpty ()) {
    return {};
  }
  auto biggest = std::max_element (keys.cbegin (), keys.cend (),
                                   [this](const Include &l, const Include &r) {
          return includers_[l].size () < includers_[r].size ();
        });
  if (includers_[*biggest].isEmpty ()) {
    return {};
  }
  return *biggest;
}

Includes IncludeMap::includersOf (const Include &file) const
{
  return includes_.value (file);
}

void IncludeMap::removeIncluder (const Include &file)
{
  for (const auto &i: includers_.value (file)) {
    for (const auto &ii: includes_[i]) {
      includers_[ii].removeAll (i);
    }
    includes_.remove (i);
  }
  includers_.remove (file);
}

} // namespace OrganizeIncludes
} // namespace Internal
} // namespace QtcUtilities
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2014

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2014 Sensics, Inc.
//
// 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.

// Internal Includes
#include <osvr/Connection/DeviceToken.h>
#include "AsyncDeviceToken.h"
#include "SyncDeviceToken.h"
#include "VirtualDeviceToken.h"
#include <osvr/Connection/Connection.h>
#include <osvr/Connection/ConnectionDevice.h>

// Library/third-party includes
// - none

// Standard includes
#include <stdexcept>

using osvr::connection::DeviceTokenPtr;
using osvr::connection::DeviceInitObject;
using osvr::connection::AsyncDeviceToken;
using osvr::connection::SyncDeviceToken;
using osvr::connection::VirtualDeviceToken;
using osvr::connection::ConnectionPtr;
using osvr::connection::MessageType;
using osvr::connection::GuardPtr;
using osvr::connection::ConnectionDevicePtr;
DeviceTokenPtr
OSVR_DeviceTokenObject::createAsyncDevice(DeviceInitObject &init) {
    DeviceTokenPtr ret(new AsyncDeviceToken(init.getQualifiedName()));
    ret->m_sharedInit(init);
    return ret;
}

DeviceTokenPtr
OSVR_DeviceTokenObject::createSyncDevice(DeviceInitObject &init) {
    DeviceTokenPtr ret(new SyncDeviceToken(init.getQualifiedName()));
    ret->m_sharedInit(init);
    return ret;
}

DeviceTokenPtr
OSVR_DeviceTokenObject::createVirtualDevice(std::string const &name,
                                            ConnectionPtr const &conn) {
    DeviceInitObject init(conn);
    init.setName(name);
    DeviceTokenPtr ret(new VirtualDeviceToken(name));
    ret->m_sharedInit(init);
    return ret;
}

OSVR_DeviceTokenObject::OSVR_DeviceTokenObject(std::string const &name)
    : m_name(name) {}

OSVR_DeviceTokenObject::~OSVR_DeviceTokenObject() {}

std::string const &OSVR_DeviceTokenObject::getName() const { return m_name; }

void OSVR_DeviceTokenObject::sendData(MessageType *type, const char *bytestream,
                                      size_t len) {
    osvr::util::time::TimeValue tv;
    osvr::util::time::getNow(tv);
    m_sendData(tv, type, bytestream, len);
}
void OSVR_DeviceTokenObject::sendData(
    osvr::util::time::TimeValue const &timestamp, MessageType *type,
    const char *bytestream, size_t len) {
    m_sendData(timestamp, type, bytestream, len);
}

GuardPtr OSVR_DeviceTokenObject::getSendGuard() { return m_getSendGuard(); }

void OSVR_DeviceTokenObject::setUpdateCallback(
    osvr::connection::DeviceUpdateCallback const &cb) {
    m_setUpdateCallback(cb);
}

void OSVR_DeviceTokenObject::connectionInteract() { m_connectionInteract(); }

void OSVR_DeviceTokenObject::stopThreads() { m_stopThreads(); }

void OSVR_DeviceTokenObject::setDeviceDescriptor(
    std::string const &jsonString) {
    m_getConnectionDevice()->setDeviceDescriptor(jsonString);
    m_getConnection()->triggerDescriptorHandlers();
}

ConnectionPtr OSVR_DeviceTokenObject::m_getConnection() { return m_conn; }

ConnectionDevicePtr OSVR_DeviceTokenObject::m_getConnectionDevice() {
    return m_dev;
}

void OSVR_DeviceTokenObject::m_stopThreads() {}

void OSVR_DeviceTokenObject::m_sharedInit(DeviceInitObject &init) {
    m_conn = init.getConnection();
    m_dev = m_conn->createConnectionDevice(init);
    m_dev->setDeviceToken(*this);
    m_serverInterfaces = init.getServerInterfaces();
    for (auto &iface : m_serverInterfaces) {
        iface->registerMessageTypes(*this);
    }
}
<commit_msg>Device token destructor should stop threads.<commit_after>/** @file
    @brief Implementation

    @date 2014

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2014 Sensics, Inc.
//
// 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.

// Internal Includes
#include <osvr/Connection/DeviceToken.h>
#include "AsyncDeviceToken.h"
#include "SyncDeviceToken.h"
#include "VirtualDeviceToken.h"
#include <osvr/Connection/Connection.h>
#include <osvr/Connection/ConnectionDevice.h>

// Library/third-party includes
// - none

// Standard includes
#include <stdexcept>

using osvr::connection::DeviceTokenPtr;
using osvr::connection::DeviceInitObject;
using osvr::connection::AsyncDeviceToken;
using osvr::connection::SyncDeviceToken;
using osvr::connection::VirtualDeviceToken;
using osvr::connection::ConnectionPtr;
using osvr::connection::MessageType;
using osvr::connection::GuardPtr;
using osvr::connection::ConnectionDevicePtr;
DeviceTokenPtr
OSVR_DeviceTokenObject::createAsyncDevice(DeviceInitObject &init) {
    DeviceTokenPtr ret(new AsyncDeviceToken(init.getQualifiedName()));
    ret->m_sharedInit(init);
    return ret;
}

DeviceTokenPtr
OSVR_DeviceTokenObject::createSyncDevice(DeviceInitObject &init) {
    DeviceTokenPtr ret(new SyncDeviceToken(init.getQualifiedName()));
    ret->m_sharedInit(init);
    return ret;
}

DeviceTokenPtr
OSVR_DeviceTokenObject::createVirtualDevice(std::string const &name,
                                            ConnectionPtr const &conn) {
    DeviceInitObject init(conn);
    init.setName(name);
    DeviceTokenPtr ret(new VirtualDeviceToken(name));
    ret->m_sharedInit(init);
    return ret;
}

OSVR_DeviceTokenObject::OSVR_DeviceTokenObject(std::string const &name)
    : m_name(name) {}

OSVR_DeviceTokenObject::~OSVR_DeviceTokenObject() { stopThreads(); }

std::string const &OSVR_DeviceTokenObject::getName() const { return m_name; }

void OSVR_DeviceTokenObject::sendData(MessageType *type, const char *bytestream,
                                      size_t len) {
    osvr::util::time::TimeValue tv;
    osvr::util::time::getNow(tv);
    m_sendData(tv, type, bytestream, len);
}
void OSVR_DeviceTokenObject::sendData(
    osvr::util::time::TimeValue const &timestamp, MessageType *type,
    const char *bytestream, size_t len) {
    m_sendData(timestamp, type, bytestream, len);
}

GuardPtr OSVR_DeviceTokenObject::getSendGuard() { return m_getSendGuard(); }

void OSVR_DeviceTokenObject::setUpdateCallback(
    osvr::connection::DeviceUpdateCallback const &cb) {
    m_setUpdateCallback(cb);
}

void OSVR_DeviceTokenObject::connectionInteract() { m_connectionInteract(); }

void OSVR_DeviceTokenObject::stopThreads() { m_stopThreads(); }

void OSVR_DeviceTokenObject::setDeviceDescriptor(
    std::string const &jsonString) {
    m_getConnectionDevice()->setDeviceDescriptor(jsonString);
    m_getConnection()->triggerDescriptorHandlers();
}

ConnectionPtr OSVR_DeviceTokenObject::m_getConnection() { return m_conn; }

ConnectionDevicePtr OSVR_DeviceTokenObject::m_getConnectionDevice() {
    return m_dev;
}

void OSVR_DeviceTokenObject::m_stopThreads() {}

void OSVR_DeviceTokenObject::m_sharedInit(DeviceInitObject &init) {
    m_conn = init.getConnection();
    m_dev = m_conn->createConnectionDevice(init);
    m_dev->setDeviceToken(*this);
    m_serverInterfaces = init.getServerInterfaces();
    for (auto &iface : m_serverInterfaces) {
        iface->registerMessageTypes(*this);
    }
}
<|endoftext|>