<commit_before>/*
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Unordered buffer of messages that can be inserted such
 * that they can be dequeued after a given delta time has expired.
 */

#ifndef __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
#define __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__

#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

#include "mem/packet.hh"
#include "mem/ruby/buffers/MessageBufferNode.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/slicc_interface/Message.hh"

class MessageBuffer
{
  public:
    MessageBuffer(const std::string &name = "");

    std::string name() const { return m_name; }

    void setRecycleLatency(Cycles recycle_latency)
    { m_recycle_latency = recycle_latency; }

    void reanalyzeMessages(const Address& addr);
    void reanalyzeAllMessages();
    void stallMessage(const Address& addr);

    // TRUE if head of queue timestamp <= SystemTime
    bool isReady() const;

    void
    delayHead()
    {
        MessageBufferNode node = m_prio_heap.front();
        std::pop_heap(m_prio_heap.begin(), m_prio_heap.end(),
                      std::greater<MessageBufferNode>());
        m_prio_heap.pop_back();
        enqueue(node.m_msgptr, Cycles(1));
    }

    bool areNSlotsAvailable(int n);
    int getPriority() { return m_priority_rank; }
    void setPriority(int rank) { m_priority_rank = rank; }
    void setConsumer(Consumer* consumer)
    {
        assert(m_consumer == NULL);
        m_consumer = consumer;
    }

    void setSender(ClockedObject* obj)
    {
        assert(m_sender == NULL || m_sender == obj);
        m_sender = obj;
    }

    void setReceiver(ClockedObject* obj)
    {
        assert(m_receiver == NULL || m_receiver == obj);
        m_receiver = obj;
    }

    void setDescription(const std::string& name) { m_name = name; }
    std::string getDescription() { return m_name;}

    Consumer* getConsumer() { return m_consumer; }

    const Message* peekAtHeadOfQueue() const;
    const Message* peek() const { return peekAtHeadOfQueue(); }
    const MsgPtr getMsgPtrCopy() const;

    const MsgPtr&
    peekMsgPtr() const
    {
        assert(isReady());
        return m_prio_heap.front().m_msgptr;
    }

    const MsgPtr&
    peekMsgPtrEvenIfNotReady() const
    {
        return m_prio_heap.front().m_msgptr;
    }

    void enqueue(MsgPtr message) { enqueue(message, Cycles(1)); }
    void enqueue(MsgPtr message, Cycles delta);

    //!  returns delay ticks of the message.
    Cycles dequeue_getDelayCycles(MsgPtr& message);
    void dequeue(MsgPtr& message);

    //! returns delay cycles of the message
    Cycles dequeue_getDelayCycles();
    void dequeue() { pop(); }
    void pop();
    void recycle();
    bool isEmpty() const { return m_prio_heap.size() == 0; }

    void
    setOrdering(bool order)
    {
        m_strict_fifo = order;
        m_ordering_set = true;
    }
    void resize(int size) { m_max_size = size; }
    int getSize();
    void setRandomization(bool random_flag) { m_randomization = random_flag; }

    void clear();

    void print(std::ostream& out) const;
    void printStats(std::ostream& out);
    void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; }

    void setIncomingLink(int link_id) { m_input_link_id = link_id; }
    void setVnet(int net) { m_vnet_id = net; }

    // Function for figuring out if any of the messages in the buffer can
    // satisfy the read request for the address in the packet.
    // Return value, if true, indicates that the request was fulfilled.
    bool functionalRead(Packet *pkt);

    // Function for figuring out if any of the messages in the buffer need
    // to be updated with the data from the packet.
    // Return value indicates the number of messages that were updated.
    // This required for debugging the code.
    uint32_t functionalWrite(Packet *pkt);

  private:
    //added by SS
    Cycles m_recycle_latency;

    // Private Methods
    Cycles setAndReturnDelayCycles(MsgPtr message);

    // Private copy constructor and assignment operator
    MessageBuffer(const MessageBuffer& obj);
    MessageBuffer& operator=(const MessageBuffer& obj);

    // Data Members (m_ prefix)
    //! The two ends of the buffer.
    ClockedObject* m_sender;
    ClockedObject* m_receiver;

    //! Consumer to signal a wakeup(), can be NULL
    Consumer* m_consumer;
    std::vector<MessageBufferNode> m_prio_heap;

    // use a std::map for the stalled messages as this container is
    // sorted and ensures a well-defined iteration order
    typedef std::map< Address, std::list<MsgPtr> > StallMsgMapType;
    typedef std::vector<MsgPtr>::iterator MsgListIter;

    StallMsgMapType m_stall_msg_map;
    std::string m_name;

    int m_max_size;
    int m_size;

    Cycles m_time_last_time_size_checked;
    int m_size_last_time_size_checked;

    // variables used so enqueues appear to happen imediately, while
    // pop happen the next cycle
    Cycles m_time_last_time_enqueue;
    Cycles m_time_last_time_pop;
    int m_size_at_cycle_start;
    int m_msgs_this_cycle;

    int m_not_avail_count;  // count the # of times I didn't have N
                            // slots available
    uint64 m_msg_counter;
    int m_priority_rank;
    bool m_strict_fifo;
    bool m_ordering_set;
    bool m_randomization;

    Tick m_last_arrival_time;

    int m_input_link_id;
    int m_vnet_id;
};

Cycles random_time();

inline std::ostream&
operator<<(std::ostream& out, const MessageBuffer& obj)
{
    obj.print(out);
    out << std::flush;
    return out;
}

#endif // __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
<commit_msg>Ruby: More descriptive message buffer connection fatal<commit_after>/*
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Unordered buffer of messages that can be inserted such
 * that they can be dequeued after a given delta time has expired.
 */

#ifndef __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
#define __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__

#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

#include "mem/packet.hh"
#include "mem/ruby/buffers/MessageBufferNode.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/slicc_interface/Message.hh"

class MessageBuffer
{
  public:
    MessageBuffer(const std::string &name = "");

    std::string name() const { return m_name; }

    void setRecycleLatency(Cycles recycle_latency)
    { m_recycle_latency = recycle_latency; }

    void reanalyzeMessages(const Address& addr);
    void reanalyzeAllMessages();
    void stallMessage(const Address& addr);

    // TRUE if head of queue timestamp <= SystemTime
    bool isReady() const;

    void
    delayHead()
    {
        MessageBufferNode node = m_prio_heap.front();
        std::pop_heap(m_prio_heap.begin(), m_prio_heap.end(),
                      std::greater<MessageBufferNode>());
        m_prio_heap.pop_back();
        enqueue(node.m_msgptr, Cycles(1));
    }

    bool areNSlotsAvailable(int n);
    int getPriority() { return m_priority_rank; }
    void setPriority(int rank) { m_priority_rank = rank; }
    void setConsumer(Consumer* consumer)
    {
        if (m_consumer != NULL) {
            fatal("Trying to connect %s to MessageBuffer %s. \
                  \n%s already connected. Check the cntrl_id's.\n",
                  *consumer, *this, *m_consumer);
        }
        m_consumer = consumer;
    }

    void setSender(ClockedObject* obj)
    {
        assert(m_sender == NULL || m_sender == obj);
        m_sender = obj;
    }

    void setReceiver(ClockedObject* obj)
    {
        assert(m_receiver == NULL || m_receiver == obj);
        m_receiver = obj;
    }

    void setDescription(const std::string& name) { m_name = name; }
    std::string getDescription() { return m_name;}

    Consumer* getConsumer() { return m_consumer; }

    const Message* peekAtHeadOfQueue() const;
    const Message* peek() const { return peekAtHeadOfQueue(); }
    const MsgPtr getMsgPtrCopy() const;

    const MsgPtr&
    peekMsgPtr() const
    {
        assert(isReady());
        return m_prio_heap.front().m_msgptr;
    }

    const MsgPtr&
    peekMsgPtrEvenIfNotReady() const
    {
        return m_prio_heap.front().m_msgptr;
    }

    void enqueue(MsgPtr message) { enqueue(message, Cycles(1)); }
    void enqueue(MsgPtr message, Cycles delta);

    //!  returns delay ticks of the message.
    Cycles dequeue_getDelayCycles(MsgPtr& message);
    void dequeue(MsgPtr& message);

    //! returns delay cycles of the message
    Cycles dequeue_getDelayCycles();
    void dequeue() { pop(); }
    void pop();
    void recycle();
    bool isEmpty() const { return m_prio_heap.size() == 0; }

    void
    setOrdering(bool order)
    {
        m_strict_fifo = order;
        m_ordering_set = true;
    }
    void resize(int size) { m_max_size = size; }
    int getSize();
    void setRandomization(bool random_flag) { m_randomization = random_flag; }

    void clear();

    void print(std::ostream& out) const;
    void printStats(std::ostream& out);
    void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; }

    void setIncomingLink(int link_id) { m_input_link_id = link_id; }
    void setVnet(int net) { m_vnet_id = net; }

    // Function for figuring out if any of the messages in the buffer can
    // satisfy the read request for the address in the packet.
    // Return value, if true, indicates that the request was fulfilled.
    bool functionalRead(Packet *pkt);

    // Function for figuring out if any of the messages in the buffer need
    // to be updated with the data from the packet.
    // Return value indicates the number of messages that were updated.
    // This required for debugging the code.
    uint32_t functionalWrite(Packet *pkt);

  private:
    //added by SS
    Cycles m_recycle_latency;

    // Private Methods
    Cycles setAndReturnDelayCycles(MsgPtr message);

    // Private copy constructor and assignment operator
    MessageBuffer(const MessageBuffer& obj);
    MessageBuffer& operator=(const MessageBuffer& obj);

    // Data Members (m_ prefix)
    //! The two ends of the buffer.
    ClockedObject* m_sender;
    ClockedObject* m_receiver;

    //! Consumer to signal a wakeup(), can be NULL
    Consumer* m_consumer;
    std::vector<MessageBufferNode> m_prio_heap;

    // use a std::map for the stalled messages as this container is
    // sorted and ensures a well-defined iteration order
    typedef std::map< Address, std::list<MsgPtr> > StallMsgMapType;
    typedef std::vector<MsgPtr>::iterator MsgListIter;

    StallMsgMapType m_stall_msg_map;
    std::string m_name;

    int m_max_size;
    int m_size;

    Cycles m_time_last_time_size_checked;
    int m_size_last_time_size_checked;

    // variables used so enqueues appear to happen imediately, while
    // pop happen the next cycle
    Cycles m_time_last_time_enqueue;
    Cycles m_time_last_time_pop;
    int m_size_at_cycle_start;
    int m_msgs_this_cycle;

    int m_not_avail_count;  // count the # of times I didn't have N
                            // slots available
    uint64 m_msg_counter;
    int m_priority_rank;
    bool m_strict_fifo;
    bool m_ordering_set;
    bool m_randomization;

    Tick m_last_arrival_time;

    int m_input_link_id;
    int m_vnet_id;
};

Cycles random_time();

inline std::ostream&
operator<<(std::ostream& out, const MessageBuffer& obj)
{
    obj.print(out);
    out << std::flush;
    return out;
}

#endif // __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
<|endoftext|>


<commit_before>/*
 * Copyright 2015 - 2018 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <ox/std/std.hpp>

namespace ox {
namespace fs {

template<typename T, typename size_t>
class Ptr {

	private:
		uint8_t *m_dataStart = nullptr;
		size_t m_itemStart = 0;
		size_t m_itemSize = 0;

	public:
		inline Ptr() = default;

		inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T));

		inline bool valid() const;

		inline size_t size() const;

		inline size_t offset() const;

		inline T *operator->() const;

		inline operator T*() const;

		inline operator size_t() const;

		inline T &operator*() const;

		inline Ptr &operator=(size_t offset);

		inline Ptr &operator+=(size_t offset);

	protected:
		void init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize);

};

template<typename T, typename size_t>
inline Ptr<T, size_t>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) {
	init(dataStart, dataSize, itemStart, itemSize);
}

template<typename T, typename size_t>
inline bool Ptr<T, size_t>::valid() const {
	return m_dataStart and m_itemStart;
}

template<typename T, typename size_t>
inline size_t Ptr<T, size_t>::size() const {
	return m_itemSize;
}

template<typename T, typename size_t>
inline size_t Ptr<T, size_t>::offset() const {
	return m_itemStart;
}

template<typename T, typename size_t>
inline T *Ptr<T, size_t>::operator->() const {
	return reinterpret_cast<T*>(m_dataStart + m_itemStart);
}

template<typename T, typename size_t>
inline Ptr<T, size_t>::operator T*() const {
	return reinterpret_cast<T*>(m_dataStart + m_itemStart);
}

template<typename T, typename size_t>
inline Ptr<T, size_t>::operator size_t() const {
	if (valid()) {
		return m_itemStart;
	}
	return 0;
}

template<typename T, typename size_t>
inline T &Ptr<T, size_t>::operator*() const {
	return *static_cast<T>(this);
}

template<typename T, typename size_t>
inline Ptr<T, size_t> &Ptr<T, size_t>::operator=(size_t offset) {
	m_itemStart = offset;
	return *this;
}

template<typename T, typename size_t>
inline Ptr<T, size_t> &Ptr<T, size_t>::operator+=(size_t offset) {
	m_itemStart += offset;
	return *this;
}

template<typename T, typename size_t>
void Ptr<T, size_t>::init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) {
	// do some sanity checks before assuming this is valid
	if (itemSize >= sizeof(T) and
		 dataStart and
		 itemStart + itemSize <= dataSize) {
		m_dataStart = static_cast<uint8_t*>(dataStart);
		m_itemStart = itemStart;
		m_itemSize = itemSize;
	}
}

}
}
<commit_msg>Add asserts to ox::fs::Ptr<commit_after>/*
 * Copyright 2015 - 2018 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <ox/std/std.hpp>

namespace ox {
namespace fs {

template<typename T, typename size_t>
class Ptr {

	private:
		uint8_t *m_dataStart = nullptr;
		size_t m_itemStart = 0;
		size_t m_itemSize = 0;

	public:
		inline Ptr() = default;

		inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T));

		inline bool valid() const;

		inline size_t size() const;

		inline size_t offset() const;

		inline T *operator->() const;

		inline operator T*() const;

		inline operator size_t() const;

		inline T &operator*() const;

		inline Ptr &operator=(size_t offset);

		inline Ptr &operator+=(size_t offset);

	protected:
		void init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize);

};

template<typename T, typename size_t>
inline Ptr<T, size_t>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) {
	init(dataStart, dataSize, itemStart, itemSize);
}

template<typename T, typename size_t>
inline bool Ptr<T, size_t>::valid() const {
	return m_dataStart and m_itemStart;
}

template<typename T, typename size_t>
inline size_t Ptr<T, size_t>::size() const {
	return m_itemSize;
}

template<typename T, typename size_t>
inline size_t Ptr<T, size_t>::offset() const {
	return m_itemStart;
}

template<typename T, typename size_t>
inline T *Ptr<T, size_t>::operator->() const {
	ox_assert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
	return reinterpret_cast<T*>(m_dataStart + m_itemStart);
}

template<typename T, typename size_t>
inline Ptr<T, size_t>::operator T*() const {
	return reinterpret_cast<T*>(m_dataStart + m_itemStart);
}

template<typename T, typename size_t>
inline Ptr<T, size_t>::operator size_t() const {
	if (valid()) {
		return m_itemStart;
	}
	return 0;
}

template<typename T, typename size_t>
inline T &Ptr<T, size_t>::operator*() const {
	ox_assert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
	return *static_cast<T>(this);
}

template<typename T, typename size_t>
inline Ptr<T, size_t> &Ptr<T, size_t>::operator=(size_t offset) {
	m_itemStart = offset;
	return *this;
}

template<typename T, typename size_t>
inline Ptr<T, size_t> &Ptr<T, size_t>::operator+=(size_t offset) {
	m_itemStart += offset;
	return *this;
}

template<typename T, typename size_t>
void Ptr<T, size_t>::init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) {
	// do some sanity checks before assuming this is valid
	if (itemSize >= sizeof(T) and
		 dataStart and
		 itemStart + itemSize <= dataSize) {
		m_dataStart = static_cast<uint8_t*>(dataStart);
		m_itemStart = itemStart;
		m_itemSize = itemSize;
	}
}

}
}
<|endoftext|>


<commit_before>/*
 * This file is part of OpenCorsairLink.
 * Copyright (C) 2014  Sean Nelson <audiohacked@gmail.com>

 * OpenCorsairLink is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * any later version.

 * OpenCorsairLink is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with OpenCorsairLink.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "Proto.h"
#include "Link.h"
#include "Fan.h"

CorsairLink::CorsairLink() {
	handle = NULL;
	CommandId = 0x81;
	max_ms_read_wait = 5000;
}

int CorsairLink::Initialize()
{
	if(handle == NULL)
	{
		if (hid_init())
			return 0;

		// Set up the command buffer.
		//memset(buf,0x00,sizeof(buf));
		//buf[0] = 0x01;
		//buf[1] = 0x81;

		// Open the device using the VID, PID,
		// and optionally the Serial number.
		// open Corsair H80i or H100i cooler
		handle = hid_open(0x1b1c, 0x0c04, NULL);
		if (!handle)
		{
			fprintf(stderr, "Error: Unable to open Corsair H80i or H100i CPU Cooler\n");
			return 0;
		}
		hid_set_nonblocking(handle, 1);

		deviceId = this->GetDeviceId();
		if ((deviceId != 0x3b) && (deviceId != 0x3c))
		{
			fprintf(stderr, "Device ID: %2x mismatch. Not Corsair H80i or H100i CPU Cooler\n", deviceId );
			this->Close();
			return 0;
		}
	} else {
		fprintf(stderr, "Cannot initialize twice\n" );
		return 0;
	}
	return 1;
}

int CorsairLink::GetDeviceId(void)
{
	memset(buf,0,sizeof(buf));

	// Read Device ID: 0x3b = H80i. 0x3c = H100i
	buf[0] = 0x03; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadOneByte; // Command Opcode
	buf[3] = DeviceID; // Command data...
	buf[4] = 0x00;

	int res = hid_write(handle, buf, 17);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}

	return buf[2];
}

int CorsairLink::GetFirmwareVersion()
{
	memset(buf,0,sizeof(buf));

	// Read Device ID: 0x3b = H80i. 0x3c = H100i
	buf[0] = 0x03; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadTwoBytes; // Command Opcode
	buf[3] = FirmwareID; // Command data...
	buf[4] = 0x00;

	int res = hid_write(handle, buf, 17);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}
	int firmware = buf[3]<<8;
	firmware += buf[2];
	return firmware;
}

int CorsairLink::GetProductName(char *ostring)
{
	memset(buf,0,sizeof(buf));

	// Read Device ID: 0x3b = H80i. 0x3c = H100i
	buf[0] = 0x04; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadThreeBytes; // Command Opcode
	buf[3] = ProductName; // Command data...
	buf[4] = 0x08;

	int res = hid_write(handle, buf, 8);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}
	memcpy(ostring, buf + 3, 8);
	return 0;
}

int CorsairLink::GetDeviceStatus()
{
	memset(buf,0,sizeof(buf));

	buf[0] = 0x03; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadOneByte; // Command Opcode
	buf[3] = Status; // Command data...
	buf[4] = 0x00;

	int res = hid_write(handle, buf, 17);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}

	return buf[2];
}

char* CorsairLink::_GetManufacturer()
{
	char *str;
	char wstr[MAX_STR];
	wstr[0] = 0x0000;

	int res = hid_get_manufacturer_string(handle, (wchar_t*)wstr, MAX_STR);
	if (res < 0)
		fprintf(stderr, "Unable to read manufacturer string\n");

	str = wstr;
	return str;
}

char* CorsairLink::_GetProduct()
{
	char* str;
	char wstr[MAX_STR];
	wstr[0] = 0x0000;

	int res = hid_get_product_string(handle, (wchar_t*)wstr, MAX_STR);
	if (res < 0)
		fprintf(stderr, "Unable to read product string\n");

	str = wstr;
	return str;
}

int CorsairLink::hid_read_wrapper (hid_device *handle, unsigned char *buf)
{
	// Read requested state. hid_read() has been set to be
	// non-blocking by the call to hid_set_nonblocking() above.
	// This loop demonstrates the non-blocking nature of hid_read().
	int res = 0;
	int sleepTotal = 0;
	while (res == 0 && sleepTotal < this->max_ms_read_wait)
	{
		res = hid_read(handle, buf, sizeof(buf));
		if (res < 0)
			fprintf(stderr, "Unable to read()\n");

		this->sleep(100);
		sleepTotal += 100;
	}
	if(sleepTotal == this->max_ms_read_wait)
	{
		res = 0;
	}

#if DEBUG
	int i = 0;
	for (i = 0; i < sizeof(buf); i++)
	{
		fprintf(stdout, "Debug-hid_read_wrapper: %02X\n", buf[i]);
	}
#endif
	return 1;
}

int CorsairLink::hid_wrapper (hid_device *handle, unsigned char *buf, size_t buf_size) {
	int res = hid_write(handle, buf, buf_size);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
		//return -1;
	}
	res = this->hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
		//return -1;
	}
	return res;
}

void CorsairLink::sleep(int ms)
{
	#ifdef WIN32
	Sleep(ms);
	#else
	usleep(ms*1000);
	#endif
}

void CorsairLink::Close()
{
	if(handle != NULL)
	{
		hid_close(handle);
		hid_exit();
		handle = NULL;
	}
}

CorsairLink::~CorsairLink()
{
	this->Close();
//	if(fans != NULL) {
//		free(fans);
//	}
}
<commit_msg>Added support for H110i coolers<commit_after>/*
 * This file is part of OpenCorsairLink.
 * Copyright (C) 2014  Sean Nelson <audiohacked@gmail.com>

 * OpenCorsairLink is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * any later version.

 * OpenCorsairLink is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with OpenCorsairLink.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "Proto.h"
#include "Link.h"
#include "Fan.h"

CorsairLink::CorsairLink() {
	handle = NULL;
	CommandId = 0x81;
	max_ms_read_wait = 5000;
}

int CorsairLink::Initialize()
{
	if(handle == NULL)
	{
		if (hid_init())
			return 0;

		// Set up the command buffer.
		//memset(buf,0x00,sizeof(buf));
		//buf[0] = 0x01;
		//buf[1] = 0x81;

		// Open the device using the VID, PID,
		// and optionally the Serial number.
		// open Corsair H80i, H100i, or H110i cooler
		handle = hid_open(0x1b1c, 0x0c04, NULL);
		if (!handle)
		{
			fprintf(stderr, "Error: Unable to open Corsair H80i, H100i or H110i CPU Cooler\n");
			return 0;
		}
		hid_set_nonblocking(handle, 1);

		deviceId = this->GetDeviceId();
		if ((deviceId != 0x3b) && (deviceId != 0x3c) && (deviceId != 0x41))
		{
			fprintf(stderr, "Device ID: %2x mismatch. Not Corsair H80i, H100i or H110i CPU Cooler\n", deviceId );
			this->Close();
			return 0;
		}
	} else {
		fprintf(stderr, "Cannot initialize twice\n" );
		return 0;
	}
	return 1;
}

int CorsairLink::GetDeviceId(void)
{
	memset(buf,0,sizeof(buf));

	// Read Device ID: 0x3b = H80i. 0x3c = H100i. 0x41 = H110i
	buf[0] = 0x03; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadOneByte; // Command Opcode
	buf[3] = DeviceID; // Command data...
	buf[4] = 0x00;

	int res = hid_write(handle, buf, 17);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}

	return buf[2];
}

int CorsairLink::GetFirmwareVersion()
{
	memset(buf,0,sizeof(buf));

	// Read Device ID: 0x3b = H80i. 0x3c = H100i. 0x41 = H110i
	buf[0] = 0x03; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadTwoBytes; // Command Opcode
	buf[3] = FirmwareID; // Command data...
	buf[4] = 0x00;

	int res = hid_write(handle, buf, 17);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}
	int firmware = buf[3]<<8;
	firmware += buf[2];
	return firmware;
}

int CorsairLink::GetProductName(char *ostring)
{
	memset(buf,0,sizeof(buf));

	// Read Device ID: 0x3b = H80i. 0x3c = H100i. 0x41 = H110i
	buf[0] = 0x04; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadThreeBytes; // Command Opcode
	buf[3] = ProductName; // Command data...
	buf[4] = 0x08;

	int res = hid_write(handle, buf, 8);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}
	memcpy(ostring, buf + 3, 8);
	return 0;
}

int CorsairLink::GetDeviceStatus()
{
	memset(buf,0,sizeof(buf));

	buf[0] = 0x03; // Length
	buf[1] = this->CommandId++; // Command ID
	buf[2] = ReadOneByte; // Command Opcode
	buf[3] = Status; // Command data...
	buf[4] = 0x00;

	int res = hid_write(handle, buf, 17);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
	}

	hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
	}

	return buf[2];
}

char* CorsairLink::_GetManufacturer()
{
	char *str;
	char wstr[MAX_STR];
	wstr[0] = 0x0000;

	int res = hid_get_manufacturer_string(handle, (wchar_t*)wstr, MAX_STR);
	if (res < 0)
		fprintf(stderr, "Unable to read manufacturer string\n");

	str = wstr;
	return str;
}

char* CorsairLink::_GetProduct()
{
	char* str;
	char wstr[MAX_STR];
	wstr[0] = 0x0000;

	int res = hid_get_product_string(handle, (wchar_t*)wstr, MAX_STR);
	if (res < 0)
		fprintf(stderr, "Unable to read product string\n");

	str = wstr;
	return str;
}

int CorsairLink::hid_read_wrapper (hid_device *handle, unsigned char *buf)
{
	// Read requested state. hid_read() has been set to be
	// non-blocking by the call to hid_set_nonblocking() above.
	// This loop demonstrates the non-blocking nature of hid_read().
	int res = 0;
	int sleepTotal = 0;
	while (res == 0 && sleepTotal < this->max_ms_read_wait)
	{
		res = hid_read(handle, buf, sizeof(buf));
		if (res < 0)
			fprintf(stderr, "Unable to read()\n");

		this->sleep(100);
		sleepTotal += 100;
	}
	if(sleepTotal == this->max_ms_read_wait)
	{
		res = 0;
	}

#if DEBUG
	int i = 0;
	for (i = 0; i < sizeof(buf); i++)
	{
		fprintf(stdout, "Debug-hid_read_wrapper: %02X\n", buf[i]);
	}
#endif
	return 1;
}

int CorsairLink::hid_wrapper (hid_device *handle, unsigned char *buf, size_t buf_size) {
	int res = hid_write(handle, buf, buf_size);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to write() %s\n", (char*)hid_error(handle) );
		//return -1;
	}
	res = this->hid_read_wrapper(handle, buf);
	if (res < 0) {
		fprintf(stderr, "Error: Unable to read() %s\n", (char*)hid_error(handle) );
		//return -1;
	}
	return res;
}

void CorsairLink::sleep(int ms)
{
	#ifdef WIN32
	Sleep(ms);
	#else
	usleep(ms*1000);
	#endif
}

void CorsairLink::Close()
{
	if(handle != NULL)
	{
		hid_close(handle);
		hid_exit();
		handle = NULL;
	}
}

CorsairLink::~CorsairLink()
{
	this->Close();
//	if(fans != NULL) {
//		free(fans);
//	}
}
<|endoftext|>


<commit_before>/*
	Copyright (c) 2014, Madd Games.
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

	* Redistributions of source code must retain the above copyright notice, this
	  list of conditions and the following disclaimer.

	* Redistributions in binary form must reproduce the above copyright notice,
	  this list of conditions and the following disclaimer in the documentation
	  and/or other materials provided with the distribution.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
	DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
	SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
	CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
	OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
	OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <Apoc/Entity/Entity.h>
#include <Apoc/Entity/World.h>
#include <Apoc/Utils/Utils.h>
#include <Apoc/Physics/CollisionCheck.h>
#include <inttypes.h>
#include <Apoc/Video/RenderHandler.h>
#include <Apoc/Utils/Archive.h>
#include <string.h>
#include <iostream>
#include <stddef.h>

using namespace std;

extern RenderHandler *apocRenderHandler;
map<string, map<string, Entity::Object> > Entity::apocEntityCache;

// XXX: Don't worry guys, this constructor is going away soon.
Entity::Entity(Model::ObjDef *defs) : bbDirty(true), shouldRemove(false), isStatic(true), entParent(NULL)
{
	cerr << "[APOC] [WARNING] The deprecated Entity constructor was used to load an embedded OBJ file!" << endl;

	modelMatrix = Matrix::Identity();

	while (defs->vertices != NULL)
	{
		Object obj;
		if (defs->model == NULL)
		{
			obj.model = new Model(defs->vertices, defs->count);
			defs->model = obj.model;
		}
		else
		{
			obj.model = defs->model;
		};

		string texName = defs->texName;
		string specMap = defs->specTex;
		string normalMap = defs->normalMap;
		if (texName != "empty_texture")
		{
			obj.textures[0] = Texture::Get(texName);
		};
		if (specMap != "<NONE>")
		{
			obj.textures[4] = Texture::Get(specMap);
		};
		if (normalMap != "<NONE>")
		{
			obj.textures[5] = Texture::Get(normalMap);
		};
		obj.matrix = Matrix::Identity();
		obj.diffuseColor = defs->diffuseColor;
		obj.specularColor = defs->specularColor;
		obj.shininess = defs->shininess;
		string name(defs->name);
		obj.visible = (name != "ApocColl");
		obj.collideable = (name == "ApocColl");
		objects[defs->name] = obj;
		defs++;
	};

	if (objects.count("ApocColl") == 0)
	{
		map<string, Object>::iterator it;
		for (it=objects.begin(); it!=objects.end(); ++it)
		{
			it->second.collideable = true;
		};
	};
};

Entity::Entity(string entname) : bbDirty(true), shouldRemove(false), isStatic(true), entParent(NULL)
{
	modelMatrix = Matrix::Identity();

	if (apocEntityCache.count(entname) != 0)
	{
		objects = apocEntityCache[entname];
	}
	else
	{
		DataFile file(string("Game/Models/") + entname + ".apm");
		uint8_t *data = new uint8_t[file.getSize()];
		file.read(data, file.getSize());

		APM_Header *header = (APM_Header*) data;
		if (memcmp(header->magic, "APM", 3) != 0)
		{
			ApocFail(string(entname) + " does not have a valid APM header");
		};

		map<uint32_t, Texture*> modelTextures;
		uint32_t count = header->numTex;
		APM_TexHeader *texHeader = (APM_TexHeader*) &data[header->offTex];

		while (count--)
		{
			uint8_t *texdata = (uint8_t*) (texHeader+1);
			modelTextures[texHeader->idx] = new Texture(texHeader->width, texHeader->height, texdata, (texHeader->flags & 1) == 0);
			texHeader = (APM_TexHeader*) &texdata[4 * texHeader->width * texHeader->height];
		};

		count = header->numObjDefs;
		uint8_t *objscan = &data[header->offObjDefs];

		while (count--)
		{
			string name((const char*)objscan);
			objscan += name.size();
			objscan++;
			APM_ObjHeader *objHeader = (APM_ObjHeader*) objscan;

			// unroll the vertices
			Model::Vertex *vertices = new Model::Vertex[objHeader->numVertices];
			Model::Vertex *vunroll = vertices;
			uint8_t *mdlv = (uint8_t*) objHeader + objHeader->szThis;
			uint32_t vcnt = objHeader->numVertices;

			while (vcnt--)
			{
				memcpy(vunroll, mdlv, header->szVertex);
				vunroll++;
				mdlv += header->szVertex;
			};

			uint32_t idxIllumMap = 0;
			uint32_t idxWarpMap = 0;

			if (objHeader->szThis >= 36)
			{
				idxIllumMap = objHeader->idxIllumMap;
			};

			if (objHeader->szThis >= 40)
			{
				idxWarpMap = objHeader->idxWarpMap;
			};

			Object obj;
			obj.model = new Model(vertices, objHeader->numVertices);
			obj.matrix = Matrix::Identity();
			if (objHeader->idxColor != 0)
			{
				obj.textures[0] = modelTextures[objHeader->idxColor];
			};
			if (objHeader->idxSpecular != 0)
			{
				obj.textures[4] = modelTextures[objHeader->idxSpecular];
			};
			if (objHeader->idxNormals != 0)
			{
				obj.textures[5] = modelTextures[objHeader->idxNormals];
			};
			if (idxIllumMap != 0)
			{
				obj.textures[6] = modelTextures[idxIllumMap];
			};
			if (idxWarpMap != 0)
			{
				obj.textures[7] = modelTextures[idxWarpMap];
			};
			obj.diffuseColor = Vector(
				(float) objHeader->colDiffuse[0] / 255.0,
				(float) objHeader->colDiffuse[1] / 255.0,
				(float) objHeader->colDiffuse[2] / 255.0,
				(float) objHeader->colDiffuse[3] / 255.0
			);
			obj.specularColor = Vector(
				(float) objHeader->colSpecular[0] / 255.0,
				(float) objHeader->colSpecular[1] / 255.0,
				(float) objHeader->colSpecular[2] / 255.0,
				(float) objHeader->colSpecular[3] / 255.0
			);
			obj.shininess = objHeader->shininess;
			obj.visible = (name != "ApocColl");
			obj.collideable = (name == "ApocColl");
			objects[name] = obj;

			objscan = mdlv;
		};

		delete data;

		if (objects.count("ApocColl") == 0)
		{
			map<string, Object>::iterator it;
			for (it=objects.begin(); it!=objects.end(); ++it)
			{
				it->second.collideable = true;
			};
		};

		apocEntityCache[entname] = objects;
	};
};

Entity::~Entity()
{
};

void Entity::transform(string obj, Matrix mat)
{
	if (obj == "")
	{
		modelMatrix = mat * modelMatrix;
	}
	else
	{
		objects[obj].matrix = mat * objects[obj].matrix;
	};
	bbDirty = true;
	isStatic = false;

	vector<IBindable*>::iterator it;
	for (it=boundList.begin(); it!=boundList.end(); ++it)
	{
		(*it)->transform(getModelMatrix());
	};
};

void Entity::preTransform(string obj, Matrix mat)
{
	if (obj == "")
	{
		modelMatrix = modelMatrix * mat;
	}
	else
	{
		objects[obj].matrix = objects[obj].matrix * mat;
	};
	bbDirty = true;
	isStatic = false;

	vector<IBindable*>::iterator it;
	for (it=boundList.begin(); it!=boundList.end(); ++it)
	{
		(*it)->transform(getModelMatrix());
	};
};

Matrix Entity::getModelMatrix()
{
	if (entParent != NULL)
	{
		return entParent->getModelMatrix() * modelMatrix;
	};
	return modelMatrix;
};

bool& Entity::visible(string name)
{
	return objects[name].visible;
};

bool& Entity::collideable(string name)
{
	return objects[name].collideable;
};

void Entity::update()
{
};

void Entity::renderObjects()
{
	GLint uModelMatrix = apocRenderHandler->getUniformLocation("uModelMatrix");
	GLint uObjectMatrix = apocRenderHandler->getUniformLocation("uObjectMatrix");
	GLint uDiffuseColor = apocRenderHandler->getUniformLocation("uDiffuseColor");
	GLint uSpecularColor = apocRenderHandler->getUniformLocation("uSpecularColor");
	GLint uShininess = apocRenderHandler->getUniformLocation("uShininess");

	Matrix matModel = getModelMatrix();
	glUniformMatrix4fv(uModelMatrix, 1, GL_FALSE, &matModel[0][0]);

	map<string, Object>::iterator it;
	for (it=objects.begin(); it!=objects.end(); ++it)
	{
		if (it->second.visible)
		{
			apocRenderHandler->bindDefaultTextures();
			map<unsigned int, Texture*>::iterator jt;
			for (jt=it->second.textures.begin(); jt!=it->second.textures.end(); ++jt)
			{
				glActiveTexture(GL_TEXTURE0 + jt->first);
				jt->second->bind();
			};

			glUniform4fv(uDiffuseColor, 1, &it->second.diffuseColor[0]);
			glUniform4fv(uSpecularColor, 1, &it->second.specularColor[0]);
			glUniform1f(uShininess, it->second.shininess);
			glUniformMatrix4fv(uObjectMatrix, 1, GL_FALSE, &it->second.matrix[0][0]);
			it->second.model->draw();
		};
	};
};

void Entity::translate(Vector vec, const char *objName)
{
	transform(objName, Matrix::Translate(vec.x(), vec.y(), vec.z()));
};

void Entity::rotate(float x, float y, float z, const char *objName)
{
	preTransform(objName, Matrix::Rotate(x, y, z));
};

void Entity::markForRemoval()
{
	shouldRemove = true;
};

void Entity::attachTo(Entity *parent)
{
	entParent = parent;
};

void Entity::bind(IBindable *obj)
{
	obj->transform(getModelMatrix());
	boundList.push_back(obj);
};

void Entity::unmangleVectors(Vector &a, Vector &b)
{
	int i;
	for (i=0; i<3; i++)
	{
		if (a[i] > b[i])
		{
			float tmp = a[i];
			a[i] = b[i];
			b[i] = tmp;
		};
	};
};

Entity::BoundingBox Entity::getBoundingBox()
{
	if (bbDirty)
	{
		modelBoundingBox.min = modelMatrix * objects.begin()->second.matrix * objects.begin()->second.model->data[0].pos;
		modelBoundingBox.max = modelBoundingBox.min;

		map<string, Object>::iterator it;
		for (it=objects.begin(); it!=objects.end(); ++it)
		{
			Matrix mat = modelMatrix * it->second.matrix;
			int i;
			for (i=0; i<it->second.model->vertexCount; i++)
			{
				Vector pos = mat * it->second.model->data[i].pos;
				int j;
				for (j=0; j<3; j++)
				{
					if (pos[j] < modelBoundingBox.min[j]) modelBoundingBox.min[j] = pos[j];
					if (pos[j] > modelBoundingBox.max[j]) modelBoundingBox.max[j] = pos[j];
				};
			};
		};

		bbDirty = false;
	};

	return modelBoundingBox;
};

Entity* Entity::checkCollision()
{
	vector<Entity*>::iterator it;
	for (it=World::entities.begin(); it!=World::entities.end(); ++it)
	{
		if ((*it) != this)
		{
			if (CollisionCheck::Entities(this, *it))
			{
				return *it;
			};
		};
	};

	return NULL;
};

Entity* Entity::move(Vector vec)
{
	translate(vec);
	Entity *coll = checkCollision();
	if (coll != NULL)
	{
		translate(-vec);
		return coll;
	};
	return NULL;
};
<commit_msg>Added an APM validation check<commit_after>/*
	Copyright (c) 2014, Madd Games.
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

	* Redistributions of source code must retain the above copyright notice, this
	  list of conditions and the following disclaimer.

	* Redistributions in binary form must reproduce the above copyright notice,
	  this list of conditions and the following disclaimer in the documentation
	  and/or other materials provided with the distribution.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
	DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
	SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
	CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
	OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
	OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <Apoc/Entity/Entity.h>
#include <Apoc/Entity/World.h>
#include <Apoc/Utils/Utils.h>
#include <Apoc/Physics/CollisionCheck.h>
#include <inttypes.h>
#include <Apoc/Video/RenderHandler.h>
#include <Apoc/Utils/Archive.h>
#include <string.h>
#include <iostream>
#include <stddef.h>

using namespace std;

extern RenderHandler *apocRenderHandler;
map<string, map<string, Entity::Object> > Entity::apocEntityCache;

// XXX: Don't worry guys, this constructor is going away soon.
Entity::Entity(Model::ObjDef *defs) : bbDirty(true), shouldRemove(false), isStatic(true), entParent(NULL)
{
	cerr << "[APOC] [WARNING] The deprecated Entity constructor was used to load an embedded OBJ file!" << endl;

	modelMatrix = Matrix::Identity();

	while (defs->vertices != NULL)
	{
		Object obj;
		if (defs->model == NULL)
		{
			obj.model = new Model(defs->vertices, defs->count);
			defs->model = obj.model;
		}
		else
		{
			obj.model = defs->model;
		};

		string texName = defs->texName;
		string specMap = defs->specTex;
		string normalMap = defs->normalMap;
		if (texName != "empty_texture")
		{
			obj.textures[0] = Texture::Get(texName);
		};
		if (specMap != "<NONE>")
		{
			obj.textures[4] = Texture::Get(specMap);
		};
		if (normalMap != "<NONE>")
		{
			obj.textures[5] = Texture::Get(normalMap);
		};
		obj.matrix = Matrix::Identity();
		obj.diffuseColor = defs->diffuseColor;
		obj.specularColor = defs->specularColor;
		obj.shininess = defs->shininess;
		string name(defs->name);
		obj.visible = (name != "ApocColl");
		obj.collideable = (name == "ApocColl");
		objects[defs->name] = obj;
		defs++;
	};

	if (objects.count("ApocColl") == 0)
	{
		map<string, Object>::iterator it;
		for (it=objects.begin(); it!=objects.end(); ++it)
		{
			it->second.collideable = true;
		};
	};
};

Entity::Entity(string entname) : bbDirty(true), shouldRemove(false), isStatic(true), entParent(NULL)
{
	modelMatrix = Matrix::Identity();

	if (apocEntityCache.count(entname) != 0)
	{
		objects = apocEntityCache[entname];
	}
	else
	{
		DataFile file(string("Game/Models/") + entname + ".apm");
		uint8_t *data = new uint8_t[file.getSize()];
		file.read(data, file.getSize());

		APM_Header *header = (APM_Header*) data;
		if (memcmp(header->magic, "APM", 3) != 0)
		{
			ApocFail(entname + " does not have a valid APM header");
		};

		map<uint32_t, Texture*> modelTextures;
		uint32_t count = header->numTex;
		APM_TexHeader *texHeader = (APM_TexHeader*) &data[header->offTex];

		while (count--)
		{
			uint8_t *texdata = (uint8_t*) (texHeader+1);
			modelTextures[texHeader->idx] = new Texture(texHeader->width, texHeader->height, texdata, (texHeader->flags & 1) == 0);
			texHeader = (APM_TexHeader*) &texdata[4 * texHeader->width * texHeader->height];
		};

		count = header->numObjDefs;
		uint8_t *objscan = &data[header->offObjDefs];

		while (count--)
		{
			string name((const char*)objscan);
			objscan += name.size();
			objscan++;
			APM_ObjHeader *objHeader = (APM_ObjHeader*) objscan;

			// unroll the vertices
			Model::Vertex *vertices = new Model::Vertex[objHeader->numVertices];
			Model::Vertex *vunroll = vertices;
			uint8_t *mdlv = (uint8_t*) objHeader + objHeader->szThis;
			uint32_t vcnt = objHeader->numVertices;

			while (vcnt--)
			{
				memcpy(vunroll, mdlv, header->szVertex);
				vunroll++;
				mdlv += header->szVertex;
			};

			uint32_t idxIllumMap = 0;
			uint32_t idxWarpMap = 0;

			if (objHeader->szThis >= 36)
			{
				idxIllumMap = objHeader->idxIllumMap;
			};

			if (objHeader->szThis >= 40)
			{
				idxWarpMap = objHeader->idxWarpMap;
			};

			Object obj;
			obj.model = new Model(vertices, objHeader->numVertices);
			obj.matrix = Matrix::Identity();
			if (objHeader->idxColor != 0)
			{
				obj.textures[0] = modelTextures[objHeader->idxColor];
			}
			else
			{
				ApocFail(entname + " contains an object with no color map");
			};

			if (objHeader->idxSpecular != 0)
			{
				obj.textures[4] = modelTextures[objHeader->idxSpecular];
			};
			if (objHeader->idxNormals != 0)
			{
				obj.textures[5] = modelTextures[objHeader->idxNormals];
			};
			if (idxIllumMap != 0)
			{
				obj.textures[6] = modelTextures[idxIllumMap];
			};
			if (idxWarpMap != 0)
			{
				obj.textures[7] = modelTextures[idxWarpMap];
			};
			obj.diffuseColor = Vector(
				(float) objHeader->colDiffuse[0] / 255.0,
				(float) objHeader->colDiffuse[1] / 255.0,
				(float) objHeader->colDiffuse[2] / 255.0,
				(float) objHeader->colDiffuse[3] / 255.0
			);
			obj.specularColor = Vector(
				(float) objHeader->colSpecular[0] / 255.0,
				(float) objHeader->colSpecular[1] / 255.0,
				(float) objHeader->colSpecular[2] / 255.0,
				(float) objHeader->colSpecular[3] / 255.0
			);
			obj.shininess = objHeader->shininess;
			obj.visible = (name != "ApocColl");
			obj.collideable = (name == "ApocColl");
			objects[name] = obj;

			objscan = mdlv;
		};

		delete data;

		if (objects.count("ApocColl") == 0)
		{
			map<string, Object>::iterator it;
			for (it=objects.begin(); it!=objects.end(); ++it)
			{
				it->second.collideable = true;
			};
		};

		apocEntityCache[entname] = objects;
	};
};

Entity::~Entity()
{
};

void Entity::transform(string obj, Matrix mat)
{
	if (obj == "")
	{
		modelMatrix = mat * modelMatrix;
	}
	else
	{
		objects[obj].matrix = mat * objects[obj].matrix;
	};
	bbDirty = true;
	isStatic = false;

	vector<IBindable*>::iterator it;
	for (it=boundList.begin(); it!=boundList.end(); ++it)
	{
		(*it)->transform(getModelMatrix());
	};
};

void Entity::preTransform(string obj, Matrix mat)
{
	if (obj == "")
	{
		modelMatrix = modelMatrix * mat;
	}
	else
	{
		objects[obj].matrix = objects[obj].matrix * mat;
	};
	bbDirty = true;
	isStatic = false;

	vector<IBindable*>::iterator it;
	for (it=boundList.begin(); it!=boundList.end(); ++it)
	{
		(*it)->transform(getModelMatrix());
	};
};

Matrix Entity::getModelMatrix()
{
	if (entParent != NULL)
	{
		return entParent->getModelMatrix() * modelMatrix;
	};
	return modelMatrix;
};

bool& Entity::visible(string name)
{
	return objects[name].visible;
};

bool& Entity::collideable(string name)
{
	return objects[name].collideable;
};

void Entity::update()
{
};

void Entity::renderObjects()
{
	GLint uModelMatrix = apocRenderHandler->getUniformLocation("uModelMatrix");
	GLint uObjectMatrix = apocRenderHandler->getUniformLocation("uObjectMatrix");
	GLint uDiffuseColor = apocRenderHandler->getUniformLocation("uDiffuseColor");
	GLint uSpecularColor = apocRenderHandler->getUniformLocation("uSpecularColor");
	GLint uShininess = apocRenderHandler->getUniformLocation("uShininess");

	Matrix matModel = getModelMatrix();
	glUniformMatrix4fv(uModelMatrix, 1, GL_FALSE, &matModel[0][0]);

	map<string, Object>::iterator it;
	for (it=objects.begin(); it!=objects.end(); ++it)
	{
		if (it->second.visible)
		{
			apocRenderHandler->bindDefaultTextures();
			map<unsigned int, Texture*>::iterator jt;
			for (jt=it->second.textures.begin(); jt!=it->second.textures.end(); ++jt)
			{
				glActiveTexture(GL_TEXTURE0 + jt->first);
				jt->second->bind();
			};

			glUniform4fv(uDiffuseColor, 1, &it->second.diffuseColor[0]);
			glUniform4fv(uSpecularColor, 1, &it->second.specularColor[0]);
			glUniform1f(uShininess, it->second.shininess);
			glUniformMatrix4fv(uObjectMatrix, 1, GL_FALSE, &it->second.matrix[0][0]);
			it->second.model->draw();
		};
	};
};

void Entity::translate(Vector vec, const char *objName)
{
	transform(objName, Matrix::Translate(vec.x(), vec.y(), vec.z()));
};

void Entity::rotate(float x, float y, float z, const char *objName)
{
	preTransform(objName, Matrix::Rotate(x, y, z));
};

void Entity::markForRemoval()
{
	shouldRemove = true;
};

void Entity::attachTo(Entity *parent)
{
	entParent = parent;
};

void Entity::bind(IBindable *obj)
{
	obj->transform(getModelMatrix());
	boundList.push_back(obj);
};

void Entity::unmangleVectors(Vector &a, Vector &b)
{
	int i;
	for (i=0; i<3; i++)
	{
		if (a[i] > b[i])
		{
			float tmp = a[i];
			a[i] = b[i];
			b[i] = tmp;
		};
	};
};

Entity::BoundingBox Entity::getBoundingBox()
{
	if (bbDirty)
	{
		modelBoundingBox.min = modelMatrix * objects.begin()->second.matrix * objects.begin()->second.model->data[0].pos;
		modelBoundingBox.max = modelBoundingBox.min;

		map<string, Object>::iterator it;
		for (it=objects.begin(); it!=objects.end(); ++it)
		{
			Matrix mat = modelMatrix * it->second.matrix;
			int i;
			for (i=0; i<it->second.model->vertexCount; i++)
			{
				Vector pos = mat * it->second.model->data[i].pos;
				int j;
				for (j=0; j<3; j++)
				{
					if (pos[j] < modelBoundingBox.min[j]) modelBoundingBox.min[j] = pos[j];
					if (pos[j] > modelBoundingBox.max[j]) modelBoundingBox.max[j] = pos[j];
				};
			};
		};

		bbDirty = false;
	};

	return modelBoundingBox;
};

Entity* Entity::checkCollision()
{
	vector<Entity*>::iterator it;
	for (it=World::entities.begin(); it!=World::entities.end(); ++it)
	{
		if ((*it) != this)
		{
			if (CollisionCheck::Entities(this, *it))
			{
				return *it;
			};
		};
	};

	return NULL;
};

Entity* Entity::move(Vector vec)
{
	translate(vec);
	Entity *coll = checkCollision();
	if (coll != NULL)
	{
		translate(-vec);
		return coll;
	};
	return NULL;
};
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

int currentPosition=-1;
class Node;

//An edge between two nodes is described by the index of the first character and the index of the last character
//and represents a substring of the initial input
class NormalEdge {
public:
    int startCharacterIndex;
	int endCharacterIndex;
	Node *startNode;
	Node *endNode;

    NormalEdge(){}

    NormalEdge(int _startCharacterIndex, int _endCharacterIndex, Node *_startNode, Node *_endNode)
	{
		this->startCharacterIndex=_startCharacterIndex;
		this->endCharacterIndex=_endCharacterIndex;
		this->startNode=_startNode;
		this->endNode=_endNode;
	}

	int returnEndCharacterIndex();
};

class Node {
public:
    int number;
	Node *suffixEdge;
	vector<NormalEdge> edges;
	bool isLeaf;
    Node() {}

    Node(int _number, bool _isLeaf){
        this->number = _number;
		this->isLeaf=_isLeaf;
		this->suffixEdge=NULL;
    }

	void RemoveEdge(NormalEdge *e){
		int index=-1;
		int fs=0;
		if(e->startNode!=NULL){
			fs=e->startNode->number;
		}
		int fe=0;
		if(e->endNode!=NULL){
			fe=e->endNode->number;
		}
		for(vector<NormalEdge>::iterator it = edges.begin(); it != edges.end(); ++it) {
			NormalEdge *edgeTmp=&(*it);
			int ss=0;
			if(edgeTmp->startNode!=NULL){
				ss=edgeTmp->startNode->number;
			}
			int se=0;
			if(edgeTmp->endNode!=NULL){
				se=edgeTmp->endNode->number;
			}
			if(fs==ss && fe==se){
				edges.erase(it);
				break;
			}
		}
	}
};

int NormalEdge::returnEndCharacterIndex() {
		if(endNode->isLeaf==1)
		{
			return currentPosition;
		}
		else
		{
			return endCharacterIndex;
		}
	}

//The algorithm is based on the triple: Active Node, Active Edge and Active Lenght which keeps a better track
//of the current step and helps out with characters already inserted in the tree, as well as with suffix links
class Triple{
public:
	Node *activeNode;
	NormalEdge *activeEdge;
	int length;

	Triple() {}

	Triple(Node * _activeNode, int _length){
		this->activeNode=_activeNode;
		this->length=_length;
		this->activeEdge=NULL;
	}
};

//The Tree instance which iscreated from the initial input.
class SuffixTree {
private:
    Node *root;
	int nodeNumber;
	string inputString;
	Triple *activePoint;
	int remainder;
	stringstream graphvizOutput;   //Output is in dot notation (gaphviz)
	int startCharacterIndexForInsertInString;
	Node *previousInsertedNode;

public:
    SuffixTree(string _inputString){
        this->inputString = _inputString;
		this->nodeNumber=1;
		this->root=new Node(this->nodeNumber, false);
		this->nodeNumber++;
		this->remainder=0;
		this->startCharacterIndexForInsertInString=0;
		this->graphvizOutput.clear();
		Triple *triple=new Triple(root, 0);
		this->activePoint=triple;
		this->previousInsertedNode=NULL;
    }

    void CreateSuffixTree(){
		int inputStringLen=inputString.length();
		for(int i=0;i<inputStringLen; i++){
			AddCharacter(inputString[i]);
		}
	}

    //Handling a new character while following all the rules
	void AddCharacter(char c){
		this->previousInsertedNode=NULL;
		currentPosition++;
		this->remainder++;

		while(this->remainder>0){

			if(this->activePoint->length==0){
				this->startCharacterIndexForInsertInString=currentPosition;
			}

			if(NeedToInsertNewEdge(false)){
				AddNewEdge(activePoint->activeNode, startCharacterIndexForInsertInString, startCharacterIndexForInsertInString);
				if(previousInsertedNode!=NULL){
					previousInsertedNode->suffixEdge=activePoint->activeNode;
				}
				previousInsertedNode=activePoint->activeNode;
			}
			else{
				activePoint->activeEdge=ChooseActiveEdge();
				int edgeLen=activePoint->activeEdge->endCharacterIndex-activePoint->activeEdge->startCharacterIndex+1;
				if(activePoint->length>=edgeLen)
				{
					startCharacterIndexForInsertInString+=edgeLen;
					activePoint->length-=edgeLen;
					activePoint->activeNode=activePoint->activeEdge->endNode;
					activePoint->activeEdge=ChooseActiveEdge();
					continue;
				}
				if(!NeedToInsertNewEdge(true)){
					activePoint->length++;

					if(previousInsertedNode!=NULL){
						previousInsertedNode->suffixEdge=activePoint->activeNode;
					}
					previousInsertedNode=activePoint->activeNode;
					break;
				}

			    int splitIndex=activePoint->length+activePoint->activeEdge->startCharacterIndex;
				AddNewInternalEdge(splitIndex, currentPosition);
				if(previousInsertedNode!=NULL){
					previousInsertedNode->suffixEdge=activePoint->activeEdge->endNode;
				}
				previousInsertedNode=activePoint->activeEdge->endNode;
			}
			remainder--;
			if(activePoint->activeNode->number==root->number && activePoint->length>0){
				activePoint->length--;
				startCharacterIndexForInsertInString++;
				activePoint->activeEdge=ChooseActiveEdge();
			}
			else{
				if(activePoint->activeNode->suffixEdge==NULL){
					activePoint->activeNode=root;
				}
				else{
					activePoint->activeNode=activePoint->activeNode->suffixEdge;
				}
			}
		}

	}

    //Creating a new edge in the tree
	void AddNewEdge(Node *startNode, int startIndex, int endIndex){
			Node *leaf=new Node(nodeNumber, true);
			nodeNumber++;
			NormalEdge *edge=new NormalEdge(startIndex, endIndex, startNode, leaf);
			startNode->edges.push_back(*edge);
	}

	void AddNewInternalEdge(int startIndex, int endIndex){
		Node *splittedEdgeNode =new Node(nodeNumber, false);
		nodeNumber++;

		NormalEdge *splittedEdge=new NormalEdge(activePoint->activeEdge->startCharacterIndex, startIndex-1, activePoint->activeNode, splittedEdgeNode);
		activePoint->activeNode->edges.push_back(*splittedEdge);
		activePoint->activeEdge=ChooseActiveEdge();

		Node *leafEdgeNode=new Node(nodeNumber, true);
		nodeNumber++;
		NormalEdge *leafEdge=new NormalEdge(endIndex, endIndex, splittedEdgeNode, leafEdgeNode);
		splittedEdgeNode->edges.push_back(*leafEdge);

		activePoint->activeEdge->startCharacterIndex+=activePoint->length;

		activePoint->activeEdge->startNode=splittedEdgeNode;
		splittedEdgeNode->edges.push_back(*(activePoint->activeEdge));

		activePoint->activeNode->RemoveEdge(activePoint->activeEdge);
		activePoint->activeEdge=splittedEdge;
	}

	bool NeedToInsertNewEdge(bool useActiveLen){
		int len=1;
		if(useActiveLen){
			len+=activePoint->length;
		}
		if(activePoint->activeEdge==NULL){

			int edgesSize=activePoint->activeNode->edges.size();
			for(int i=0;i<edgesSize;i++){

				if(len==1){
					NormalEdge *tmp=&activePoint->activeNode->edges.at(i);
					char s1=inputString.at(tmp->startCharacterIndex);
					char s2=inputString.at(startCharacterIndexForInsertInString);
					if(s1==s2){//equals
						return false;
					}
				}
				else{
					NormalEdge *tmp=&activePoint->activeNode->edges.at(i);
					string s1=inputString.substr(tmp->startCharacterIndex, len);
					string s2=inputString.substr(startCharacterIndexForInsertInString, len);
					if(s1.compare(s2)==0){//equals
						return false;
					}
				}
			}
			return true;
		}
		else{
			if(len==1){
					char s1=inputString.at(activePoint->activeEdge->startCharacterIndex);
					char s2=inputString.at(startCharacterIndexForInsertInString);
					if(s1==s2){//equals
						return false;
					}
			}
			else{
				string s1=inputString.substr(activePoint->activeEdge->startCharacterIndex, len);
				string s2=inputString.substr(startCharacterIndexForInsertInString, len);
				if(s1.compare(s2)==0){//equals
					return false;
				}
			}
		}
		return true;
	}

	NormalEdge* ChooseActiveEdge(){
		int edgeSize=activePoint->activeNode->edges.size();
		for(int i=0;i<edgeSize;i++){
			NormalEdge *tmpEdge=&activePoint->activeNode->edges.at(i);
			string s1=inputString.substr(tmpEdge->startCharacterIndex, 1);
			string s2=inputString.substr(startCharacterIndexForInsertInString, 1);

			if(s1.compare(s2)==0){//equals
				return tmpEdge;
			}
		}
	return NULL;
	}

	//Printing the edges in a standard .dot notation
	void PrintEdges(Node *n)
	{
		int edgesSize=n->edges.size();
		for(int i=0;i<edgesSize;i++)
		{
			NormalEdge *tmp=&n->edges.at(i);
			graphvizOutput<<"\t node"<<n->number;
			graphvizOutput<<" -> node"<<tmp->endNode->number;
			graphvizOutput<<" [label=\"";
			//graphvizOutput<<tmp->text;
			graphvizOutput<<"\",weight=3] \n";
			PrintEdges(tmp->endNode);
		}
	}

	void PrintInternalNodes(Node *n)
	{
		int edgesSize=n->edges.size();
		if(n->number!=root->number && edgesSize>0)
		{
			graphvizOutput<<"\t node";
			graphvizOutput<<n->number;
			graphvizOutput<<" [label=\"\",style=filled,fillcolor=lightgrey,shape=circle,width=.07,height=.07] \n";
		}
		if(edgesSize>0)
		{
			for(int i=0;i<edgesSize;i++)
			{
				NormalEdge *e=&n->edges.at(i);
				if(e->endNode!=NULL)
				{
					PrintInternalNodes(e->endNode);
				}
			}
		}
	}

	void PrintLeaves(Node *n)
	{
		int edgesSize=n->edges.size();
		if(edgesSize==0)
		{
			cout<<n->number<<endl;
			graphvizOutput<<"\t node"<<n->number;
			graphvizOutput<<" [label=\"\",shape=point] \n";
		}
		else
		{
			for(int i=0;i<edgesSize;i++)
			{
				NormalEdge *tmp=&n->edges.at(i);
				if(tmp->endNode!=NULL)
				{
					PrintLeaves(tmp->endNode);
				}
			}
		}
	}
	void PrintSuffixEdges(Node *n)
	{
		if(n->suffixEdge!=NULL)
		{
			graphvizOutput<<"\t node" ;
			graphvizOutput<<n->number<<" -> node";
			graphvizOutput<<n->suffixEdge->number<<" [label=\"\",weight=1,style=dotted] \n";
		}
		int edgesSize=n->edges.size();
		for(int i=0;i<edgesSize;i++)
		{
			NormalEdge *e=&n->edges.at(i);
			if(e->endNode!=NULL)
			{
			PrintSuffixEdges(e->endNode);
			}
		}
	}

	//Printing the tree in a .dot format which is a standard for graphviz visualization
	string PrintTree()
	{
		graphvizOutput.clear();
        graphvizOutput<<"digraph { \n";
        graphvizOutput<<"\t rankdir = LR; \n";
        graphvizOutput<<"\t edge [arrowsize=0.5,fontsize=12] \n";
        graphvizOutput<<"\t node1 [label=\"\",style=filled,fillcolor=lightgrey,shape=circle,width=.1,height=.1]; \n";
        graphvizOutput<<"//------leaves------ \n";
        PrintLeaves(root);
        graphvizOutput<<"//------nodes------ \n";
        PrintInternalNodes(root);
        graphvizOutput<<"//------edges------ \n";
        PrintEdges(root);
        graphvizOutput<<"//------suffix links------ \n";
	    PrintSuffixEdges(root);
        graphvizOutput<<"} \n";

        return graphvizOutput.str();
	}

};

//Methods handling input/output

void WriteToFile(string str, char* fileName)
{
	ofstream outFile;
    outFile.open(fileName);
    outFile<<str;
    outFile.close();
}

string ReadFromFile(const char *filename)
{
  ifstream inFile(filename);
  if (inFile)
  {
    std::string input;
    inFile.seekg(0, std::ios::end);
    input.resize(inFile.tellg());
    inFile.seekg(0, std::ios::beg);
    inFile.read(&input[0], input.size());
    inFile.close();
    return(input);
  }
}

int main (int argc, char* argv[]) {
    return 0;
}
<commit_msg>Modified function ChooseActiveEdge. Made some changes because of c++ code standard.<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

int currentPosition=-1;
class Node;

//An edge between two nodes is described by the index of the first character and the index of the last character
//and represents a substring of the initial input
class NormalEdge {
public:
    int startCharacterIndex;
	int endCharacterIndex;
	Node *startNode;
	Node *endNode;

    NormalEdge(){}

    NormalEdge(int _startCharacterIndex, int _endCharacterIndex, Node *_startNode, Node *_endNode)
	{
		this->startCharacterIndex=_startCharacterIndex;
		this->endCharacterIndex=_endCharacterIndex;
		this->startNode=_startNode;
		this->endNode=_endNode;
	}

	int returnEndCharacterIndex();
};

class Node {
public:
    int number;
	Node *suffixEdge;
	vector<NormalEdge> edges;
	bool isLeaf;
    Node() {}

    Node(int _number, bool _isLeaf){
        this->number = _number;
		this->isLeaf=_isLeaf;
		this->suffixEdge=NULL;
    }

	void RemoveEdge(NormalEdge *e){
		int index=-1;
		int fs=0;
		if(e->startNode!=NULL){
			fs=e->startNode->number;
		}
		int fe=0;
		if(e->endNode!=NULL){
			fe=e->endNode->number;
		}
		for(vector<NormalEdge>::iterator it = edges.begin(); it != edges.end(); ++it) {
			NormalEdge *edgeTmp=&(*it);
			int ss=0;
			if(edgeTmp->startNode!=NULL){
				ss=edgeTmp->startNode->number;
			}
			int se=0;
			if(edgeTmp->endNode!=NULL){
				se=edgeTmp->endNode->number;
			}
			if(fs==ss && fe==se){
				edges.erase(it);
				break;
			}
		}
	}
};

int NormalEdge::returnEndCharacterIndex() {
		if(endNode->isLeaf==1){
			return currentPosition;
		}
		else{
			return endCharacterIndex;
		}
	}

//The algorithm is based on the triple: Active Node, Active Edge and Active Lenght which keeps a better track
//of the current step and helps out with characters already inserted in the tree, as well as with suffix links
class Triple{
public:
	Node *activeNode;
	NormalEdge *activeEdge;
	int length;

	Triple() {}

	Triple(Node * _activeNode, int _length){
		this->activeNode=_activeNode;
		this->length=_length;
		this->activeEdge=NULL;
	}
};

//The Tree instance which iscreated from the initial input.
class SuffixTree {
private:
    Node *root;
	int nodeNumber;
	string inputString;
	Triple *activePoint;
	int remainder;
	stringstream graphvizOutput;   //Output is in dot notation (gaphviz)
	int startCharacterIndexForInsertInString;
	Node *previousInsertedNode;

public:
    SuffixTree(string _inputString){
        this->inputString = _inputString;
		this->nodeNumber=1;
		this->root=new Node(this->nodeNumber, false);
		this->nodeNumber++;
		this->remainder=0;
		this->startCharacterIndexForInsertInString=0;
		this->graphvizOutput.clear();
		Triple *triple=new Triple(root, 0);
		this->activePoint=triple;
		this->previousInsertedNode=NULL;
    }

    void CreateSuffixTree(){
		int inputStringLen=inputString.length();
		for(int i=0;i<inputStringLen; i++){
			AddCharacter(inputString[i]);
		}
	}

    //Handling a new character while following all the rules
	void AddCharacter(char c){
		this->previousInsertedNode=NULL;
		currentPosition++;
		this->remainder++;

		while(this->remainder>0){

			if(this->activePoint->length==0){
				this->startCharacterIndexForInsertInString=currentPosition;
			}

			if(NeedToInsertNewEdge(false)){
				AddNewEdge(activePoint->activeNode, startCharacterIndexForInsertInString, startCharacterIndexForInsertInString);
				if(previousInsertedNode!=NULL){
					previousInsertedNode->suffixEdge=activePoint->activeNode;
				}
				previousInsertedNode=activePoint->activeNode;
			}
			else{
				activePoint->activeEdge=ChooseActiveEdge();
				int edgeLen=activePoint->activeEdge->endCharacterIndex-activePoint->activeEdge->startCharacterIndex+1;
				if(activePoint->length>=edgeLen){

					startCharacterIndexForInsertInString+=edgeLen;
					activePoint->length-=edgeLen;
					activePoint->activeNode=activePoint->activeEdge->endNode;
					activePoint->activeEdge=ChooseActiveEdge();
					continue;
				}
				if(!NeedToInsertNewEdge(true)){

					activePoint->length++;
					if(previousInsertedNode!=NULL){
						previousInsertedNode->suffixEdge=activePoint->activeNode;
					}
					previousInsertedNode=activePoint->activeNode;
					break;
				}

			    int splitIndex=activePoint->length+activePoint->activeEdge->startCharacterIndex;
				AddNewInternalEdge(splitIndex, currentPosition);
				if(previousInsertedNode!=NULL){
					previousInsertedNode->suffixEdge=activePoint->activeEdge->endNode;
				}
				previousInsertedNode=activePoint->activeEdge->endNode;
			}
			remainder--;
			if(activePoint->activeNode->number==root->number && activePoint->length>0){
				activePoint->length--;
				startCharacterIndexForInsertInString++;
				activePoint->activeEdge=ChooseActiveEdge();
			}
			else{
				if(activePoint->activeNode->suffixEdge==NULL){
					activePoint->activeNode=root;
				}
				else{
					activePoint->activeNode=activePoint->activeNode->suffixEdge;
				}
			}
		}

	}

    //Creating a new edge in the tree
	void AddNewEdge(Node *startNode, int startIndex, int endIndex){
			Node *leaf=new Node(nodeNumber, true);
			nodeNumber++;
			NormalEdge *edge=new NormalEdge(startIndex, endIndex, startNode, leaf);
			startNode->edges.push_back(*edge);
	}

	void AddNewInternalEdge(int startIndex, int endIndex){
		Node *splittedEdgeNode =new Node(nodeNumber, false);
		nodeNumber++;

		NormalEdge *splittedEdge=new NormalEdge(activePoint->activeEdge->startCharacterIndex, startIndex-1, activePoint->activeNode, splittedEdgeNode);
		activePoint->activeNode->edges.push_back(*splittedEdge);
		activePoint->activeEdge=ChooseActiveEdge();

		Node *leafEdgeNode=new Node(nodeNumber, true);
		nodeNumber++;
		NormalEdge *leafEdge=new NormalEdge(endIndex, endIndex, splittedEdgeNode, leafEdgeNode);
		splittedEdgeNode->edges.push_back(*leafEdge);

		activePoint->activeEdge->startCharacterIndex+=activePoint->length;

		activePoint->activeEdge->startNode=splittedEdgeNode;
		splittedEdgeNode->edges.push_back(*(activePoint->activeEdge));

		activePoint->activeNode->RemoveEdge(activePoint->activeEdge);
		activePoint->activeEdge=splittedEdge;
	}

	bool NeedToInsertNewEdge(bool useActiveLen){
		int len=1;
		if(useActiveLen){
			len+=activePoint->length;
		}
		if(activePoint->activeEdge==NULL){

			int edgesSize=activePoint->activeNode->edges.size();
			for(int i=0;i<edgesSize;i++){

				if(len==1){
					NormalEdge *tmp=&activePoint->activeNode->edges.at(i);
					char s1=inputString.at(tmp->startCharacterIndex);
					char s2=inputString.at(startCharacterIndexForInsertInString);
					if(s1==s2){//equals
						return false;
					}
				}
				else{
					NormalEdge *tmp=&activePoint->activeNode->edges.at(i);
					string s1=inputString.substr(tmp->startCharacterIndex, len);
					string s2=inputString.substr(startCharacterIndexForInsertInString, len);
					if(s1.compare(s2)==0){//equals
						return false;
					}
				}
			}
			return true;
		}
		else{
			if(len==1){
					char s1=inputString.at(activePoint->activeEdge->startCharacterIndex);
					char s2=inputString.at(startCharacterIndexForInsertInString);
					if(s1==s2){//equals
						return false;
					}
			}
			else{
				string s1=inputString.substr(activePoint->activeEdge->startCharacterIndex, len);
				string s2=inputString.substr(startCharacterIndexForInsertInString, len);
				if(s1.compare(s2)==0){//equals
					return false;
				}
			}
		}
		return true;
	}

	NormalEdge* ChooseActiveEdge(){
		int edgeSize=activePoint->activeNode->edges.size();
		for(int i=0;i<edgeSize;i++){
			NormalEdge *tmpEdge=&activePoint->activeNode->edges.at(i);
			char s1=inputString.at(tmpEdge->startCharacterIndex);
			char s2=inputString.at(startCharacterIndexForInsertInString);
			if(s1==s2)//equals
			{
				return tmpEdge;
			}
		}
		return NULL;
	}

	//Printing the edges in a standard .dot notation
	void PrintEdges(Node *n){
		int edgesSize=n->edges.size();
		for(int i=0;i<edgesSize;i++){
			NormalEdge *tmp=&n->edges.at(i);
			graphvizOutput<<"\t node"<<n->number;
			graphvizOutput<<" -> node"<<tmp->endNode->number;
			graphvizOutput<<" [label=\"";
			graphvizOutput<<inputString.substr(tmp->startCharacterIndex, tmp->returnEndCharacterIndex()-tmp->startCharacterIndex+1);
			graphvizOutput<<"\",weight=3] \n";
			PrintEdges(tmp->endNode);
		}
	}

	void PrintInternalNodes(Node *n){
		int edgesSize=n->edges.size();
		if(n->number!=root->number && edgesSize>0){
			graphvizOutput<<"\t node";
			graphvizOutput<<n->number;
			graphvizOutput<<" [label=\"\",style=filled,fillcolor=lightgrey,shape=circle,width=.07,height=.07] \n";
		}
		if(edgesSize>0){
			for(int i=0;i<edgesSize;i++){
				NormalEdge *e=&n->edges.at(i);
				if(e->endNode!=NULL){
					PrintInternalNodes(e->endNode);
				}
			}
		}
	}

	void PrintLeaves(Node *n){
		int edgesSize=n->edges.size();
		if(edgesSize==0){
			graphvizOutput<<"\t node"<<n->number;
			graphvizOutput<<" [label=\"\",shape=point] \n";
		}
		else{
			for(int i=0;i<edgesSize;i++){
				NormalEdge *tmp=&n->edges.at(i);
				if(tmp->endNode!=NULL){
					PrintLeaves(tmp->endNode);
				}
			}
		}
	}

	void PrintSuffixEdges(Node *n){
		if(n->suffixEdge!=NULL){
			graphvizOutput<<"\t node" ;
			graphvizOutput<<n->number<<" -> node";
			graphvizOutput<<n->suffixEdge->number<<" [label=\"\",weight=1,style=dotted] \n";
		}
		int edgesSize=n->edges.size();
		for(int i=0;i<edgesSize;i++){
			NormalEdge *e=&n->edges.at(i);
			if(e->endNode!=NULL){
			PrintSuffixEdges(e->endNode);
			}
		}
	}

	//Printing the tree in a .dot format which is a standard for graphviz visualization
	string PrintTree()
	{
		graphvizOutput.clear();
        graphvizOutput<<"digraph { \n";
        graphvizOutput<<"\t rankdir = LR; \n";
        graphvizOutput<<"\t edge [arrowsize=0.5,fontsize=12] \n";
        graphvizOutput<<"\t node1 [label=\"\",style=filled,fillcolor=lightgrey,shape=circle,width=.1,height=.1]; \n";
        graphvizOutput<<"//------leaves------ \n";
        PrintLeaves(root);
        graphvizOutput<<"//------nodes------ \n";
        PrintInternalNodes(root);
        graphvizOutput<<"//------edges------ \n";
        PrintEdges(root);
        graphvizOutput<<"//------suffix links------ \n";
	    PrintSuffixEdges(root);
        graphvizOutput<<"} \n";

        return graphvizOutput.str();
	}

};

//Methods handling input/output

void WriteToFile(string str, char* fileName)
{
	ofstream outFile;
    outFile.open(fileName);
    outFile<<str;
    outFile.close();
}

string ReadFromFile(const char *filename)
{
  ifstream inFile(filename);
  if (inFile)
  {
    std::string input;
    inFile.seekg(0, std::ios::end);
    input.resize(inFile.tellg());
    inFile.seekg(0, std::ios::beg);
    inFile.read(&input[0], input.size());
    inFile.close();
    return(input);
  }
}

int main (int argc, char* argv[]) {
    return 0;
}
<|endoftext|>


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

void ir_print_visitor::visit(ir_variable *ir)
{
   printf("(declare \n");

   const char *const cent = (ir->centroid) ? "centroid " : "";
   const char *const inv = (ir->invariant) ? "invariant " : "";
   const char *const mode[] = { "", "uniform ", "in ", "out ", "inout " };
   const char *const interp[] = { "", "flat", "noperspective" };

   printf("    (%s%s%s%s)\n",
	  cent, inv, mode[ir->mode], interp[ir->interpolation]);

   printf("    (FINISHME: type goes here)\n");
   printf("    (%s)\n", ir->name);
   printf(")\n");
}

void ir_print_visitor::visit(ir_label *ir)
{
   printf("(label %s)\n", ir->label);
}

void ir_print_visitor::visit(ir_function_signature *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}

void ir_print_visitor::visit(ir_function *ir)
{
   printf("(function %s\n", ir->name);
   printf(")\n");
}

void ir_print_visitor::visit(ir_expression *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}

void ir_print_visitor::visit(ir_dereference *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}

void ir_print_visitor::visit(ir_assignment *ir)
{
   printf("(assign\n");

   printf("    (");
   if (ir->condition)
      ir->condition->accept(this);
   else
      printf("true");
   printf(")\n");

   printf("    (");
   ir->lhs->accept(this);
   printf(")\n");

   printf("    (");
   ir->rhs->accept(this);
   printf(")\n");
}

void ir_print_visitor::visit(ir_constant *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}
<commit_msg>IR print visitor: Add some support for printing types and constants<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
#include <cstdio>
#include "ir_print_visitor.h"
#include "glsl_types.h"

static void
print_type(const glsl_type *t)
{
   if (t->base_type == GLSL_TYPE_ARRAY) {
      printf("array\n");
      printf("    (");
      print_type(t->fields.array);
      printf(")\n");

      printf("    (%u)\n", t->length);
      printf(")");
   } else if (t->base_type == GLSL_TYPE_STRUCT) {
      printf("struct (%s %u\n", t->name ? t->name : "@", t->length);
      printf("    (FINISHME: structure fields go here)\n");
      printf(")");
   } else {
      printf("%s", t->name);
   }
}

void ir_print_visitor::visit(ir_variable *ir)
{
   printf("(declare \n");

   const char *const cent = (ir->centroid) ? "centroid " : "";
   const char *const inv = (ir->invariant) ? "invariant " : "";
   const char *const mode[] = { "", "uniform ", "in ", "out ", "inout " };
   const char *const interp[] = { "", "flat", "noperspective" };

   printf("    (%s%s%s%s)\n",
	  cent, inv, mode[ir->mode], interp[ir->interpolation]);

   printf("    (");
   print_type(ir->type);
   printf(")\n");

   printf("    (%s)\n", ir->name);
   printf(")\n");
}

void ir_print_visitor::visit(ir_label *ir)
{
   printf("(label %s)\n", ir->label);
}

void ir_print_visitor::visit(ir_function_signature *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}

void ir_print_visitor::visit(ir_function *ir)
{
   printf("(function %s\n", ir->name);
   printf(")\n");
}

void ir_print_visitor::visit(ir_expression *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}

void ir_print_visitor::visit(ir_dereference *ir)
{
   printf("%s:%d:\n", __func__, __LINE__);
   (void) ir;
}

void ir_print_visitor::visit(ir_assignment *ir)
{
   printf("(assign\n");

   printf("    (");
   if (ir->condition)
      ir->condition->accept(this);
   else
      printf("true");
   printf(")\n");

   printf("    (");
   ir->lhs->accept(this);
   printf(")\n");

   printf("    (");
   ir->rhs->accept(this);
   printf(")\n");
}

void ir_print_visitor::visit(ir_constant *ir)
{
   (void) ir;

   printf("(constant\n");
   printf("    (");
   print_type(ir->type);
   printf(")\n");
   printf("    (FINISHME: value goes here)\n");
   printf(")\n");
}
<|endoftext|>


<commit_before>#include "binaryio.h"

namespace scpak
{
    void BinaryReader::readBytes(int size, byte buf[])
    {
        for (int i = 0; i<size; ++i)
            buf[i] = readByte();
    }

    int BinaryReader::readInt()
    {
        int value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    float BinaryReader::readFloat()
    {
        float value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    int BinaryReader::read7BitEncodedInt()
    {
        int value = 0;
        int offset = 0;
        while (offset != 35)
        {
            byte b = readByte();
            value |= static_cast<int>(b & 127) << offset;
            offset += 7;
            if ((b & 128) == 0)
                return value;
        }
        throw std::runtime_error("bad 7 bit encoded int32");
    }

    int BinaryReader::readUtf8Char()
    {
        byte first = readByte();
        if ((first & 0b10000000) == 0)
            // only one byte long, 0b0???????
            return static_cast<int>(first);
        if ((first & 0b11000000) == 0b11000000 && (first & 0b00100000) == 0)
        {
            // two bytes long, 0b110????? 0b10??????
            int second = readByte();
            int value = (first & 0b00011111) << 6;
            value |= second & 0b00111111;
            return value;
        }
        if ((first & 0b11100000) == 0b11100000 && (first & 0b00010000) == 0)
        {
            // three bytes long, 0b1110???? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int value = (first & 0b00001111) << 12;
            value |= (second & 0b00111111) << 6;
            value |= third & 0b00111111;
            return value;
        }
        if ((first & 0b11110000) == 0b11110000 && (first & 0b00001000) == 0)
        {
            // four bytes long, 0b11110??? 0b10?????? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int fourth = readByte();
            int value = (first & 0b00000111) << 18;
            value |= (second & 0b00111111) << 12;
            value |= (third & 0b00111111) << 6;
            value |= fourth & 0b00111111;
            return value;
        }
        throw std::runtime_error("utf-8 encoded unicode is too large");
    }

    bool BinaryReader::readBoolean()
    {
        return bool(readByte());
    }

    std::string BinaryReader::readString()
    {
        int length = read7BitEncodedInt();
        std::string buffer;
        buffer.resize(length);
        for (int i = 0; i<length; ++i)
            buffer[i] = static_cast<char>(readByte());
        return buffer;
    }

    int BinaryReader::getUtf8CharCount(const std::string &value)
    {
        MemoryBinaryReader reader(reinterpret_cast<const byte*>(value.data()));
        int count = 0;
        while (reader.position < value.length())
        {
            int unicode = reader.readUtf8Char();
            ++count;
        }
        return count;
    }

    StreamBinaryReader::StreamBinaryReader(std::istream *stream)
    {
        m_stream = stream;
    }

    byte StreamBinaryReader::readByte()
    {
        if (!*m_stream)
            throw std::runtime_error("bad stream");
        char ch;
        m_stream->get(ch);
        return static_cast<byte>(ch);
    }

    MemoryBinaryReader::MemoryBinaryReader(const byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    byte MemoryBinaryReader::readByte()
    {
        return m_buffer[position++];
    }

    StreamBinaryWriter::StreamBinaryWriter(std::ostream *stream)
    {
        m_stream = stream;
    }

    void StreamBinaryWriter::writeByte(byte value)
    {
        if (!m_stream)
            throw std::runtime_error("bad stream");
        char ch = static_cast<char>(value);
        m_stream->put(ch);
    }

    MemoryBinaryWriter::MemoryBinaryWriter(byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    void MemoryBinaryWriter::writeByte(byte value)
    {
        m_buffer[position++] = value;
    }

    void BinaryWriter::writeBytes(int size, const byte value[])
    {
        for (int i = 0; i<size; ++i)
            writeByte(value[i]);
    }

    void BinaryWriter::writeInt(int value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    void BinaryWriter::writeFloat(float value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    int BinaryWriter::write7BitEncodedInt(int value)
    {
        int count = 0;
        while (value > 127)
        {
            byte n = static_cast<byte>(value & 127);
            n |= 128;
            writeByte(n); ++count;
            value >>= 7;
        }
        byte n = static_cast<byte>(value);
        writeByte(n); ++count;
        return count;
    }

    int BinaryWriter::writeUtf8Char(int value)
    {
        if (value <= 0x7f)
        {
            writeByte(static_cast<byte>(value));
            return 1;
        }
        if (value <= 0x7ff)
        {
            byte first = value >> 6;
            first &= 0b11011111;
            first |= 0b11000000;
            byte second = value & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;
            writeByte(first);
            writeByte(second);
            return 2;
        }
        if (value <= 0xffff)
        {
            byte first = value >> 12;
            first &= 0b11101111;
            first |= 0b11100000;

            byte second = (value >> 6) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = value & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            return 3;
        }
        if (value <= 0x10ffff)
        {
            byte first = value >> 18;
            first &= 0b11110111;
            first |= 0b11110000;

            byte second = (value >> 12) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = (value >> 6) & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            byte fourth = value & 0b00111111;
            fourth &= 0b10111111;
            fourth |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            writeByte(fourth);
            return 4;
        }
        throw std::runtime_error("unicode is too large");
    }

    void BinaryWriter::writeBoolean(bool value)
    {
        writeByte(byte(value));
    }

    void BinaryWriter::writeString(const std::string &value)
    {
        write7BitEncodedInt(value.length());
        writeBytes(value.length(), reinterpret_cast<const byte*>(value.data()));
    }
}<commit_msg>add missing #include <stdexcept><commit_after>#include "binaryio.h"
#include <stdexcept>

namespace scpak
{
    void BinaryReader::readBytes(int size, byte buf[])
    {
        for (int i = 0; i<size; ++i)
            buf[i] = readByte();
    }

    int BinaryReader::readInt()
    {
        int value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    float BinaryReader::readFloat()
    {
        float value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    int BinaryReader::read7BitEncodedInt()
    {
        int value = 0;
        int offset = 0;
        while (offset != 35)
        {
            byte b = readByte();
            value |= static_cast<int>(b & 127) << offset;
            offset += 7;
            if ((b & 128) == 0)
                return value;
        }
        throw std::runtime_error("bad 7 bit encoded int32");
    }

    int BinaryReader::readUtf8Char()
    {
        byte first = readByte();
        if ((first & 0b10000000) == 0)
            // only one byte long, 0b0???????
            return static_cast<int>(first);
        if ((first & 0b11000000) == 0b11000000 && (first & 0b00100000) == 0)
        {
            // two bytes long, 0b110????? 0b10??????
            int second = readByte();
            int value = (first & 0b00011111) << 6;
            value |= second & 0b00111111;
            return value;
        }
        if ((first & 0b11100000) == 0b11100000 && (first & 0b00010000) == 0)
        {
            // three bytes long, 0b1110???? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int value = (first & 0b00001111) << 12;
            value |= (second & 0b00111111) << 6;
            value |= third & 0b00111111;
            return value;
        }
        if ((first & 0b11110000) == 0b11110000 && (first & 0b00001000) == 0)
        {
            // four bytes long, 0b11110??? 0b10?????? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int fourth = readByte();
            int value = (first & 0b00000111) << 18;
            value |= (second & 0b00111111) << 12;
            value |= (third & 0b00111111) << 6;
            value |= fourth & 0b00111111;
            return value;
        }
        throw std::runtime_error("utf-8 encoded unicode is too large");
    }

    bool BinaryReader::readBoolean()
    {
        return bool(readByte());
    }

    std::string BinaryReader::readString()
    {
        int length = read7BitEncodedInt();
        std::string buffer;
        buffer.resize(length);
        for (int i = 0; i<length; ++i)
            buffer[i] = static_cast<char>(readByte());
        return buffer;
    }

    int BinaryReader::getUtf8CharCount(const std::string &value)
    {
        MemoryBinaryReader reader(reinterpret_cast<const byte*>(value.data()));
        int count = 0;
        while (reader.position < value.length())
        {
            int unicode = reader.readUtf8Char();
            ++count;
        }
        return count;
    }

    StreamBinaryReader::StreamBinaryReader(std::istream *stream)
    {
        m_stream = stream;
    }

    byte StreamBinaryReader::readByte()
    {
        if (!*m_stream)
            throw std::runtime_error("bad stream");
        char ch;
        m_stream->get(ch);
        return static_cast<byte>(ch);
    }

    MemoryBinaryReader::MemoryBinaryReader(const byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    byte MemoryBinaryReader::readByte()
    {
        return m_buffer[position++];
    }

    StreamBinaryWriter::StreamBinaryWriter(std::ostream *stream)
    {
        m_stream = stream;
    }

    void StreamBinaryWriter::writeByte(byte value)
    {
        if (!m_stream)
            throw std::runtime_error("bad stream");
        char ch = static_cast<char>(value);
        m_stream->put(ch);
    }

    MemoryBinaryWriter::MemoryBinaryWriter(byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    void MemoryBinaryWriter::writeByte(byte value)
    {
        m_buffer[position++] = value;
    }

    void BinaryWriter::writeBytes(int size, const byte value[])
    {
        for (int i = 0; i<size; ++i)
            writeByte(value[i]);
    }

    void BinaryWriter::writeInt(int value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    void BinaryWriter::writeFloat(float value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    int BinaryWriter::write7BitEncodedInt(int value)
    {
        int count = 0;
        while (value > 127)
        {
            byte n = static_cast<byte>(value & 127);
            n |= 128;
            writeByte(n); ++count;
            value >>= 7;
        }
        byte n = static_cast<byte>(value);
        writeByte(n); ++count;
        return count;
    }

    int BinaryWriter::writeUtf8Char(int value)
    {
        if (value <= 0x7f)
        {
            writeByte(static_cast<byte>(value));
            return 1;
        }
        if (value <= 0x7ff)
        {
            byte first = value >> 6;
            first &= 0b11011111;
            first |= 0b11000000;
            byte second = value & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;
            writeByte(first);
            writeByte(second);
            return 2;
        }
        if (value <= 0xffff)
        {
            byte first = value >> 12;
            first &= 0b11101111;
            first |= 0b11100000;

            byte second = (value >> 6) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = value & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            return 3;
        }
        if (value <= 0x10ffff)
        {
            byte first = value >> 18;
            first &= 0b11110111;
            first |= 0b11110000;

            byte second = (value >> 12) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = (value >> 6) & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            byte fourth = value & 0b00111111;
            fourth &= 0b10111111;
            fourth |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            writeByte(fourth);
            return 4;
        }
        throw std::runtime_error("unicode is too large");
    }

    void BinaryWriter::writeBoolean(bool value)
    {
        writeByte(byte(value));
    }

    void BinaryWriter::writeString(const std::string &value)
    {
        write7BitEncodedInt(value.length());
        writeBytes(value.length(), reinterpret_cast<const byte*>(value.data()));
    }
}
<|endoftext|>