<commit_before>/*
 * Copyright (c) 2011, Peter Thorson. 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 WebSocket++ Project 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 PETER THORSON 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.
 *
 */

#ifndef WEBSOCKET_CONSTANTS_HPP
#define WEBSOCKET_CONSTANTS_HPP

#ifndef __STDC_LIMIT_MACROS
  #define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>

// SIZE_MAX appears to be a compiler thing not an OS header thing.
// make sure it is defined.
#ifndef SIZE_MAX
    #define SIZE_MAX ((size_t)(-1))
#endif

#include <exception>
#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

// Defaults
namespace websocketpp {
    typedef std::vector<unsigned char> binary_string;
    typedef boost::shared_ptr<binary_string> binary_string_ptr;

    typedef std::string utf8_string;
    typedef boost::shared_ptr<utf8_string> utf8_string_ptr;

    const uint64_t DEFAULT_MAX_MESSAGE_SIZE = 0xFFFFFF; // ~16MB

    const uint16_t DEFAULT_PORT = 80;
    const uint16_t DEFAULT_SECURE_PORT = 443;

    inline uint16_t default_port(bool secure) {
        return (secure ? DEFAULT_SECURE_PORT : DEFAULT_PORT);
    }

    namespace session {
        namespace state {
            enum value {
                CONNECTING = 0,
                OPEN = 1,
                CLOSING = 2,
                CLOSED = 3
            };
        }
    }

    namespace close {
    namespace status {
        enum value {
            INVALID_END = 999,
            NORMAL = 1000,
            GOING_AWAY = 1001,
            PROTOCOL_ERROR = 1002,
            UNSUPPORTED_DATA = 1003,
            RSV_ADHOC_1 = 1004,
            NO_STATUS = 1005,
            ABNORMAL_CLOSE = 1006,
            INVALID_PAYLOAD = 1007,
            POLICY_VIOLATION = 1008,
            MESSAGE_TOO_BIG = 1009,
            EXTENSION_REQUIRE = 1010,
            INTERNAL_ENDPOINT_ERROR = 1011,
            RSV_START = 1012,
            RSV_END = 2999,
            INVALID_START = 5000
        };

        inline bool reserved(value s) {
            return ((s >= RSV_START && s <= RSV_END) ||
                    s == RSV_ADHOC_1);
        }

        inline bool invalid(value s) {
            return ((s <= INVALID_END || s >= INVALID_START) ||
                    s == NO_STATUS ||
                    s == ABNORMAL_CLOSE);
        }

        // TODO functions for application ranges?
    } // namespace status
    } // namespace close

    namespace frame {
        // Opcodes are 4 bits
        // See spec section 5.2
        namespace opcode {
            enum value {
                CONTINUATION = 0x0,
                TEXT = 0x1,
                BINARY = 0x2,
                RSV3 = 0x3,
                RSV4 = 0x4,
                RSV5 = 0x5,
                RSV6 = 0x6,
                RSV7 = 0x7,
                CLOSE = 0x8,
                PING = 0x9,
                PONG = 0xA,
                CONTROL_RSVB = 0xB,
                CONTROL_RSVC = 0xC,
                CONTROL_RSVD = 0xD,
                CONTROL_RSVE = 0xE,
                CONTROL_RSVF = 0xF,
            };

            inline bool reserved(value v) {
                return (v >= RSV3 && v <= RSV7) ||
                (v >= CONTROL_RSVB && v <= CONTROL_RSVF);
            }

            inline bool invalid(value v) {
                return (v > 0xF || v < 0);
            }

            inline bool is_control(value v) {
                return v >= 0x8;
            }
        }

        namespace limits {
            static const uint8_t PAYLOAD_SIZE_BASIC = 125;
            static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535
            static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFF;//2^63
        }
    } // namespace frame

    // exception class for errors that should be propogated back to the user.
    namespace error {
        enum value {
            GENERIC = 0,
            // send attempted when endpoint write queue was full
            SEND_QUEUE_FULL = 1,
            PAYLOAD_VIOLATION = 2,
            ENDPOINT_UNSECURE = 3,
            ENDPOINT_UNAVAILABLE = 4
        };
    }

    class exception : public std::exception {
    public:
        exception(const std::string& msg,
                  error::value code = error::GENERIC)
        : m_msg(msg),m_code(code) {}
        ~exception() throw() {}

        virtual const char* what() const throw() {
            return m_msg.c_str();
        }

        error::value code() const throw() {
            return m_code;
        }

        std::string m_msg;
        error::value m_code;
    };
}

#endif // WEBSOCKET_CONSTANTS_HPP
<commit_msg>corrected some stdint issues<commit_after>/*
 * Copyright (c) 2011, Peter Thorson. 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 WebSocket++ Project 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 PETER THORSON 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.
 *
 */

#ifndef WEBSOCKET_CONSTANTS_HPP
#define WEBSOCKET_CONSTANTS_HPP

#ifndef __STDC_LIMIT_MACROS
  #define __STDC_LIMIT_MACROS
#endif
//#include <stdint.h>
#include <boost/cstdint.hpp>

// SIZE_MAX appears to be a compiler thing not an OS header thing.
// make sure it is defined.
#ifndef SIZE_MAX
    #define SIZE_MAX ((size_t)(-1))
#endif

#include <exception>
#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

// Defaults
namespace websocketpp {
    typedef std::vector<unsigned char> binary_string;
    typedef boost::shared_ptr<binary_string> binary_string_ptr;

    typedef std::string utf8_string;
    typedef boost::shared_ptr<utf8_string> utf8_string_ptr;

    const uint64_t DEFAULT_MAX_MESSAGE_SIZE = 0xFFFFFF; // ~16MB

    const uint16_t DEFAULT_PORT = 80;
    const uint16_t DEFAULT_SECURE_PORT = 443;

    inline uint16_t default_port(bool secure) {
        return (secure ? DEFAULT_SECURE_PORT : DEFAULT_PORT);
    }

    namespace session {
        namespace state {
            enum value {
                CONNECTING = 0,
                OPEN = 1,
                CLOSING = 2,
                CLOSED = 3
            };
        }
    }

    namespace close {
    namespace status {
        enum value {
            INVALID_END = 999,
            NORMAL = 1000,
            GOING_AWAY = 1001,
            PROTOCOL_ERROR = 1002,
            UNSUPPORTED_DATA = 1003,
            RSV_ADHOC_1 = 1004,
            NO_STATUS = 1005,
            ABNORMAL_CLOSE = 1006,
            INVALID_PAYLOAD = 1007,
            POLICY_VIOLATION = 1008,
            MESSAGE_TOO_BIG = 1009,
            EXTENSION_REQUIRE = 1010,
            INTERNAL_ENDPOINT_ERROR = 1011,
            RSV_START = 1012,
            RSV_END = 2999,
            INVALID_START = 5000
        };

        inline bool reserved(value s) {
            return ((s >= RSV_START && s <= RSV_END) ||
                    s == RSV_ADHOC_1);
        }

        inline bool invalid(value s) {
            return ((s <= INVALID_END || s >= INVALID_START) ||
                    s == NO_STATUS ||
                    s == ABNORMAL_CLOSE);
        }

        // TODO functions for application ranges?
    } // namespace status
    } // namespace close

    namespace frame {
        // Opcodes are 4 bits
        // See spec section 5.2
        namespace opcode {
            enum value {
                CONTINUATION = 0x0,
                TEXT = 0x1,
                BINARY = 0x2,
                RSV3 = 0x3,
                RSV4 = 0x4,
                RSV5 = 0x5,
                RSV6 = 0x6,
                RSV7 = 0x7,
                CLOSE = 0x8,
                PING = 0x9,
                PONG = 0xA,
                CONTROL_RSVB = 0xB,
                CONTROL_RSVC = 0xC,
                CONTROL_RSVD = 0xD,
                CONTROL_RSVE = 0xE,
                CONTROL_RSVF = 0xF,
            };

            inline bool reserved(value v) {
                return (v >= RSV3 && v <= RSV7) ||
                (v >= CONTROL_RSVB && v <= CONTROL_RSVF);
            }

            inline bool invalid(value v) {
                return (v > 0xF || v < 0);
            }

            inline bool is_control(value v) {
                return v >= 0x8;
            }
        }

        namespace limits {
            static const uint8_t PAYLOAD_SIZE_BASIC = 125;
            static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535
            static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFFLL;//2^63
        }
    } // namespace frame

    // exception class for errors that should be propogated back to the user.
    namespace error {
        enum value {
            GENERIC = 0,
            // send attempted when endpoint write queue was full
            SEND_QUEUE_FULL = 1,
            PAYLOAD_VIOLATION = 2,
            ENDPOINT_UNSECURE = 3,
            ENDPOINT_UNAVAILABLE = 4
        };
    }

    class exception : public std::exception {
    public:
        exception(const std::string& msg,
                  error::value code = error::GENERIC)
        : m_msg(msg),m_code(code) {}
        ~exception() throw() {}

        virtual const char* what() const throw() {
            return m_msg.c_str();
        }

        error::value code() const throw() {
            return m_code;
        }

        std::string m_msg;
        error::value m_code;
    };
}

#endif // WEBSOCKET_CONSTANTS_HPP
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <string>

#include "tokens.h"
#include "utils/printer.h"
#include "assembler.h"
#include "parser.hpp"

#include "paths.h"

void genObjectFile(const char *filename, std::map<std::string, int> &symbolTable);

extern FILE *yyin;
extern int yyparse(void);
extern Token *root;
extern int rowNum, colNum;

int main(int argc, char *argv[])
{
    Printer& printer = Printer::getInstance();
    std::map<std::string, int> symbolTable;

    if(argc < 2) {
        printer.printfMessage(Printer::ERROR, "usage: %s file [file ...]", argv[0]);
    } else {
        for(int i = 1; i < argc; i++) {
            genObjectFile(argv[i], symbolTable);
        }
    }

    return 0;
}

void genObjectFile(const char *filename, std::map<std::string, int> &symbolTable)
{
    Assembler& as = Assembler::getInstance();
    Printer& printer = Printer::getInstance();

    if((yyin = fopen(filename, "r")) == nullptr) {
         printer.printfMessage(Printer::WARNING, "Skipping file %s ...", filename);
    } else {
        rowNum = 0; colNum = 0;
        yyparse();
        as.assembleProgram(true, filename, root, symbolTable);

        fclose(yyin);
    }
}
<commit_msg>[main] BREAKING BUILD FOR TESTING!!!<commit_after>#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <string>

#include "tokens.h"
#include "utils/printer.h"
#include "assembler.h"
#include "parser.hpp"

#include "paths.h"

void genObjectFile(const char *filename, std::map<std::string, int> &symbolTable);

extern FILE *yyin;
extern int yyparse(void);
extern Token *root;
extern int rowNum, colNum;

int main(int argc, char *argv[])
{
    Printer& printer = Printer::getInstance();
    std::map<std::string, int> symbolTable;

    if(argc < 2) {
        printer.printfMessage(Printer::ERROR, "usage: %s file [file ...]", argv[0]);
    } else {
        for(int i = 1; i < argc; i++) {
            genObjectFile(argv[i], symbolTable);
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "net/TCPConnection.h"
#include "network_os.h"

namespace network {
	TCPConnection::TCPConnection(void) : bound(false), state(SCS_CLOSED), handle(0), af(0) {}

	TCPConnection::TCPConnection(int hndl, int afn) : bound(false), state(SCS_CLOSED), handle(hndl), af(afn)
	{
		TCPConnection::CheckState();
	}

	void TCPConnection::CheckState()
	{
		if(!handle) { return; }
		unsigned long i;
		socklen_t l = sizeof(unsigned long);
		if(!getsockopt(handle, SOL_SOCKET, 0x00700c, (char*)&i, &l)) {
			state = SCS_CONNECTED;
		}
	}

	bool TCPConnection::SetNoDelay(bool enable)
	{
		unsigned long i = (enable ? 1 : 0);
		if(!handle) { return false; }
		if(setsockopt(handle, SOL_SOCKET, TCP_NODELAY, (char*)&i, sizeof(unsigned long))) {
			return false;
		}
		return true;
	}

	bool TCPConnection::SetKeepAlive(unsigned long time, unsigned long intvl, unsigned long probes)
	{
		unsigned long i = (enable ? 1 : 0);
		if(!handle) { return false; }
		if(setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&i, sizeof(unsigned long))) {
			return false;
		}
		if(setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, &time, sizeof(unsigned long))) {
			return false;
		}
		if(setsockopt(mySocket, SOL_TCP, TCP_KEEPCNT, &probes, sizeof(unsigned long))) {
			return false;
		}
		if(setsockopt(mySocket, SOL_TCP, TCP_KEEPINTVL, &intvl, sizeof(unsigned long))) {
			return false;
		}
		return true;
	}

	bool TCPConnection::SetNonBlocking(bool enable)
	{
		if(!handle) { return false; }
	#ifdef WIN32
		unsigned long iMode = (enable ? 1 : 0);
		ioctlsocket(handle, FIONBIO, &iMode);
	#else
		int flags = fcntl(handle, F_GETFL, 0);
		if (enable) {
			flags |= O_NONBLOCK;
		}
		else {
			flags ^= O_NONBLOCK;
		}
		fcntl(handle, F_SETFL, flags);
	#endif
		return true;
	}

	bool TCPConnection::Select(bool rd, bool wr, bool er)
	{
		if(!handle) { return false; }
		fd_set fd;
		FD_ZERO(&fd);
		FD_SET(handle, &fd);
		int i;
		if(i = select(handle+1, (rd ? &fd : NULL), (wr ? &fd : NULL), (er ? &fd : NULL), NULL)) {
			if(i == -1) { return false; }
			return true;
		}
		return false;
	}
	int TCPConnection::Send(const char * buf, int buflen)
	{
		int i;
		if(!handle) { return -1; }
		if(state != SCS_CONNECTED) { return -1; }
		i = send(handle, buf, buflen, 0);
		if(i < 0) {
			TCPConnection::Close();
		}
		return i;
	}
	int TCPConnection::Send(const std::string &s)
	{
		int i;
		if(!handle) { return -1; }
		if(state != SCS_CONNECTED) { return -1; }
		i = send(handle, s.data(), s.length(), 0);
		if(i < 0) {
			TCPConnection::Close();
		}
		return i;
	}
	int TCPConnection::Recv(char * buf, int buflen)
	{
		int i;
		if(!handle) { return -1; }
		if(state != SCS_CONNECTED) { return -1; }
		i = recv(handle, buf, buflen, 0);
		if(i <= 0) {
#ifdef WIN32
			if(WSAGetLastError() == WSAEWOULDBLOCK) {
#else
			if(errno == EAGAIN || errno == EWOULDBLOCK) {
#endif
				return 0;
			}
			TCPConnection::Close();
		}
		return i;
	}
	int TCPConnection::Recv(std::string &s, int buflen)
	{
		if(!handle) { return -1; }
		char *h = new char[buflen];
		int i = Recv(h, buflen);
		if(i > 0) {
			s.assign(h, i);
		}
		delete h;
		return i;
	}

	bool TCPConnection::IsConnected()
	{
		return (state == SCS_CONNECTED);
	}
	bool TCPConnection::IsListening()
	{
		return (state == SCS_LISTEN);
	}
	bool TCPConnection::Select(bool rd, bool wr, bool er, long sec, long microsec)
	{
		if(!handle) { return false; }
		struct timeval tv;
		tv.tv_sec = sec;
		tv.tv_usec = microsec;
		fd_set fd;
		FD_ZERO(&fd);
		FD_SET(handle,&fd);
		int i;
		if(i = select(handle+1, (rd ? &fd : NULL), (wr ? &fd : NULL), (er ? &fd : NULL), &tv)) {
			if(i == -1) { return false; }
			return true;
		}
		return false;
	}

	bool TCPConnection::Accept(TCPConnection * that)
	{
		if(this->state != SCS_LISTEN) { return false; }
		if(!that) { return false; }
		int h;
		socklen_t sas = sizeof(sockaddr);
		h = accept(this->handle, (struct sockaddr*)&that->raddr.addr, &sas);
		if(h == INVALID_SOCKET) {
			return false;
		}
		that->laddr = this->laddr;
		that->raddr.af = this->laddr.af;
		that->af = this->af;
		that->handle = h;
		that->state = SCS_CONNECTED;
		that->bound = true;
		return true;
	}

	bool TCPConnection::Init(ADDRTYPE afn)
	{
		if(handle) {
			Close();
		}
		this->af = afn;
		int sc;
		sc = socket(afn, SOCK_STREAM, IPPROTO_TCP);
		if(INVALID_SOCKET == sc) {
			return false;
		}

		handle = sc;
		state = SCS_CLOSED;
		return true;
	}

	bool TCPConnection::Bind(const NetworkAddress &local)
	{
		if(!handle) { return false; }
		long v = 1;
		if(setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char*)&v, sizeof(long))) {
			return false;
		}
		if(bind(handle, (struct sockaddr*)&local.addr, local.Length())) {
			return false;
		}
		laddr = local;
		bound = true;
		return true;
	}
	bool TCPConnection::Connect(const NetworkAddress &remote)
	{
		if(!handle) { return false; }
		long v = 1;
		if(setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char*)&v, sizeof(long))) {
			return false;
		}
		if(connect(handle, (struct sockaddr*)&remote.addr, remote.Length())) {
			return false;
		}
		raddr = remote;
		state = SCS_CONNECTED;
		bound = true;
		return true;
	}

	bool TCPConnection::Listen(int queue)
	{
		if(!handle) { return false; }
		if(!bound) { return false; }
		if(state != SCS_CLOSED) { return false; }
		if(listen(handle, queue)) {
			return false;
		}
		state = SCS_LISTEN;
		return true;
	}

	void TCPConnection::Close()
	{
		if(!handle) { return; }
		if(state != SCS_CLOSED) {
			shutdown(handle, SHUT_RDWR);
		}
	#ifdef WIN32
		closesocket(handle);
	#else
		close(handle);
	#endif
		state = SCS_CLOSED;
		handle = 0;
	}

	TCPConnection::~TCPConnection(void)
	{
		Close();
	}
}
<commit_msg>Removing Close() call in destructor.<commit_after>#include "net/TCPConnection.h"
#include "network_os.h"

namespace network {
	TCPConnection::TCPConnection(void) : bound(false), state(SCS_CLOSED), handle(0), af(0) {}

	TCPConnection::TCPConnection(int hndl, int afn) : bound(false), state(SCS_CLOSED), handle(hndl), af(afn)
	{
		TCPConnection::CheckState();
	}

	void TCPConnection::CheckState()
	{
		if(!handle) { return; }
		unsigned long i;
		socklen_t l = sizeof(unsigned long);
		if(!getsockopt(handle, SOL_SOCKET, 0x00700c, (char*)&i, &l)) {
			state = SCS_CONNECTED;
		}
	}

	bool TCPConnection::SetNoDelay(bool enable)
	{
		unsigned long i = (enable ? 1 : 0);
		if(!handle) { return false; }
		if(setsockopt(handle, SOL_SOCKET, TCP_NODELAY, (char*)&i, sizeof(unsigned long))) {
			return false;
		}
		return true;
	}

	bool TCPConnection::SetKeepAlive(unsigned long time, unsigned long intvl, unsigned long probes)
	{
		unsigned long i = (enable ? 1 : 0);
		if(!handle) { return false; }
		if(setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&i, sizeof(unsigned long))) {
			return false;
		}
		if(setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, &time, sizeof(unsigned long))) {
			return false;
		}
		if(setsockopt(mySocket, SOL_TCP, TCP_KEEPCNT, &probes, sizeof(unsigned long))) {
			return false;
		}
		if(setsockopt(mySocket, SOL_TCP, TCP_KEEPINTVL, &intvl, sizeof(unsigned long))) {
			return false;
		}
		return true;
	}

	bool TCPConnection::SetNonBlocking(bool enable)
	{
		if(!handle) { return false; }
	#ifdef WIN32
		unsigned long iMode = (enable ? 1 : 0);
		ioctlsocket(handle, FIONBIO, &iMode);
	#else
		int flags = fcntl(handle, F_GETFL, 0);
		if (enable) {
			flags |= O_NONBLOCK;
		}
		else {
			flags ^= O_NONBLOCK;
		}
		fcntl(handle, F_SETFL, flags);
	#endif
		return true;
	}

	bool TCPConnection::Select(bool rd, bool wr, bool er)
	{
		if(!handle) { return false; }
		fd_set fd;
		FD_ZERO(&fd);
		FD_SET(handle, &fd);
		int i;
		if(i = select(handle+1, (rd ? &fd : NULL), (wr ? &fd : NULL), (er ? &fd : NULL), NULL)) {
			if(i == -1) { return false; }
			return true;
		}
		return false;
	}
	int TCPConnection::Send(const char * buf, int buflen)
	{
		int i;
		if(!handle) { return -1; }
		if(state != SCS_CONNECTED) { return -1; }
		i = send(handle, buf, buflen, 0);
		if(i < 0) {
			TCPConnection::Close();
		}
		return i;
	}
	int TCPConnection::Send(const std::string &s)
	{
		int i;
		if(!handle) { return -1; }
		if(state != SCS_CONNECTED) { return -1; }
		i = send(handle, s.data(), s.length(), 0);
		if(i < 0) {
			TCPConnection::Close();
		}
		return i;
	}
	int TCPConnection::Recv(char * buf, int buflen)
	{
		int i;
		if(!handle) { return -1; }
		if(state != SCS_CONNECTED) { return -1; }
		i = recv(handle, buf, buflen, 0);
		if(i <= 0) {
#ifdef WIN32
			if(WSAGetLastError() == WSAEWOULDBLOCK) {
#else
			if(errno == EAGAIN || errno == EWOULDBLOCK) {
#endif
				return 0;
			}
			TCPConnection::Close();
		}
		return i;
	}
	int TCPConnection::Recv(std::string &s, int buflen)
	{
		if(!handle) { return -1; }
		char *h = new char[buflen];
		int i = Recv(h, buflen);
		if(i > 0) {
			s.assign(h, i);
		}
		delete h;
		return i;
	}

	bool TCPConnection::IsConnected()
	{
		return (state == SCS_CONNECTED);
	}
	bool TCPConnection::IsListening()
	{
		return (state == SCS_LISTEN);
	}
	bool TCPConnection::Select(bool rd, bool wr, bool er, long sec, long microsec)
	{
		if(!handle) { return false; }
		struct timeval tv;
		tv.tv_sec = sec;
		tv.tv_usec = microsec;
		fd_set fd;
		FD_ZERO(&fd);
		FD_SET(handle,&fd);
		int i;
		if(i = select(handle+1, (rd ? &fd : NULL), (wr ? &fd : NULL), (er ? &fd : NULL), &tv)) {
			if(i == -1) { return false; }
			return true;
		}
		return false;
	}

	bool TCPConnection::Accept(TCPConnection * that)
	{
		if(this->state != SCS_LISTEN) { return false; }
		if(!that) { return false; }
		int h;
		socklen_t sas = sizeof(sockaddr);
		h = accept(this->handle, (struct sockaddr*)&that->raddr.addr, &sas);
		if(h == INVALID_SOCKET) {
			return false;
		}
		that->laddr = this->laddr;
		that->raddr.af = this->laddr.af;
		that->af = this->af;
		that->handle = h;
		that->state = SCS_CONNECTED;
		that->bound = true;
		return true;
	}

	bool TCPConnection::Init(ADDRTYPE afn)
	{
		if(handle) {
			Close();
		}
		this->af = afn;
		int sc;
		sc = socket(afn, SOCK_STREAM, IPPROTO_TCP);
		if(INVALID_SOCKET == sc) {
			return false;
		}

		handle = sc;
		state = SCS_CLOSED;
		return true;
	}

	bool TCPConnection::Bind(const NetworkAddress &local)
	{
		if(!handle) { return false; }
		long v = 1;
		if(setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char*)&v, sizeof(long))) {
			return false;
		}
		if(bind(handle, (struct sockaddr*)&local.addr, local.Length())) {
			return false;
		}
		laddr = local;
		bound = true;
		return true;
	}
	bool TCPConnection::Connect(const NetworkAddress &remote)
	{
		if(!handle) { return false; }
		long v = 1;
		if(setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char*)&v, sizeof(long))) {
			return false;
		}
		if(connect(handle, (struct sockaddr*)&remote.addr, remote.Length())) {
			return false;
		}
		raddr = remote;
		state = SCS_CONNECTED;
		bound = true;
		return true;
	}

	bool TCPConnection::Listen(int queue)
	{
		if(!handle) { return false; }
		if(!bound) { return false; }
		if(state != SCS_CLOSED) { return false; }
		if(listen(handle, queue)) {
			return false;
		}
		state = SCS_LISTEN;
		return true;
	}

	void TCPConnection::Close()
	{
		if(!handle) { return; }
		if(state != SCS_CLOSED) {
			shutdown(handle, SHUT_RDWR);
		}
	#ifdef WIN32
		closesocket(handle);
	#else
		close(handle);
	#endif
		state = SCS_CLOSED;
		handle = 0;
	}

	TCPConnection::~TCPConnection(void)
	{
//		Close();
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Rhys Ulerich
 *
 * 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/.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <iterator>

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

#include <descendu/hexmap.hpp>
#include <descendu/tile.hpp>

using namespace descendu;

TEST_CASE( "hexmap" ) {

    hexmap<tile> m;
    typedef hexmap<tile>::key_type key_type;

    SECTION( "conjure" ) {
        // Empty on construction
        REQUIRE( m.cbegin() == m.cend() );

        // Insertion with explicit type
        m.conjure(key_type(0, 0));
        auto a = m.cbegin();
        std::advance(a, 1);
        REQUIRE( a == m.cend() );
        REQUIRE( 1 == m.size() );

        // Idempotent re-insertion
        m.conjure(key_type(0, 0));
        auto b = m.cbegin();
        std::advance(b, 1);
        REQUIRE( b == m.cend() );
        REQUIRE( 1 == m.size() );

        // Insertion with nicety provided by hex
        m.conjure(key_type(1, 0));
        auto c = m.cbegin();
        std::advance(c, 2);
        REQUIRE( c == m.cend() );
        REQUIRE( 2 == m.size() );
    }

    SECTION( "mutable" ) {
        auto& a = m.conjure({0, 0});
        a.cannon.increase(1);
        REQUIRE( a.cannon.total() == 1 );

        auto& b = m.lookup({0, 0}).value();
        REQUIRE( b.cannon.total() == 1 );

        // No clobber of existing entry
        auto& c = m.conjure({0, 0});
        REQUIRE( c.cannon.total() == 1 );
    }

    SECTION( "not_found" ) {
        REQUIRE( !m.lookup({0, 0}).has_value() );
        REQUIRE( !m.lookup({0, 0}) );
    }

}

TEST_CASE( "breadth_first_search" ) {

    hexmap<int> m;
    typedef hexmap<tile>::key_type key_type;

    SECTION( "origin_in_map" ) {
        // Add origin
        m.conjure({0, 0});
        // Search
        const auto& retval = breadth_first_search(
            m,
            key_type(0, 0),
            [](const auto&) { return search_result::include; },
            555);
        // Considered origin
        REQUIRE( retval.size() == 1 );
        // Origin considered and provides self-referencing path
        REQUIRE( retval.lookup({0, 0}) );
        REQUIRE( retval.lookup({0, 0}).value() == key_type(0, 0) );

    }

    SECTION( "origin_not_in_map" ) {
        // Origin not added
        // Search
        const auto& retval = breadth_first_search(
            m,
            key_type(0, 0),
            [](const auto&) { return search_result::include; },
            555);
        // Considered origin
        REQUIRE( retval.size() == 1 );
        // Considered origin involves and empty optional
        REQUIRE( !retval.lookup({0, 0}).value() );
    }

    SECTION( "linear_one_direction" ) {
        m.conjure({+0, +0});
        m.conjure({+0, -1});
        m.conjure({+0, -2});
        const auto& retval = breadth_first_search(
            m,
            key_type(0, 0),
            [](const auto&) { return search_result::include; },
            555);
        REQUIRE( retval.size() == 3 );
        REQUIRE( retval.lookup({+0, -2}).value() == key_type(+0, -1) );
        REQUIRE( retval.lookup({+0, -1}).value() == key_type(+0, +0) );
        REQUIRE( retval.lookup({+0, +0}).value() == key_type(+0, +0) );
    }

    SECTION( "linear_all_directions" ) {
        const auto& p0 = key_type(+3, +3);
        const std::vector<int> directions = {0, 1, 2, 3, 4, 5};
        for (const auto direction : directions) {
            // Construct 4 edges in the given direction
            hexmap<int> o;
            o.conjure(p0);
            const auto& p1 = p0.neighbor(direction);
            o.conjure(p1);
            const auto& p2 = p1.neighbor(direction);
            o.conjure(p2);
            const auto& p3 = p2.neighbor(direction);
            o.conjure(p3);
            const auto& p4 = p3.neighbor(direction);
            o.conjure(p4);
            // Search three edges in the direction
            const auto& retval = breadth_first_search(
                o,
                p0,
                [](const auto&) { return search_result::include; },
                3);
            // Origin plus 3 close-enough edges
            REQUIRE( retval.size() == 4 );
            REQUIRE( retval.lookup(p3).value().value() == p2 );
            REQUIRE( retval.lookup(p2).value().value() == p1 );
            REQUIRE( retval.lookup(p1).value().value() == p0 );
            REQUIRE( retval.lookup(p0).value().value() == p0 );
            // Fourth edge was too far
            REQUIRE( !retval.lookup(p4) );
        }
    }

//  SECTION( "outward" ) {
//      m.conjure({+0, +0});
//      m.conjure({+1, +0});
//      m.conjure({+1, -1});
//      m.conjure({+0, -1});
//      m.conjure({-1, +0});
//      m.conjure({-1, +1});
//      m.conjure({+0, +1});
//      const auto& retval = breadth_first_search(
//          m,
//          key_type(0, 0),
//          [](const auto&) { return search_result::include; },
//          555);
//      REQUIRE( retval.size() == 7 );
//      REQUIRE( retval.lookup({+0, +0}).value() == key_type(+0, +0) );
//      REQUIRE( retval.lookup({+1, +0}).value().value() == key_type(+0, +0) );
//      REQUIRE( retval.lookup({+1, -1}).value().value() == key_type(+0, +0) );
//      REQUIRE( retval.lookup({+0, -1}).value().value() == key_type(+0, +0) );
//      REQUIRE( retval.lookup({-1, +0}).value().value() == key_type(+0, +0) );
//      REQUIRE( retval.lookup({-1, +1}).value().value() == key_type(+0, +0) );
//      REQUIRE( retval.lookup({+0, +1}).value().value() == key_type(+0, +0) );
//  }

}
<commit_msg>Progress on bug<commit_after>/*
 * Copyright (C) 2016 Rhys Ulerich
 *
 * 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/.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <iterator>

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

#include <descendu/hexmap.hpp>
#include <descendu/tile.hpp>

using namespace descendu;

TEST_CASE( "hexmap" ) {

    hexmap<tile> m;
    typedef hexmap<tile>::key_type key_type;

    SECTION( "conjure" ) {
        // Empty on construction
        REQUIRE( m.cbegin() == m.cend() );

        // Insertion with explicit type
        m.conjure(key_type(0, 0));
        auto a = m.cbegin();
        std::advance(a, 1);
        REQUIRE( a == m.cend() );
        REQUIRE( 1 == m.size() );

        // Idempotent re-insertion
        m.conjure(key_type(0, 0));
        auto b = m.cbegin();
        std::advance(b, 1);
        REQUIRE( b == m.cend() );
        REQUIRE( 1 == m.size() );

        // Insertion with nicety provided by hex
        m.conjure(key_type(1, 0));
        auto c = m.cbegin();
        std::advance(c, 2);
        REQUIRE( c == m.cend() );
        REQUIRE( 2 == m.size() );
    }

    SECTION( "mutable" ) {
        auto& a = m.conjure({0, 0});
        a.cannon.increase(1);
        REQUIRE( a.cannon.total() == 1 );

        auto& b = m.lookup({0, 0}).value();
        REQUIRE( b.cannon.total() == 1 );

        // No clobber of existing entry
        auto& c = m.conjure({0, 0});
        REQUIRE( c.cannon.total() == 1 );
    }

    SECTION( "not_found" ) {
        REQUIRE( !m.lookup({0, 0}).has_value() );
        REQUIRE( !m.lookup({0, 0}) );
    }

}

TEST_CASE( "breadth_first_search" ) {

    hexmap<int> m;
    typedef hexmap<tile>::key_type key_type;

    SECTION( "origin_in_map" ) {
        // Add origin
        m.conjure({0, 0});
        // Search
        const auto& retval = breadth_first_search(
            m,
            key_type(0, 0),
            [](const auto&) { return search_result::include; },
            555);
        // Considered origin
        REQUIRE( retval.size() == 1 );
        // Origin considered and provides self-referencing path
        REQUIRE( retval.lookup({0, 0}) );
        REQUIRE( retval.lookup({0, 0}).value() == key_type(0, 0) );

    }

    SECTION( "origin_not_in_map" ) {
        // Origin not added
        // Search
        const auto& retval = breadth_first_search(
            m,
            key_type(0, 0),
            [](const auto&) { return search_result::include; },
            555);
        // Considered origin
        REQUIRE( retval.size() == 1 );
        // Considered origin involves and empty optional
        REQUIRE( !retval.lookup({0, 0}).value() );
    }

    SECTION( "linear_one_direction" ) {
        m.conjure({+0, +0});
        m.conjure({+0, -1});
        m.conjure({+0, -2});
        const auto& retval = breadth_first_search(
            m,
            key_type(0, 0),
            [](const auto&) { return search_result::include; },
            555);
        REQUIRE( retval.size() == 3 );
        REQUIRE( retval.lookup({+0, -2}).value() == key_type(+0, -1) );
        REQUIRE( retval.lookup({+0, -1}).value() == key_type(+0, +0) );
        REQUIRE( retval.lookup({+0, +0}).value() == key_type(+0, +0) );
    }

    SECTION( "linear_all_directions" ) {
        const auto& p0 = key_type(+3, +3);
        const std::vector<int> directions = {0, 1, 2, 3, 4, 5};
        for (const auto direction : directions) {
            CAPTURE( direction );
            // Construct 4 edges in the given direction
            hexmap<int> o;
            o.conjure(p0);
            const auto& p1 = p0.neighbor(direction);
            o.conjure(p1);
            const auto& p2 = p1.neighbor(direction);
            o.conjure(p2);
            const auto& p3 = p2.neighbor(direction);
            o.conjure(p3);
            const auto& p4 = p3.neighbor(direction);
            o.conjure(p4);
            // Search three edges in the direction
            const auto& retval = breadth_first_search(
                o,
                p0,
                [](const auto&) { return search_result::include; },
                3);
            // Origin plus 3 close-enough edges
            REQUIRE( retval.size() == 4 );
            REQUIRE( retval.lookup(p3).value().value() == p2 );
            REQUIRE( retval.lookup(p2).value().value() == p1 );
            REQUIRE( retval.lookup(p1).value().value() == p0 );
            REQUIRE( retval.lookup(p0).value().value() == p0 );
            // Fourth edge was too far
            REQUIRE( !retval.lookup(p4) );
        }
    }

    SECTION( "outward_one_step" ) {
        const auto& start = key_type(+0, +0);
        m.conjure(start);
        for (const auto& neighbor : neighbors(start)) {
            std::cout << neighbor << std::endl;
            m.conjure(neighbor);
        }
        const auto& retval = breadth_first_search(
            m,
            start,
            [](const auto&) { return search_result::include; },
            555);
        REQUIRE( retval.size() == 7 );
        REQUIRE( retval.lookup(start).value() == start );
        for (const auto& neighbor : neighbors(start)) {
            CAPTURE( neighbor );
// TODO //  REQUIRE( retval.lookup(neighbor).value().value() == start);
        }
    }

}
<|endoftext|>


<commit_before>// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// @brief IronBee --- LUA rules module tests
///
/// @author Brian Rectanus <brectanus@qualys.com>
//////////////////////////////////////////////////////////////////////////////

#include "gtest/gtest.h"
#include "base_fixture.h"

extern "C" {
#include "lua_common_private.h"
}

#include "ibtest_util.hpp"
#include "engine_private.h"
#include <ironbee/hash.h>
#include <ironbee/mpool.h>
#include <ironbee/field.h>
#include <string>

namespace {
    // Defined in Makefile.am to point to test_module_rules_lua.lua.
    const char* luafile = TEST_LUA_FILE;
}

/**
 * Test rules.
 */
class TestIronBeeModuleRulesLua : public BaseTransactionFixture
{
    protected:
    ib_rule_t *rule;

    public:

    TestIronBeeModuleRulesLua() : BaseTransactionFixture() {
    }

    virtual void SetUp(){
        BaseTransactionFixture::SetUp();
        loadModule("ibmod_rules.so");
        ASSERT_IB_OK(ib_rule_create(ib_engine,
                                    ib_engine->ectx,
                                    __FILE__,
                                    __LINE__,
                                    true,
                                    &rule));
    }

    void setSearchPath(lua_State *L)
    {
        std::string rule_path(IB_XSTRINGIFY(RULE_BASE_PATH));
        std::string module_path(IB_XSTRINGIFY(MODULE_BASE_PATH));

        rule_path.append("/?.lua");
        module_path.append("/?.lua");
        ib_lua_add_require_path(ib_engine, L, rule_path.c_str());
        ib_lua_add_require_path(ib_engine, L, module_path.c_str());
    }
};

TEST_F(TestIronBeeModuleRulesLua, load_eval)
{
    lua_State *L = luaL_newstate();

    luaL_openlibs(L);

    setSearchPath(L);

    ASSERT_NE(static_cast<lua_State*>(NULL), L);
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ffi", "ffi"));
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ibapi", "ironbee/api"));
    ASSERT_EQ(IB_OK, ib_lua_load_eval(ib_engine, L, luafile));

}

TEST_F(TestIronBeeModuleRulesLua, load_func_eval)
{
    int res = 0;
    ib_tx_t tx;
    tx.ib = ib_engine;
    tx.id = "tx_id.TestIronBeeModuleRulesLua.load_func_eval";
    ASSERT_EQ(IB_OK, ib_conn_create(ib_engine, &tx.conn, NULL));

    ib_rule_exec_t rule_exec;
    memset(&rule_exec, 0, sizeof(rule_exec));
    rule_exec.ib = ib_engine;
    rule_exec.tx = &tx;
    rule_exec.rule = rule;

    lua_State *L = luaL_newstate();
    ASSERT_NE(static_cast<lua_State*>(NULL), L);
    luaL_openlibs(L);
    setSearchPath(L);
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ffi", "ffi"));
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ibapi", "ironbee/api"));
    ASSERT_EQ(IB_OK, ib_lua_load_func(ib_engine, L, luafile, "f1"));
    ASSERT_EQ(IB_OK, ib_lua_func_eval_int(ib_engine, &tx, L, "f1", &res));
    ASSERT_EQ(5, res);
}

TEST_F(TestIronBeeModuleRulesLua, new_state)
{
    int res = 0;
    ib_tx_t tx;
    tx.ib = ib_engine;
    tx.mp = ib_engine->mp;

    ib_rule_exec_t rule_exec;
    memset(&rule_exec, 0, sizeof(rule_exec));
    rule_exec.ib = ib_engine;
    rule_exec.tx = &tx;
    rule_exec.rule = rule;

    ib_tx_generate_id(&tx);
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    setSearchPath(L);
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ffi", "ffi"));
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ibapi", "ironbee/api"));
    ASSERT_NE(static_cast<lua_State*>(NULL), L);

    lua_State *L2;

    ASSERT_EQ(IB_OK, ib_lua_new_thread(ib_engine, L, &L2));
    ASSERT_NE(static_cast<lua_State*>(NULL), L2);
    ASSERT_EQ(IB_OK, ib_lua_load_func(ib_engine, L2, luafile, "f1"));
    ASSERT_EQ(IB_OK, ib_lua_func_eval_int(ib_engine, &tx, L2, "f1", &res));
    ASSERT_EQ(IB_OK, ib_lua_join_thread(ib_engine, L, &L2));
    ASSERT_EQ(5, res);
}

TEST_F(TestIronBeeModuleRulesLua, operator_test)
{
    const ib_operator_t *op;
    void *instance_data;
    ib_num_t result;

    ib_field_t* field1;

    const char* op_name = "test_module_rules_lua.lua";
    const char* rule_name = "luarule001";

    char* str1 = (char *)ib_mpool_strdup(ib_engine->mp, "string 1");
    ASSERT_TRUE(str1);

    // Create field 1.
    ASSERT_EQ(IB_OK,
        ib_field_create(
            &field1,
            ib_engine->mp,
            IB_FIELD_NAME("field1"),
            IB_FTYPE_NULSTR,
            ib_ftype_nulstr_in(str1)
        )
    );

    /* Configure the operator. */
    configureIronBee();

    // Ensure that the operator exists.
    ASSERT_EQ(IB_OK,
        ib_operator_lookup(ib_engine, op_name, &op)
    );

    ASSERT_EQ(IB_OK, ib_operator_inst_create(op,
                                             ib_context_main(ib_engine),
                                             IB_OP_CAPABILITY_NON_STREAM,
                                             rule_name,
                                             &instance_data));
    performTx();

    // Attempt to match.
    ASSERT_EQ(IB_OK, ib_operator_inst_execute(op,
                                          instance_data,
                                          ib_tx,
                                          field1,
                                          NULL,
                                          &result));

    // This time we should succeed.
    ASSERT_TRUE(result);
}
<commit_msg>modules/tests/test_module_rules_lua.cpp: Fix uuid usage.<commit_after>// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// @brief IronBee --- LUA rules module tests
///
/// @author Brian Rectanus <brectanus@qualys.com>
//////////////////////////////////////////////////////////////////////////////

#include "gtest/gtest.h"
#include "base_fixture.h"

extern "C" {
#include "lua_common_private.h"
}

#include "ibtest_util.hpp"
#include "engine_private.h"
#include <ironbee/hash.h>
#include <ironbee/mpool.h>
#include <ironbee/field.h>
#include <ironbee/uuid.h>
#include <string>

namespace {
    // Defined in Makefile.am to point to test_module_rules_lua.lua.
    const char* luafile = TEST_LUA_FILE;
}

/**
 * Test rules.
 */
class TestIronBeeModuleRulesLua : public BaseTransactionFixture
{
    protected:
    ib_rule_t *rule;

    public:

    TestIronBeeModuleRulesLua() : BaseTransactionFixture() {
    }

    virtual void SetUp(){
        BaseTransactionFixture::SetUp();
        loadModule("ibmod_rules.so");
        ASSERT_IB_OK(ib_rule_create(ib_engine,
                                    ib_engine->ectx,
                                    __FILE__,
                                    __LINE__,
                                    true,
                                    &rule));
    }

    void setSearchPath(lua_State *L)
    {
        std::string rule_path(IB_XSTRINGIFY(RULE_BASE_PATH));
        std::string module_path(IB_XSTRINGIFY(MODULE_BASE_PATH));

        rule_path.append("/?.lua");
        module_path.append("/?.lua");
        ib_lua_add_require_path(ib_engine, L, rule_path.c_str());
        ib_lua_add_require_path(ib_engine, L, module_path.c_str());
    }
};

TEST_F(TestIronBeeModuleRulesLua, load_eval)
{
    lua_State *L = luaL_newstate();

    luaL_openlibs(L);

    setSearchPath(L);

    ASSERT_NE(static_cast<lua_State*>(NULL), L);
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ffi", "ffi"));
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ibapi", "ironbee/api"));
    ASSERT_EQ(IB_OK, ib_lua_load_eval(ib_engine, L, luafile));

}

TEST_F(TestIronBeeModuleRulesLua, load_func_eval)
{
    int res = 0;
    ib_tx_t tx;
    tx.ib = ib_engine;
    ASSERT_EQ(IB_OK, ib_uuid_create_v4(tx.id));
    ASSERT_EQ(IB_OK, ib_conn_create(ib_engine, &tx.conn, NULL));

    ib_rule_exec_t rule_exec;
    memset(&rule_exec, 0, sizeof(rule_exec));
    rule_exec.ib = ib_engine;
    rule_exec.tx = &tx;
    rule_exec.rule = rule;

    lua_State *L = luaL_newstate();
    ASSERT_NE(static_cast<lua_State*>(NULL), L);
    luaL_openlibs(L);
    setSearchPath(L);
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ffi", "ffi"));
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ibapi", "ironbee/api"));
    ASSERT_EQ(IB_OK, ib_lua_load_func(ib_engine, L, luafile, "f1"));
    ASSERT_EQ(IB_OK, ib_lua_func_eval_int(ib_engine, &tx, L, "f1", &res));
    ASSERT_EQ(5, res);
}

TEST_F(TestIronBeeModuleRulesLua, new_state)
{
    int res = 0;
    ib_tx_t tx;
    tx.ib = ib_engine;
    tx.mp = ib_engine->mp;

    ib_rule_exec_t rule_exec;
    memset(&rule_exec, 0, sizeof(rule_exec));
    rule_exec.ib = ib_engine;
    rule_exec.tx = &tx;
    rule_exec.rule = rule;

    ib_tx_generate_id(&tx);
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    setSearchPath(L);
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ffi", "ffi"));
    ASSERT_EQ(IB_OK, ib_lua_require(ib_engine, L, "ibapi", "ironbee/api"));
    ASSERT_NE(static_cast<lua_State*>(NULL), L);

    lua_State *L2;

    ASSERT_EQ(IB_OK, ib_lua_new_thread(ib_engine, L, &L2));
    ASSERT_NE(static_cast<lua_State*>(NULL), L2);
    ASSERT_EQ(IB_OK, ib_lua_load_func(ib_engine, L2, luafile, "f1"));
    ASSERT_EQ(IB_OK, ib_lua_func_eval_int(ib_engine, &tx, L2, "f1", &res));
    ASSERT_EQ(IB_OK, ib_lua_join_thread(ib_engine, L, &L2));
    ASSERT_EQ(5, res);
}

TEST_F(TestIronBeeModuleRulesLua, operator_test)
{
    const ib_operator_t *op;
    void *instance_data;
    ib_num_t result;

    ib_field_t* field1;

    const char* op_name = "test_module_rules_lua.lua";
    const char* rule_name = "luarule001";

    char* str1 = (char *)ib_mpool_strdup(ib_engine->mp, "string 1");
    ASSERT_TRUE(str1);

    // Create field 1.
    ASSERT_EQ(IB_OK,
        ib_field_create(
            &field1,
            ib_engine->mp,
            IB_FIELD_NAME("field1"),
            IB_FTYPE_NULSTR,
            ib_ftype_nulstr_in(str1)
        )
    );

    /* Configure the operator. */
    configureIronBee();

    // Ensure that the operator exists.
    ASSERT_EQ(IB_OK,
        ib_operator_lookup(ib_engine, op_name, &op)
    );

    ASSERT_EQ(IB_OK, ib_operator_inst_create(op,
                                             ib_context_main(ib_engine),
                                             IB_OP_CAPABILITY_NON_STREAM,
                                             rule_name,
                                             &instance_data));
    performTx();

    // Attempt to match.
    ASSERT_EQ(IB_OK, ib_operator_inst_execute(op,
                                          instance_data,
                                          ib_tx,
                                          field1,
                                          NULL,
                                          &result));

    // This time we should succeed.
    ASSERT_TRUE(result);
}
<|endoftext|>


<commit_before>/*
 * Config
 */

#include "constants.hpp"
#include "config.hpp"

#include <string>
#include <sstream>
#include <iostream>
#include <regex>

int Config::initialize(int argc, char* argv[])
{
    Config* c = Config::getInstance();

    // we handle nodes differently, so we want to parse them in a temp variable
    std::vector< std::string > nodes;

    // parsing program options using boost::program_options
    namespace po = boost::program_options;
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message")
        ("node,n", po::value<std::vector< std::string >>(&nodes),
            "Add node to listen to (multiple arguments allowed)")
        ("box,b", po::value<std::vector <std::string> >(&c->box_dirs_),
            "Add path of a directory to watch (multiple arguments allowed)")
    ;

    po::store(po::parse_command_line( argc, argv, desc ), c->vm_);
    po::notify(c->vm_);

/*
    // adding the subscriber endpoints
    c->subscriber_endpoints_.push_back(
        std::make_pair("ipc://syncbox.ipc",SB_SUBTYPE_TCP_BIDIR)
    );

    // adding the directories to be watched
    std::string box_dir = "/home/alex/bin/ba-arbeit/syncbox/test/testdir_watch";
    c->box_dirs_.push_back(box_dir);
*/
    return c->doSanityCheck( &desc, &nodes );
}

const std::vector< std::pair<std::string,int> >
    Config::getSubscriberEndpoints() const {
        return subscriber_endpoints_;
}

const std::vector< std::string >
    Config::getBoxDirectories() const {
        return box_dirs_;
}

int Config::doSanityCheck(boost::program_options::options_description* desc,
                          std::vector<std::string>* nodes) {

    // check for help argument, print the help, and exit
    if (vm_.count("help")) {
        std::cout << *(desc) << std::endl;
        return 1;
    }

    Config* c = Config::getInstance();

    // checking nodes (need at least one)
    if ( nodes->size() >= 1 ) {
        // TODO add logic for non-bidirectional nodes
        for (std::vector<std::string>::iterator i = nodes->begin();
             i != nodes->end(); ++i)
        {
            // check if the supplied node is connectable
            // only tcp and ipc are allowed
            // depending on the matched regex, the zmq protocol will be appended
            std::smatch sm;
            if ( std::regex_match( *i,
                                   sm,
                                   std::regex("(tcp://)?(.*)(:)([0-9]*)")
                                 ) )
            {
                // prepare the node endpoint
                std::string endpoint = *i;
                if ( sm[1].length() == 0 )
                    endpoint = "tcp://" + endpoint;

                // add it to the config class for later use
                c->subscriber_endpoints_.push_back(
                    std::make_pair( endpoint, SB_SUBTYPE_TCP_BIDIR )
                );
            }
            else if ( std::regex_match( *i,
                                        sm,
                                        std::regex("(ipc://)?(.*)(\\.ipc)")
                                      ) )
            {
                // prepare the node endpoint
                std::string endpoint = *i;
                if ( sm[1].length() == 0 )
                    endpoint = "ipc://" + endpoint;

                // add it to the config class for later use
                c->subscriber_endpoints_.push_back(
                    std::make_pair( endpoint, SB_SUBTYPE_TCP_BIDIR )
                );
            } else {
                std::cerr << "[E] Cannot process node '" << *i << "'" << std::endl;
                return 1;
            }
        }
    } else {
        perror("[E] No nodes supplied, exiting...");
        return 1;
    }

    std::cout << "got " << c->box_dirs_.size() << " boxes" << std::endl;

    return 1;
}
<commit_msg>added sanity check for box strings<commit_after>/*
 * Config
 */

#include "constants.hpp"
#include "config.hpp"

#include <string>
#include <sstream>
#include <iostream>
#include <regex>

int Config::initialize(int argc, char* argv[])
{
    Config* c = Config::getInstance();

    // we handle nodes differently, so we want to parse them in a temp variable
    std::vector< std::string > nodes;

    // parsing program options using boost::program_options
    namespace po = boost::program_options;
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message")
        ("node,n", po::value<std::vector< std::string >>(&nodes),
            "Add node to listen to (multiple arguments allowed)")
        ("box,b", po::value<std::vector <std::string> >(&c->box_dirs_),
            "Add path of a directory to watch (multiple arguments allowed)")
    ;

    po::store(po::parse_command_line( argc, argv, desc ), c->vm_);
    po::notify(c->vm_);

    return c->doSanityCheck( &desc, &nodes );
}

const std::vector< std::pair<std::string,int> >
    Config::getSubscriberEndpoints() const {
        return subscriber_endpoints_;
}

const std::vector< std::string >
    Config::getBoxDirectories() const {
        return box_dirs_;
}

int Config::doSanityCheck(boost::program_options::options_description* desc,
                          std::vector<std::string>* nodes) {

    // check for help argument, print the help, and exit
    if (vm_.count("help")) {
        std::cout << *(desc) << std::endl;
        return 1;
    }

    Config* c = Config::getInstance();

    // checking nodes (need at least one)
    if (SB_MSG_DEBUG) printf("config: checking nodes\n");
    if ( nodes->size() >= 1 ) {
        // TODO add logic for non-bidirectional nodes
        for (std::vector<std::string>::iterator i = nodes->begin();
             i != nodes->end(); ++i)
        {
            // check if the supplied node is connectable
            // only tcp and ipc are allowed
            // depending on the matched regex, the zmq protocol will be appended
            std::smatch sm;
            if ( std::regex_match( *i,
                                   sm,
                                   std::regex("(tcp://)?(.*)(:)([0-9]*)")
                                 ) )
            {
                // prepare the node endpoint
                std::string endpoint = *i;
                if ( sm[1].length() == 0 )
                    endpoint = "tcp://" + endpoint;

                // add it to the config class for later use
                c->subscriber_endpoints_.push_back(
                    std::make_pair( endpoint, SB_SUBTYPE_TCP_BIDIR )
                );
            }
            else if ( std::regex_match( *i,
                                        sm,
                                        std::regex("(ipc://)?(.*)(\\.ipc)")
                                      ) )
            {
                // prepare the node endpoint
                std::string endpoint = *i;
                if ( sm[1].length() == 0 )
                    endpoint = "ipc://" + endpoint;

                // add it to the config class for later use
                c->subscriber_endpoints_.push_back(
                    std::make_pair( endpoint, SB_SUBTYPE_TCP_BIDIR )
                );
            } else {
                std::cerr << "[E] Cannot process node '" << *i << "'" << std::endl;
                return 1;
            }
        }
    } else {
        perror("[E] No nodes supplied, exiting...");
        return 1;
    }

    // checking boxes
    if (SB_MSG_DEBUG) printf("config: checking boxes\n");
    if ( c->box_dirs_.size() >= 1 ) {
        for (std::vector< std::string >::iterator i = c->box_dirs_.begin();
             i != c->box_dirs_.end(); ++i)
        {
            // check if the box locations map to directories on the filesystem
            if ( !boost::filesystem::is_directory(*i) ) {
                std::cerr << "[E] " << *i << " is not a directory." << std::endl;
                return 1;
            }
        }
    } else {
        perror("[E] No box locations supplied, exiting...");
        return 1;
    }

    return 0;
}
<|endoftext|>


<commit_before>//===--- Compression.cpp - Compression implementation ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements compression functions.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Compression.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H
#include <zlib.h>
#endif

using namespace llvm;

#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ
static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) {
  switch (Level) {
    case zlib::NoCompression: return 0;
    case zlib::BestSpeedCompression: return 1;
    case zlib::DefaultCompression: return Z_DEFAULT_COMPRESSION;
    case zlib::BestSizeCompression: return 9;
  }
  llvm_unreachable("Invalid zlib::CompressionLevel!");
}

static zlib::Status encodeZlibReturnValue(int ReturnValue) {
  switch (ReturnValue) {
    case Z_OK: return zlib::StatusOK;
    case Z_MEM_ERROR: return zlib::StatusOutOfMemory;
    case Z_BUF_ERROR: return zlib::StatusBufferTooShort;
    case Z_STREAM_ERROR: return zlib::StatusInvalidArg;
    case Z_DATA_ERROR: return zlib::StatusInvalidData;
    default: llvm_unreachable("unknown zlib return status!");
  }
}

bool zlib::isAvailable() { return true; }
zlib::Status zlib::compress(StringRef InputBuffer,
                            OwningPtr<MemoryBuffer> &CompressedBuffer,
                            CompressionLevel Level) {
  unsigned long CompressedSize = ::compressBound(InputBuffer.size());
  OwningArrayPtr<char> TmpBuffer(new char[CompressedSize]);
  int CLevel = encodeZlibCompressionLevel(Level);
  Status Res = encodeZlibReturnValue(::compress2(
      (Bytef *)TmpBuffer.get(), &CompressedSize,
      (const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel));
  if (Res == StatusOK) {
    CompressedBuffer.reset(MemoryBuffer::getMemBufferCopy(
        StringRef(TmpBuffer.get(), CompressedSize)));
    // Tell MSan that memory initialized by zlib is valid.
    __msan_unpoison(CompressedBuffer.data(), CompressedBuffer.size());
  }
  return Res;
}

zlib::Status zlib::uncompress(StringRef InputBuffer,
                              OwningPtr<MemoryBuffer> &UncompressedBuffer,
                              size_t UncompressedSize) {
  OwningArrayPtr<char> TmpBuffer(new char[UncompressedSize]);
  Status Res = encodeZlibReturnValue(
      ::uncompress((Bytef *)TmpBuffer.get(), (uLongf *)&UncompressedSize,
                   (const Bytef *)InputBuffer.data(), InputBuffer.size()));
  if (Res == StatusOK) {
    UncompressedBuffer.reset(MemoryBuffer::getMemBufferCopy(
        StringRef(TmpBuffer.get(), UncompressedSize)));
    // Tell MSan that memory initialized by zlib is valid.
    __msan_unpoison(UncompressedBuffer.data(), UncompressedBuffer.size());
  }
  return Res;
}

#else
bool zlib::isAvailable() { return false; }
zlib::Status zlib::compress(StringRef InputBuffer,
                            OwningPtr<MemoryBuffer> &CompressedBuffer,
                            CompressionLevel Level) {
  return zlib::StatusUnsupported;
}
zlib::Status zlib::uncompress(StringRef InputBuffer,
                              OwningPtr<MemoryBuffer> &UncompressedBuffer,
                              size_t UncompressedSize) {
  return zlib::StatusUnsupported;
}
#endif

<commit_msg>Fixup for r180094: properly use MSan interface functions<commit_after>//===--- Compression.cpp - Compression implementation ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements compression functions.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Compression.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H
#include <zlib.h>
#endif

using namespace llvm;

#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ
static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) {
  switch (Level) {
    case zlib::NoCompression: return 0;
    case zlib::BestSpeedCompression: return 1;
    case zlib::DefaultCompression: return Z_DEFAULT_COMPRESSION;
    case zlib::BestSizeCompression: return 9;
  }
  llvm_unreachable("Invalid zlib::CompressionLevel!");
}

static zlib::Status encodeZlibReturnValue(int ReturnValue) {
  switch (ReturnValue) {
    case Z_OK: return zlib::StatusOK;
    case Z_MEM_ERROR: return zlib::StatusOutOfMemory;
    case Z_BUF_ERROR: return zlib::StatusBufferTooShort;
    case Z_STREAM_ERROR: return zlib::StatusInvalidArg;
    case Z_DATA_ERROR: return zlib::StatusInvalidData;
    default: llvm_unreachable("unknown zlib return status!");
  }
}

bool zlib::isAvailable() { return true; }
zlib::Status zlib::compress(StringRef InputBuffer,
                            OwningPtr<MemoryBuffer> &CompressedBuffer,
                            CompressionLevel Level) {
  unsigned long CompressedSize = ::compressBound(InputBuffer.size());
  OwningArrayPtr<char> TmpBuffer(new char[CompressedSize]);
  int CLevel = encodeZlibCompressionLevel(Level);
  Status Res = encodeZlibReturnValue(::compress2(
      (Bytef *)TmpBuffer.get(), &CompressedSize,
      (const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel));
  if (Res == StatusOK) {
    CompressedBuffer.reset(MemoryBuffer::getMemBufferCopy(
        StringRef(TmpBuffer.get(), CompressedSize)));
    // Tell MSan that memory initialized by zlib is valid.
    __msan_unpoison(CompressedBuffer->getBufferStart(), CompressedSize);
  }
  return Res;
}

zlib::Status zlib::uncompress(StringRef InputBuffer,
                              OwningPtr<MemoryBuffer> &UncompressedBuffer,
                              size_t UncompressedSize) {
  OwningArrayPtr<char> TmpBuffer(new char[UncompressedSize]);
  Status Res = encodeZlibReturnValue(
      ::uncompress((Bytef *)TmpBuffer.get(), (uLongf *)&UncompressedSize,
                   (const Bytef *)InputBuffer.data(), InputBuffer.size()));
  if (Res == StatusOK) {
    UncompressedBuffer.reset(MemoryBuffer::getMemBufferCopy(
        StringRef(TmpBuffer.get(), UncompressedSize)));
    // Tell MSan that memory initialized by zlib is valid.
    __msan_unpoison(UncompressedBuffer->getBufferStart(), UncompressedSize);
  }
  return Res;
}

#else
bool zlib::isAvailable() { return false; }
zlib::Status zlib::compress(StringRef InputBuffer,
                            OwningPtr<MemoryBuffer> &CompressedBuffer,
                            CompressionLevel Level) {
  return zlib::StatusUnsupported;
}
zlib::Status zlib::uncompress(StringRef InputBuffer,
                              OwningPtr<MemoryBuffer> &UncompressedBuffer,
                              size_t UncompressedSize) {
  return zlib::StatusUnsupported;
}
#endif

<|endoftext|>


<commit_before>/*
Copyright (c) 2015, Dimitri Diakopoulos 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 "VorbisDecoder.h"
#include "libvorbis/include/vorbis/vorbisfile.h"

using namespace nqr;

//@todo: implement decoding from memory (c.f. http://stackoverflow.com/questions/13437422/libvorbis-audio-decode-from-memory-in-c)
class VorbisDecoderInternal
{

public:

    VorbisDecoderInternal(AudioData * d, std::string filepath) : d(d)
    {
        fileHandle = new OggVorbis_File();

        /* @todo proper steaming support + classes
         const ov_callbacks callbacks =
         {
             .read_func = s_readCallback,
             .seek_func = s_seekCallback,
             .tell_func = s_tellCallback,
             .close_func = nullptr
         };
         */

        FILE * f = fopen(filepath.c_str(), "rb");

        if (!f)
            throw std::runtime_error("Can't open file");

        if (auto r = ov_test_callbacks(f, fileHandle, nullptr, 0, OV_CALLBACKS_DEFAULT) != 0)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("File is not a valid ogg vorbis file");
        }

        if (auto r = ov_test_open(fileHandle) != 0)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("ov_test_open failed");
        }

        // Don't need to fclose() after an open -- vorbis does this internally

        vorbis_info *ovInfo = ov_info(fileHandle, -1);

        if (ovInfo == nullptr)
        {
            throw std::runtime_error("Reading metadata failed");
        }

        if (auto r = ov_streams(fileHandle) != 1)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error( "Unsupported: file contains multiple bitstreams");
        }

        d->sampleRate = int(ovInfo->rate);
        d->channelCount = ovInfo->channels;
        d->sourceFormat = MakeFormatForBits(32, true, false);
        d->lengthSeconds = double(getLengthInSeconds());
        d->frameSize = ovInfo->channels * GetFormatBitsPerSample(d->sourceFormat);

        // Samples in a single channel
        auto totalSamples = size_t(getTotalSamples());

        d->samples.resize(totalSamples * d->channelCount);

        if (!readInternal(totalSamples))
            throw std::runtime_error("could not read any data");
    }

    ~VorbisDecoderInternal()
    {
        ov_clear(fileHandle);
    }

    size_t readInternal(size_t requestedFrameCount, size_t frameOffset = 0)
    {

        //@todo support offset

        float **buffer = nullptr;
        size_t framesRemaining = requestedFrameCount;
        size_t totalFramesRead = 0;
        int bitstream = 0;

        while(0 < framesRemaining)
        {
            int64_t framesRead = ov_read_float(fileHandle, &buffer, std::min(2048, (int) framesRemaining), &bitstream);

            // EOF
            if(!framesRead)
                break;

            if (framesRead < 0)
            {
                // Probably OV_HOLE, OV_EBADLINK, OV_EINVAL. Log warning here.
                continue;
            }

            for (int i = 0; i < framesRead; ++i)
            {
                for(int ch = 0; ch < d->channelCount; ch++)
                {
                    d->samples[totalFramesRead] = buffer[ch][i];
                    totalFramesRead++;
                }
            }

        }

        return totalFramesRead;
    }

    std::string errorAsString(int ovErrorCode)
    {
        switch(ovErrorCode)
        {
            case OV_FALSE: return "OV_FALSE";
            case OV_EOF: return "OV_EOF";
            case OV_HOLE: return "OV_HOLE";
            case OV_EREAD: return "OV_EREAD";
            case OV_EFAULT: return "OV_EFAULT";
            case OV_EIMPL: return "OV_EIMPL";
            case OV_EINVAL: return "OV_EINVAL";
            case OV_ENOTVORBIS: return "OV_ENOTVORBIS";
            case OV_EBADHEADER: return "OV_EBADHEADER";
            case OV_EVERSION: return "OV_EVERSION";
            case OV_ENOTAUDIO: return "OV_ENOTAUDIO";
            case OV_EBADPACKET: return "OV_EBADPACKET";
            case OV_EBADLINK: return "OV_EBADLINK";
            case OV_ENOSEEK: return "OV_ENOSEEK";
            default: return "OV_UNKNOWN_ERROR";
        }
    }

    //////////////////////
    // vorbis callbacks //
    //////////////////////

    //@todo: implement streaming support

private:

    NO_COPY(VorbisDecoderInternal);

    OggVorbis_File * fileHandle;
    AudioData * d;

    inline int64_t getTotalSamples() const { return int64_t(ov_pcm_total(const_cast<OggVorbis_File *>(fileHandle), -1)); }
    inline int64_t getLengthInSeconds() const { return int64_t(ov_time_total(const_cast<OggVorbis_File *>(fileHandle), -1)); }
    inline int64_t getCurrentSample() const { return int64_t(ov_pcm_tell(const_cast<OggVorbis_File *>(fileHandle))); }

};

//////////////////////
// Public Interface //
//////////////////////

void VorbisDecoder::LoadFromPath(AudioData * data, const std::string & path)
{
    VorbisDecoderInternal decoder(data, path);
}

void VorbisDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & memory)
{
    throw LoadBufferNotImplEx();
}

std::vector<std::string> VorbisDecoder::GetSupportedFileExtensions()
{
    return {"ogg"};
}
<commit_msg>Add vorbis decoder callbacks support<commit_after>/*
Copyright (c) 2015, Dimitri Diakopoulos 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 "VorbisDecoder.h"
#include "libvorbis/include/vorbis/vorbisfile.h"
#include <string.h>

using namespace nqr;

//@todo: implement decoding from memory (c.f. http://stackoverflow.com/questions/13437422/libvorbis-audio-decode-from-memory-in-c)
class VorbisDecoderInternal
{

public:

    VorbisDecoderInternal(AudioData * d, std::string filepath) : d(d)
    {
        fileHandle = new OggVorbis_File();

        /* @todo proper steaming support + classes
         const ov_callbacks callbacks =
         {
             .read_func = s_readCallback,
             .seek_func = s_seekCallback,
             .tell_func = s_tellCallback,
             .close_func = nullptr
         };
         */

        FILE * f = fopen(filepath.c_str(), "rb");

        if (!f)
            throw std::runtime_error("Can't open file");

        if (auto r = ov_test_callbacks(f, fileHandle, nullptr, 0, OV_CALLBACKS_DEFAULT) != 0)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("File is not a valid ogg vorbis file");
        }

        if (auto r = ov_test_open(fileHandle) != 0)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("ov_test_open failed");
        }

        // Don't need to fclose() after an open -- vorbis does this internally

        vorbis_info *ovInfo = ov_info(fileHandle, -1);

        if (ovInfo == nullptr)
        {
            throw std::runtime_error("Reading metadata failed");
        }

        if (auto r = ov_streams(fileHandle) != 1)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error( "Unsupported: file contains multiple bitstreams");
        }

        d->sampleRate = int(ovInfo->rate);
        d->channelCount = ovInfo->channels;
        d->sourceFormat = MakeFormatForBits(32, true, false);
        d->lengthSeconds = double(getLengthInSeconds());
        d->frameSize = ovInfo->channels * GetFormatBitsPerSample(d->sourceFormat);

        // Samples in a single channel
        auto totalSamples = size_t(getTotalSamples());

        d->samples.resize(totalSamples * d->channelCount);

        if (!readInternal(totalSamples))
            throw std::runtime_error("could not read any data");
    }

    VorbisDecoderInternal(AudioData * d, const std::vector<uint8_t> & memory) : d(d)
    {
        fileHandle = new OggVorbis_File();

        data = std::move(memory);
        ov_callbacks callbacks = {
          read_func,
          seek_func,
          close_func,
          tell_func,
        };
        if (auto r = ov_open_callbacks(this, fileHandle, nullptr, 0, callbacks) != 0) {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("Failed to open ogg vorbis file");
        }

        if (auto r = ov_test_callbacks(this, fileHandle, nullptr, 0, callbacks) != 0)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("File is not a valid ogg vorbis file");
        }

        if (auto r = ov_test_open(fileHandle) != 0)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error("ov_test_open failed");
        }

        // Don't need to fclose() after an open -- vorbis does this internally

        vorbis_info *ovInfo = ov_info(fileHandle, -1);

        if (ovInfo == nullptr)
        {
            throw std::runtime_error("Reading metadata failed");
        }

        if (auto r = ov_streams(fileHandle) != 1)
        {
            std::cerr << errorAsString(r) << std::endl;
            throw std::runtime_error( "Unsupported: file contains multiple bitstreams");
        }

        d->sampleRate = int(ovInfo->rate);
        d->channelCount = ovInfo->channels;
        d->sourceFormat = MakeFormatForBits(32, true, false);
        d->lengthSeconds = double(getLengthInSeconds());
        d->frameSize = ovInfo->channels * GetFormatBitsPerSample(d->sourceFormat);

        // Samples in a single channel
        auto totalSamples = size_t(getTotalSamples());

        d->samples.resize(totalSamples * d->channelCount);

        if (!readInternal(totalSamples))
            throw std::runtime_error("could not read any data");
    }

    ~VorbisDecoderInternal()
    {
        ov_clear(fileHandle);
    }

    size_t readInternal(size_t requestedFrameCount, size_t frameOffset = 0)
    {

        //@todo support offset

        float **buffer = nullptr;
        size_t framesRemaining = requestedFrameCount;
        size_t totalFramesRead = 0;
        int bitstream = 0;

        while(0 < framesRemaining)
        {
            int64_t framesRead = ov_read_float(fileHandle, &buffer, std::min(2048, (int) framesRemaining), &bitstream);

            // EOF
            if(!framesRead)
                break;

            if (framesRead < 0)
            {
                // Probably OV_HOLE, OV_EBADLINK, OV_EINVAL. Log warning here.
                continue;
            }

            for (int i = 0; i < framesRead; ++i)
            {
                for(int ch = 0; ch < d->channelCount; ch++)
                {
                    d->samples[totalFramesRead] = buffer[ch][i];
                    totalFramesRead++;
                }
            }

        }

        return totalFramesRead;
    }

    std::string errorAsString(int ovErrorCode)
    {
        switch(ovErrorCode)
        {
            case OV_FALSE: return "OV_FALSE";
            case OV_EOF: return "OV_EOF";
            case OV_HOLE: return "OV_HOLE";
            case OV_EREAD: return "OV_EREAD";
            case OV_EFAULT: return "OV_EFAULT";
            case OV_EIMPL: return "OV_EIMPL";
            case OV_EINVAL: return "OV_EINVAL";
            case OV_ENOTVORBIS: return "OV_ENOTVORBIS";
            case OV_EBADHEADER: return "OV_EBADHEADER";
            case OV_EVERSION: return "OV_EVERSION";
            case OV_ENOTAUDIO: return "OV_ENOTAUDIO";
            case OV_EBADPACKET: return "OV_EBADPACKET";
            case OV_EBADLINK: return "OV_EBADLINK";
            case OV_ENOSEEK: return "OV_ENOSEEK";
            default: return "OV_UNKNOWN_ERROR";
        }
    }

    //////////////////////
    // vorbis callbacks //
    //////////////////////

    static size_t read_func(void *ptr, size_t size, size_t nmemb, void *datasource) {
      VorbisDecoderInternal *decoder = (VorbisDecoderInternal *)datasource;
      size_t readLength = std::min<size_t>(size * nmemb, decoder->data.size() - decoder->dataPos);
      if (readLength > 0) {
        memcpy(ptr, decoder->data.data(), readLength);
        decoder->dataPos += readLength;
      }
      return readLength;
    }
    static int seek_func(void *datasource, ogg_int64_t offset, int whence) {
      VorbisDecoderInternal *decoder = (VorbisDecoderInternal *)datasource;
      decoder->dataPos = std::min<size_t>(offset, decoder->data.size());
      return 0;
    }
    static int close_func(void *datasource) {
      // nothing
    }
    static long tell_func(void *datasource) {
      VorbisDecoderInternal *decoder = (VorbisDecoderInternal *)datasource;
      return decoder->dataPos;
    }
    //@todo: implement streaming support

private:

    NO_COPY(VorbisDecoderInternal);

    OggVorbis_File * fileHandle;
    AudioData * d;
    std::vector<uint8_t> data;
    size_t dataPos;

    inline int64_t getTotalSamples() const { return int64_t(ov_pcm_total(const_cast<OggVorbis_File *>(fileHandle), -1)); }
    inline int64_t getLengthInSeconds() const { return int64_t(ov_time_total(const_cast<OggVorbis_File *>(fileHandle), -1)); }
    inline int64_t getCurrentSample() const { return int64_t(ov_pcm_tell(const_cast<OggVorbis_File *>(fileHandle))); }

};

//////////////////////
// Public Interface //
//////////////////////

void VorbisDecoder::LoadFromPath(AudioData * data, const std::string & path)
{
    VorbisDecoderInternal decoder(data, path);
}

void VorbisDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & memory)
{
    VorbisDecoderInternal decoder(data, memory);
}

std::vector<std::string> VorbisDecoder::GetSupportedFileExtensions()
{
    return {"ogg"};
}
<|endoftext|>


<commit_before>#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#else
#include <dirent.h>
#endif

#include <sys/stat.h>

#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#endif

#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif

#include <map>

#include "amuse/DirectoryEnumerator.hpp"

namespace amuse
{

DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool sizeSort, bool reverse, bool noHidden)
{
    Sstat theStat;
    if (Stat(path, &theStat) || !S_ISDIR(theStat.st_mode))
        return;

#if _WIN32
    SystemString wc(path);
    wc += _S("/*");
    WIN32_FIND_DATAW d;
    HANDLE dir = FindFirstFileW(wc.c_str(), &d);
    if (dir == INVALID_HANDLE_VALUE)
        return;
    switch (mode)
    {
    case Mode::Native:
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp += _S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir)));
        } while (FindNextFileW(dir, &d));
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp += _S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
        } while (FindNextFileW(dir, &d));

        if (reverse)
            for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        FindClose(dir);
        dir = FindFirstFileW(wc.c_str(), &d);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    FindClose(dir);

#else

    DIR* dir = opendir(path);
    if (!dir)
        return;
    const dirent* d;
    switch (mode)
    {
    case Mode::Native:
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(Entry(std::move(fp), d->d_name, sz, isDir));
        }
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, 0, true)));
        }

        if (reverse)
            for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        rewinddir(dir);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    closedir(dir);

#endif
}
}
<commit_msg>Add some reserve() calls<commit_after>#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#else
#include <dirent.h>
#endif

#include <sys/stat.h>

#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#endif

#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif

#include <map>

#include "amuse/DirectoryEnumerator.hpp"

namespace amuse
{

DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool sizeSort, bool reverse, bool noHidden)
{
    Sstat theStat;
    if (Stat(path, &theStat) || !S_ISDIR(theStat.st_mode))
        return;

#if _WIN32
    SystemString wc(path);
    wc += _S("/*");
    WIN32_FIND_DATAW d;
    HANDLE dir = FindFirstFileW(wc.c_str(), &d);
    if (dir == INVALID_HANDLE_VALUE)
        return;
    switch (mode)
    {
    case Mode::Native:
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp += _S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir)));
        } while (FindNextFileW(dir, &d));
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp += _S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
        } while (FindNextFileW(dir, &d));

        m_entries.reserve(sort.size());
        if (reverse)
            for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        FindClose(dir);
        dir = FindFirstFileW(wc.c_str(), &d);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    FindClose(dir);

#else

    DIR* dir = opendir(path);
    if (!dir)
        return;
    const dirent* d;
    switch (mode)
    {
    case Mode::Native:
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(Entry(std::move(fp), d->d_name, sz, isDir));
        }
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, 0, true)));
        }

        m_entries.reserve(sort.size());
        if (reverse)
            for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        rewinddir(dir);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it = sort.crbegin(); it != sort.crend(); ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    closedir(dir);

#endif
}
}
<|endoftext|>