<commit_before>#include "common.th"
#include "serial.th"

#define CHANNEL "#tenyr"
#define NICK    "rynet"

#define do(X) c <- rel(X) ; call(puts) ; c <- rel(rn) ; call(puts)

_start:
    prologue

#if 0
    c <- 2
    call(sleep)
#endif

    do(nick)
    do(user)
    do(join)

loop_line:
    call(getline)
    c <- b
    push(c)
    d <- 1
    call(skipwords)

    c <- b
    d <- rel(privmsg)
    e <- 7
    call(strncmp)
    pop(c)
    jnzrel(b,loop_line)
    d <- 3
    call(skipwords)

    c <- b + 1
    call(check_input)

    goto(loop_line)

    illegal

check_input:
    push(c)
    d <- rel(trigger)
    e <- 3 // strlen(trigger)
    call(strncmp)
    pop(c)
    jzrel(b,triggered)
    ret

triggered:
    push(c)
    c <- c + 3
    call(parse_int)
    c <- b
    call(say_int)
    pop(c)
    ret

    ret

parse_int:
    b <- -40
    ret

say_int:
    c <- rel(minus_forty)
    call(say)
    ret

minus_forty: .utf32 "-40C" ; .word 0

say:
    push(c)
    c <- rel(talk)
    call(puts)
    pop(c)
    call(puts)
    c <- rel(rn)
    call(puts)
    ret

skipwords:
skipwords_top:
    g <- [c]
    e <- g == 0
    jnzrel(e,skipwords_done)
    e <- g == ' '
    c <- c + 1
    jnzrel(e,skipwords_foundspace)
    goto(skipwords_top)

skipwords_foundspace:
    d <- d - 1
    e <- d < 1
    jzrel(e,skipwords_top)

skipwords_done:
    b <- c
    ret

//  :usermask PRIVMSG #channel :message
getline:
    g <- rel(buffer)
    f <- g

getline_top:
    getch(b)
    c <- b == '\r'
    d <- b == '\n'
    c <- c | d
    jnzrel(c,getline_eol)
    b -> [f]
    f <- f + 1
    goto(getline_top)

getline_eol:
    a -> [f]
    b <- g
    ret

sleep:
    c <- c * 2047
    c <- c * 2047
sleep_loop:
    c <- c - 1
    d <- c == 0
    jnzrel(d,sleep_done)
    goto(sleep_loop)
sleep_done:
    ret

// ----------------------------------------------------------------------------

buffer: // 512 chars
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"

nick: .utf32 "NICK " NICK ; .word 0
user: .utf32 "USER " NICK " 0 * :get your own bot" ; .word 0
join: .utf32 "JOIN " CHANNEL ; .word 0
talk: .utf32 "PRIVMSG " CHANNEL " :" ; .word 0

privmsg: .utf32 "PRIVMSG" ; .word 0
trigger: .utf32 "!f " ; .word 0

rn: .word '\r', '\n', 0

<commit_msg>Preliminary positive integer parsing<commit_after>#include "common.th"
#include "serial.th"

#define CHANNEL "#tenyr"
#define NICK    "rynet"

#define do(X) c <- rel(X) ; call(puts) ; c <- rel(rn) ; call(puts)

_start:
    prologue

#if 0
    c <- 2
    call(sleep)
#endif

    do(nick)
    do(user)
    do(join)

loop_line:
    call(getline)
    c <- b
    push(c)
    d <- 1
    call(skipwords)

    c <- b
    d <- rel(privmsg)
    e <- 7
    call(strncmp)
    pop(c)
    jnzrel(b,loop_line)
    d <- 3
    call(skipwords)

    c <- b + 1
    call(check_input)

    goto(loop_line)

    illegal

check_input:
    push(c)
    d <- rel(trigger)
    e <- 3 // strlen(trigger)
    call(strncmp)
    pop(c)
    jzrel(b,triggered)
    ret

triggered:
    push(c)
    c <- c + 3
    call(parse_int)
    c <- b * 2 // XXX
    call(say_int)
    pop(c)
    ret

    ret

// c <- address of first character of number
parse_int:
    b <- 0
parse_int_top:
    d <- [c]
    c <- c + 1
    d <- d - '0'
    e <- d > 9
    jnzrel(e,parse_int_done)
    e <- d < 0
    jnzrel(e,parse_int_done)
    b <- b * 10 + d
    goto(parse_int_top)
parse_int_done:
    ret

say_int:
    c <- rel(minus_forty)
    call(say)
    ret

minus_forty: .utf32 "-40C" ; .word 0

say:
    push(c)
    c <- rel(talk)
    call(puts)
    pop(c)
    call(puts)
    c <- rel(rn)
    call(puts)
    ret

skipwords:
skipwords_top:
    g <- [c]
    e <- g == 0
    jnzrel(e,skipwords_done)
    e <- g == ' '
    c <- c + 1
    jnzrel(e,skipwords_foundspace)
    goto(skipwords_top)

skipwords_foundspace:
    d <- d - 1
    e <- d < 1
    jzrel(e,skipwords_top)

skipwords_done:
    b <- c
    ret

//  :usermask PRIVMSG #channel :message
getline:
    g <- rel(buffer)
    f <- g

getline_top:
    getch(b)
    c <- b == '\r'
    d <- b == '\n'
    c <- c | d
    jnzrel(c,getline_eol)
    b -> [f]
    f <- f + 1
    goto(getline_top)

getline_eol:
    a -> [f]
    b <- g
    ret

sleep:
    c <- c * 2047
    c <- c * 2047
sleep_loop:
    c <- c - 1
    d <- c == 0
    jnzrel(d,sleep_done)
    goto(sleep_loop)
sleep_done:
    ret

// ----------------------------------------------------------------------------

buffer: // 512 chars
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"
    .utf32 "----------------------------------------------------------------"

nick: .utf32 "NICK " NICK ; .word 0
user: .utf32 "USER " NICK " 0 * :get your own bot" ; .word 0
join: .utf32 "JOIN " CHANNEL ; .word 0
talk: .utf32 "PRIVMSG " CHANNEL " :" ; .word 0

privmsg: .utf32 "PRIVMSG" ; .word 0
trigger: .utf32 "!f " ; .word 0

rn: .word '\r', '\n', 0

<|endoftext|>


<commit_before>/*
*
*   Title: CurlDump
*   Authors: Eyaz Rehman [http://github.com/Imposter]
*   Date: 2/18/2016
*
*   Copyright (C) 2016 Eyaz Rehman. All Rights Reserved.
*
*/

#include "Configuration/All.h"
#include "Utilities/Indigo/utility/hook.hpp"
#include "Utilities/Indigo/utility/acp_dump.hpp"
#include "Utilities/Indigo/utility/config.hpp"
#include "Curl.h"

#ifdef _DEBUG
#include "Utilities/Indigo/utility/console.hpp"
#endif

#include <fstream>
#include <cstdarg>
#include <map>
#include <mutex>
#include <thread>
#include <chrono>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>

#pragma comment(lib, "ws2_32.lib")

typedef size_t (*__cdecl CurlIOCallback)(char *data, size_t size, size_t bytes, void *userdata);

struct CurlInstance {
	void *Handle;
	void *WriteData;
	void *ReadData;
	CurlIOCallback WriteCallback;
	CurlIOCallback ReadCallback;
};

indigo::ACPDump acp_dump_;
std::map<void *, CurlInstance *> redirect_set_;
std::mutex redirect_mutex_;
indigo::CallHook curl_setopt_hook_;
indigo::CallHook curl_close_hook_;

size_t curl_write_callback(char *data, size_t size, size_t bytes, CurlInstance *instance) {
	// actual size == size * bytes
	printf("CurlDump: (0x%08p) Writing %d bytes\n", instance->Handle, size * bytes);
	acp_dump_.Write(SOCK_STREAM, IPPROTO_TCP, static_cast<uint32_t>(inet_addr("127.0.0.1")),
		reinterpret_cast<uint16_t>(instance->Handle), reinterpret_cast<uint32_t>(instance->Handle), 1337, data, size * bytes);

	return instance->WriteCallback != nullptr ? instance->WriteCallback(data, size, bytes, instance->WriteData) : 0;
}

size_t curl_read_callback(char *data, size_t size, size_t bytes, CurlInstance *instance) {
	// actual size == size * bytes
	printf("CurlDump: (0x%08p) Reading %d bytes\n", instance->Handle, size * bytes);
	acp_dump_.Write(SOCK_STREAM, IPPROTO_TCP, reinterpret_cast<uint32_t>(instance->Handle), 1337,
		static_cast<uint32_t>(inet_addr("127.0.0.1")), reinterpret_cast<uint16_t>(instance->Handle), data, size * bytes);

	return instance->ReadCallback != nullptr ? instance->ReadCallback(data, size, bytes, instance->ReadData) : 0;
}

// int __cdecl Curl_setopt(void *handle, signed int option, va_list param)
int __cdecl curl_setopt_(void *handle, signed int option, va_list param) {
	printf("CurlDump: Curl_setopt(0x%08p, %d, 0x%08p)\n", handle, option, param);

	// Curl instance
	CurlInstance *instance;

	// Get the original
	auto curl_setopt = curl_setopt_hook_.Get<int(*__cdecl)(void *, signed int, va_list)>();

	redirect_mutex_.lock();
	if (redirect_set_.find(handle) == redirect_set_.end()) {
		// Initialize
		printf("CurlDump: Monitoring easy handle 0x%08p\n", handle);

		// Create curl instance
		instance = new CurlInstance{ nullptr };
		instance->Handle = handle;

		if (option == CURLOPT_WRITEDATA) {
			instance->WriteData = va_arg(param, void *);
		} else if (option == CURLOPT_READDATA) {
			instance->ReadData = va_arg(param, void *);
		} else if (option == CURLOPT_WRITEFUNCTION) {
			instance->WriteCallback = va_arg(param, CurlIOCallback);
		} else if (option == CURLOPT_READFUNCTION) {
			instance->ReadCallback = va_arg(param, CurlIOCallback);
		}

		auto setopt = [=](CURLoption opt, ...) {
			printf("CurlDump: Setting option %d for easy handle 0x%08p\n", opt, handle);

			va_list va;
			va_start(va, opt);

			curl_setopt(handle, opt, va);

			va_end(va);
		};

		setopt(CURLOPT_VERBOSE, 1);
		setopt(CURLOPT_WRITEDATA, instance);
		setopt(CURLOPT_READDATA, instance);
		setopt(CURLOPT_WRITEFUNCTION, &curl_write_callback);
		setopt(CURLOPT_READFUNCTION, &curl_read_callback);

		redirect_set_[handle] = instance;
	}

	redirect_mutex_.unlock();

	instance = redirect_set_[handle];
	if (option == CURLOPT_WRITEDATA) {
		instance->WriteData = va_arg(param, void *);
		return 0;
	}
	if (option == CURLOPT_READDATA) {
		instance->ReadData = va_arg(param, void *);
		return 0;
	}
	if (option == CURLOPT_WRITEFUNCTION) {
		instance->WriteCallback = va_arg(param, CurlIOCallback);
		return 0;
	}
	if (option == CURLOPT_READFUNCTION) {
		instance->ReadCallback = va_arg(param, CurlIOCallback);
		return 0;
	}

	return curl_setopt(handle, option, param);
}

// int __cdecl Curl_close(void *handle)
int __cdecl curl_close_(void *handle) {
	redirect_mutex_.lock();
	for (auto it = redirect_set_.begin(); it != redirect_set_.end();) {
		if (it->first == handle) {
			delete it->second;
			it = redirect_set_.erase(it);
		} else {
			++it;
		}
	}
	redirect_mutex_.unlock();

	return curl_close_hook_.Get<int(*__cdecl)(void *)>()(handle);
}

extern "C" {
	EXPORT_ATTR void __cdecl onExtensionUnloading(void) {
		// Remove curl instances
		redirect_mutex_.lock();
		for (auto it = redirect_set_.begin(); it != redirect_set_.end();) {
			delete it->second;
			it = redirect_set_.erase(it);
		}
		redirect_mutex_.unlock();

		// Close dump
		acp_dump_.Close();

#ifdef _DEBUG
		indigo::Console::Hide();
#endif
	}

	EXPORT_ATTR void __cdecl onInitializationStart(void) {
#ifdef _DEBUG
		indigo::Console::Show("Ayria Console");

		MessageBoxA(nullptr, "Attach debugger now!", "CurlDump - Debug", MB_OK);
#endif

		// Open the config file
		std::ifstream config_file;
		config_file.open("curldump.ini");
		if (!config_file.is_open()) {
			printf("CurlDump: Failed to open curldump.ini\n");
			return;
		}

		config_file.seekg(0, std::ios::end);
		size_t config_size = config_file.tellg();
		config_file.seekg(0, std::ios::beg);

		std::string config_buffer;
		config_buffer.resize(config_size);
		config_file.read(const_cast<char *>(config_buffer.c_str()), config_size);

		indigo::Config config;
		if (!config.Open(config_buffer)) {
			printf("CurlDump: Failed to read curldump.ini\n");
			return;
		}

		// Get addresses for Curl_setopt and Curl_close
		std::string setopt = config.GetString("CURL", "SetOpt");
		std::string close = config.GetString("CURL", "Close");
		int32_t delay = config.GetInteger("CURL", "HookDelay", 1);

		if (setopt.empty()) {
			printf("CurlDump: Invalid Curl_setopt pattern\n");
			return;
		}

		if (close.empty()) {
			printf("CurlDump: Invalid Curl_close pattern\n");
			return;
		}

		// Install hooks
		std::thread([=]() {
			std::this_thread::sleep_for(std::chrono::milliseconds(delay));

			while (true) {
				std::this_thread::sleep_for(std::chrono::milliseconds(10));

				if (!curl_setopt_hook_.Install(indigo::Memory::Find(setopt.c_str()).Get(0).Get<void *>(), &curl_setopt_)) {
					printf("CurlDump: Failed to install Curl_setopt hook\n");
					continue;
				}

				if (!curl_close_hook_.Install(indigo::Memory::Find(close.c_str()).Get(0).Get<void *>(), &curl_close_)) {
					printf("CurlDump: Failed to install Curl_close hook\n");
					continue;
				}

				// Open dump
				std::string file_name = indigo::String::Format("curldump_%i.acp", time(nullptr));
				if (!acp_dump_.Open(file_name)) {
					printf("CurlDump: Failed to open %s\n", file_name.c_str());
					return;
				}

				break;
			}

			printf("CurlDump: We're ready to go!\n");
		}).detach();
	}

	EXPORT_ATTR void __cdecl onInitializationComplete(void) {
	}

	EXPORT_ATTR void __cdecl onMessage(uint32_t message, ...) {
		va_list variadic;
		va_start(variadic, message);

		// Messages are a 32bit FNV1a hash of a string
		switch (message)
		{

		case FNV1a_Compiletime_32("DefaultCase"):
		default:
			break;
		}

		va_end(variadic);
	}
}

BOOLEAN WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
	if (reason == DLL_PROCESS_ATTACH) {
		DisableThreadLibraryCalls(instance);
		DeleteLogfile();
	}

	return TRUE;
}<commit_msg>Removed unnecessary code.<commit_after>/*
*
*   Title: CurlDump
*   Authors: Eyaz Rehman [http://github.com/Imposter]
*   Date: 2/18/2016
*
*   Copyright (C) 2016 Eyaz Rehman. All Rights Reserved.
*
*/

#include "Configuration/All.h"
#include "Utilities/Indigo/utility/hook.hpp"
#include "Utilities/Indigo/utility/acp_dump.hpp"
#include "Utilities/Indigo/utility/config.hpp"
#include "Curl.h"

#ifdef _DEBUG
#include "Utilities/Indigo/utility/console.hpp"
#endif

#include <fstream>
#include <cstdarg>
#include <map>
#include <mutex>
#include <thread>
#include <chrono>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>

#pragma comment(lib, "ws2_32.lib")

typedef size_t (*__cdecl CurlIOCallback)(char *data, size_t size, size_t bytes, void *userdata);

struct CurlInstance {
	void *Handle;
	void *WriteData;
	void *ReadData;
	CurlIOCallback WriteCallback;
	CurlIOCallback ReadCallback;
};

indigo::ACPDump acp_dump_;
std::map<void *, CurlInstance *> redirect_set_;
std::mutex redirect_mutex_;
indigo::CallHook curl_setopt_hook_;
indigo::CallHook curl_close_hook_;

size_t curl_write_callback(char *data, size_t size, size_t bytes, CurlInstance *instance) {
	// actual size == size * bytes
	printf("CurlDump: (0x%08p) Writing %d bytes\n", instance->Handle, size * bytes);
	acp_dump_.Write(SOCK_STREAM, IPPROTO_TCP, static_cast<uint32_t>(inet_addr("127.0.0.1")),
		reinterpret_cast<uint16_t>(instance->Handle), reinterpret_cast<uint32_t>(instance->Handle), 1337, data, size * bytes);

	return instance->WriteCallback != nullptr ? instance->WriteCallback(data, size, bytes, instance->WriteData) : 0;
}

size_t curl_read_callback(char *data, size_t size, size_t bytes, CurlInstance *instance) {
	// actual size == size * bytes
	printf("CurlDump: (0x%08p) Reading %d bytes\n", instance->Handle, size * bytes);
	acp_dump_.Write(SOCK_STREAM, IPPROTO_TCP, reinterpret_cast<uint32_t>(instance->Handle), 1337,
		static_cast<uint32_t>(inet_addr("127.0.0.1")), reinterpret_cast<uint16_t>(instance->Handle), data, size * bytes);

	return instance->ReadCallback != nullptr ? instance->ReadCallback(data, size, bytes, instance->ReadData) : 0;
}

// int __cdecl Curl_setopt(void *handle, signed int option, va_list param)
int __cdecl curl_setopt_(void *handle, signed int option, va_list param) {
	printf("CurlDump: Curl_setopt(0x%08p, %d, 0x%08p)\n", handle, option, param);

	// Curl instance
	CurlInstance *instance;

	// Get the original
	auto curl_setopt = curl_setopt_hook_.Get<int(*__cdecl)(void *, signed int, va_list)>();

	redirect_mutex_.lock();
	if (redirect_set_.find(handle) == redirect_set_.end()) {
		// Initialize
		printf("CurlDump: Monitoring easy handle 0x%08p\n", handle);

		// Create curl instance
		instance = new CurlInstance{ nullptr };
		instance->Handle = handle;

		if (option == CURLOPT_WRITEDATA) {
			instance->WriteData = va_arg(param, void *);
		} else if (option == CURLOPT_READDATA) {
			instance->ReadData = va_arg(param, void *);
		} else if (option == CURLOPT_WRITEFUNCTION) {
			instance->WriteCallback = va_arg(param, CurlIOCallback);
		} else if (option == CURLOPT_READFUNCTION) {
			instance->ReadCallback = va_arg(param, CurlIOCallback);
		}

		auto setopt = [=](CURLoption opt, ...) {
			printf("CurlDump: Setting option %d for easy handle 0x%08p\n", opt, handle);

			va_list va;
			va_start(va, opt);

			curl_setopt(handle, opt, va);

			va_end(va);
		};

#ifdef _DEBUG
		setopt(CURLOPT_VERBOSE, 1);
#endif
		setopt(CURLOPT_WRITEDATA, instance);
		setopt(CURLOPT_READDATA, instance);
		setopt(CURLOPT_WRITEFUNCTION, &curl_write_callback);
		setopt(CURLOPT_READFUNCTION, &curl_read_callback);

		redirect_set_[handle] = instance;
	}

	instance = redirect_set_[handle];
	redirect_mutex_.unlock();
	if (option == CURLOPT_WRITEDATA) {
		instance->WriteData = va_arg(param, void *);
		return 0;
	}
	if (option == CURLOPT_READDATA) {
		instance->ReadData = va_arg(param, void *);
		return 0;
	}
	if (option == CURLOPT_WRITEFUNCTION) {
		instance->WriteCallback = va_arg(param, CurlIOCallback);
		return 0;
	}
	if (option == CURLOPT_READFUNCTION) {
		instance->ReadCallback = va_arg(param, CurlIOCallback);
		return 0;
	}

	return curl_setopt(handle, option, param);
}

// int __cdecl Curl_close(void *handle)
int __cdecl curl_close_(void *handle) {
	redirect_mutex_.lock();
	for (auto it = redirect_set_.begin(); it != redirect_set_.end();) {
		if (it->first == handle) {
			delete it->second;
			it = redirect_set_.erase(it);
			break;
		}
		++it;
	}
	redirect_mutex_.unlock();

	return curl_close_hook_.Get<int(*__cdecl)(void *)>()(handle);
}

extern "C" {
	EXPORT_ATTR void __cdecl onExtensionUnloading(void) {
		// Remove curl instances
		redirect_mutex_.lock();
		for (auto it = redirect_set_.begin(); it != redirect_set_.end();) {
			delete it->second;
			it = redirect_set_.erase(it);
		}
		redirect_mutex_.unlock();

		// Close dump
		acp_dump_.Close();

#ifdef _DEBUG
		indigo::Console::Hide();
#endif
	}

	EXPORT_ATTR void __cdecl onInitializationStart(void) {
#ifdef _DEBUG
		indigo::Console::Show("Ayria Console");

		MessageBoxA(nullptr, "Attach debugger now!", "CurlDump - Debug", MB_OK);
#endif

		// Open the config file
		std::ifstream config_file;
		config_file.open("curldump.ini");
		if (!config_file.is_open()) {
			printf("CurlDump: Failed to open curldump.ini\n");
			return;
		}

		config_file.seekg(0, std::ios::end);
		size_t config_size = config_file.tellg();
		config_file.seekg(0, std::ios::beg);

		std::string config_buffer;
		config_buffer.resize(config_size);
		config_file.read(const_cast<char *>(config_buffer.c_str()), config_size);

		indigo::Config config;
		if (!config.Open(config_buffer)) {
			printf("CurlDump: Failed to read curldump.ini\n");
			return;
		}

		// Get addresses for Curl_setopt and Curl_close
		std::string setopt = config.GetString("CURL", "SetOpt");
		std::string close = config.GetString("CURL", "Close");
		int32_t delay = config.GetInteger("CURL", "HookDelay", 1);

		if (setopt.empty()) {
			printf("CurlDump: Invalid Curl_setopt pattern\n");
			return;
		}

		if (close.empty()) {
			printf("CurlDump: Invalid Curl_close pattern\n");
			return;
		}

		// Install hooks
		std::thread([=]() {
			std::this_thread::sleep_for(std::chrono::milliseconds(delay));

			while (true) {
				std::this_thread::sleep_for(std::chrono::milliseconds(10));

				if (!curl_setopt_hook_.Install(indigo::Memory::Find(setopt.c_str()).Get(0).Get<void *>(), &curl_setopt_)) {
					printf("CurlDump: Failed to install Curl_setopt hook\n");
					continue;
				}

				if (!curl_close_hook_.Install(indigo::Memory::Find(close.c_str()).Get(0).Get<void *>(), &curl_close_)) {
					printf("CurlDump: Failed to install Curl_close hook\n");
					continue;
				}

				// Open dump
				std::string file_name = indigo::String::Format("curldump_%i.acp", time(nullptr));
				if (!acp_dump_.Open(file_name)) {
					printf("CurlDump: Failed to open %s\n", file_name.c_str());
					return;
				}

				break;
			}

			printf("CurlDump: We're ready to go!\n");
		}).detach();
	}

	EXPORT_ATTR void __cdecl onInitializationComplete(void) {
	}

	EXPORT_ATTR void __cdecl onMessage(uint32_t message, ...) {
	}
}

BOOLEAN WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
	if (reason == DLL_PROCESS_ATTACH) {
		DisableThreadLibraryCalls(instance);
		DeleteLogfile();
	}

	return TRUE;
}<|endoftext|>


<commit_before>// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h"

#include <string>

#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"

namespace quic {

typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;

// Max number of connections this store can keep track.
static const size_t kDefaultMaxConnectionsInStore = 100;
// Up to half of the capacity can be used for storing non-CHLO packets.
static const size_t kMaxConnectionsWithoutCHLO =
    kDefaultMaxConnectionsInStore / 2;

namespace {

// This alarm removes expired entries in map each time this alarm fires.
class ConnectionExpireAlarm : public QuicAlarm::Delegate {
 public:
  explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store)
      : connection_store_(store) {}

  void OnAlarm() override { connection_store_->OnExpirationTimeout(); }

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

 private:
  QuicBufferedPacketStore* connection_store_;
};

}  // namespace

BufferedPacket::BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
                               QuicSocketAddress self_address,
                               QuicSocketAddress peer_address)
    : packet(std::move(packet)),
      self_address(self_address),
      peer_address(peer_address) {}

BufferedPacket::BufferedPacket(BufferedPacket&& other) = default;

BufferedPacket& BufferedPacket::operator=(BufferedPacket&& other) = default;

BufferedPacket::~BufferedPacket() {}

BufferedPacketList::BufferedPacketList()
    : creation_time(QuicTime::Zero()),
      ietf_quic(false),
      version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED) {}

BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default;

BufferedPacketList& BufferedPacketList::operator=(BufferedPacketList&& other) =
    default;

BufferedPacketList::~BufferedPacketList() {}

QuicBufferedPacketStore::QuicBufferedPacketStore(
    VisitorInterface* visitor,
    const QuicClock* clock,
    QuicAlarmFactory* alarm_factory)
    : connection_life_span_(
          QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)),
      visitor_(visitor),
      clock_(clock),
      expiration_alarm_(
          alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {}

QuicBufferedPacketStore::~QuicBufferedPacketStore() {}

EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
    QuicConnectionId connection_id,
    bool ietf_quic,
    const QuicReceivedPacket& packet,
    QuicSocketAddress self_address,
    QuicSocketAddress peer_address,
    bool is_chlo,
    const std::string& alpn,
    const ParsedQuicVersion& version) {
  QUIC_BUG_IF(!FLAGS_quic_allow_chlo_buffering)
      << "Shouldn't buffer packets if disabled via flag.";
  QUIC_BUG_IF(is_chlo && QuicContainsKey(connections_with_chlo_, connection_id))
      << "Shouldn't buffer duplicated CHLO on connection " << connection_id;
  QUIC_BUG_IF(!is_chlo && !alpn.empty())
      << "Shouldn't have an ALPN defined for a non-CHLO packet.";
  QUIC_BUG_IF(is_chlo && version.transport_version == QUIC_VERSION_UNSUPPORTED)
      << "Should have version for CHLO packet.";

  if (!QuicContainsKey(undecryptable_packets_, connection_id) &&
      ShouldBufferPacket(is_chlo)) {
    // Drop the packet if the upper limit of undecryptable packets has been
    // reached or the whole capacity of the store has been reached.
    return TOO_MANY_CONNECTIONS;
  } else if (!QuicContainsKey(undecryptable_packets_, connection_id)) {
    undecryptable_packets_.emplace(
        std::make_pair(connection_id, BufferedPacketList()));
    undecryptable_packets_.back().second.ietf_quic = ietf_quic;
    undecryptable_packets_.back().second.version = version;
  }
  CHECK(QuicContainsKey(undecryptable_packets_, connection_id));
  BufferedPacketList& queue =
      undecryptable_packets_.find(connection_id)->second;

  if (!is_chlo) {
    // If current packet is not CHLO, it might not be buffered because store
    // only buffers certain number of undecryptable packets per connection.
    size_t num_non_chlo_packets =
        QuicContainsKey(connections_with_chlo_, connection_id)
            ? (queue.buffered_packets.size() - 1)
            : queue.buffered_packets.size();
    if (num_non_chlo_packets >= kDefaultMaxUndecryptablePackets) {
      // If there are kMaxBufferedPacketsPerConnection packets buffered up for
      // this connection, drop the current packet.
      return TOO_MANY_PACKETS;
    }
  }

  if (queue.buffered_packets.empty()) {
    // If this is the first packet arrived on a new connection, initialize the
    // creation time.
    queue.creation_time = clock_->ApproximateNow();
  }

  BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()),
                           self_address, peer_address);
  if (is_chlo) {
    // Add CHLO to the beginning of buffered packets so that it can be delivered
    // first later.
    queue.buffered_packets.push_front(std::move(new_entry));
    queue.alpn = alpn;
    connections_with_chlo_[connection_id] = false;  // Dummy value.
    // Set the version of buffered packets of this connection on CHLO.
    queue.version = version;
  } else {
    // Buffer non-CHLO packets in arrival order.
    queue.buffered_packets.push_back(std::move(new_entry));
  }
  MaybeSetExpirationAlarm();
  return SUCCESS;
}

bool QuicBufferedPacketStore::HasBufferedPackets(
    QuicConnectionId connection_id) const {
  return QuicContainsKey(undecryptable_packets_, connection_id);
}

bool QuicBufferedPacketStore::HasChlosBuffered() const {
  return !connections_with_chlo_.empty();
}

BufferedPacketList QuicBufferedPacketStore::DeliverPackets(
    QuicConnectionId connection_id) {
  BufferedPacketList packets_to_deliver;
  auto it = undecryptable_packets_.find(connection_id);
  if (it != undecryptable_packets_.end()) {
    packets_to_deliver = std::move(it->second);
    undecryptable_packets_.erase(connection_id);
  }
  return packets_to_deliver;
}

void QuicBufferedPacketStore::DiscardPackets(QuicConnectionId connection_id) {
  undecryptable_packets_.erase(connection_id);
  connections_with_chlo_.erase(connection_id);
}

void QuicBufferedPacketStore::OnExpirationTimeout() {
  QuicTime expiration_time = clock_->ApproximateNow() - connection_life_span_;
  while (!undecryptable_packets_.empty()) {
    auto& entry = undecryptable_packets_.front();
    if (entry.second.creation_time > expiration_time) {
      break;
    }
    QuicConnectionId connection_id = entry.first;
    visitor_->OnExpiredPackets(connection_id, std::move(entry.second));
    undecryptable_packets_.pop_front();
    connections_with_chlo_.erase(connection_id);
  }
  if (!undecryptable_packets_.empty()) {
    MaybeSetExpirationAlarm();
  }
}

void QuicBufferedPacketStore::MaybeSetExpirationAlarm() {
  if (!expiration_alarm_->IsSet()) {
    expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_);
  }
}

bool QuicBufferedPacketStore::ShouldBufferPacket(bool is_chlo) {
  bool is_store_full =
      undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore;

  if (is_chlo) {
    return is_store_full;
  }

  size_t num_connections_without_chlo =
      undecryptable_packets_.size() - connections_with_chlo_.size();
  bool reach_non_chlo_limit =
      num_connections_without_chlo >= kMaxConnectionsWithoutCHLO;

  return is_store_full || reach_non_chlo_limit;
}

BufferedPacketList QuicBufferedPacketStore::DeliverPacketsForNextConnection(
    QuicConnectionId* connection_id) {
  if (connections_with_chlo_.empty()) {
    // Returns empty list if no CHLO has been buffered.
    return BufferedPacketList();
  }
  *connection_id = connections_with_chlo_.front().first;
  connections_with_chlo_.pop_front();

  BufferedPacketList packets = DeliverPackets(*connection_id);
  DCHECK(!packets.buffered_packets.empty())
      << "Try to deliver connectons without CHLO";
  return packets;
}

bool QuicBufferedPacketStore::HasChloForConnection(
    QuicConnectionId connection_id) {
  return QuicContainsKey(connections_with_chlo_, connection_id);
}

}  // namespace quic
<commit_msg>gfe-relnote: n/a(clean up) Switch existing directly access of FLAGS to use GetQuicFlag.<commit_after>// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h"

#include <string>

#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"

namespace quic {

typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;

// Max number of connections this store can keep track.
static const size_t kDefaultMaxConnectionsInStore = 100;
// Up to half of the capacity can be used for storing non-CHLO packets.
static const size_t kMaxConnectionsWithoutCHLO =
    kDefaultMaxConnectionsInStore / 2;

namespace {

// This alarm removes expired entries in map each time this alarm fires.
class ConnectionExpireAlarm : public QuicAlarm::Delegate {
 public:
  explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store)
      : connection_store_(store) {}

  void OnAlarm() override { connection_store_->OnExpirationTimeout(); }

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

 private:
  QuicBufferedPacketStore* connection_store_;
};

}  // namespace

BufferedPacket::BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
                               QuicSocketAddress self_address,
                               QuicSocketAddress peer_address)
    : packet(std::move(packet)),
      self_address(self_address),
      peer_address(peer_address) {}

BufferedPacket::BufferedPacket(BufferedPacket&& other) = default;

BufferedPacket& BufferedPacket::operator=(BufferedPacket&& other) = default;

BufferedPacket::~BufferedPacket() {}

BufferedPacketList::BufferedPacketList()
    : creation_time(QuicTime::Zero()),
      ietf_quic(false),
      version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED) {}

BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default;

BufferedPacketList& BufferedPacketList::operator=(BufferedPacketList&& other) =
    default;

BufferedPacketList::~BufferedPacketList() {}

QuicBufferedPacketStore::QuicBufferedPacketStore(
    VisitorInterface* visitor,
    const QuicClock* clock,
    QuicAlarmFactory* alarm_factory)
    : connection_life_span_(
          QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)),
      visitor_(visitor),
      clock_(clock),
      expiration_alarm_(
          alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {}

QuicBufferedPacketStore::~QuicBufferedPacketStore() {}

EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
    QuicConnectionId connection_id,
    bool ietf_quic,
    const QuicReceivedPacket& packet,
    QuicSocketAddress self_address,
    QuicSocketAddress peer_address,
    bool is_chlo,
    const std::string& alpn,
    const ParsedQuicVersion& version) {
  QUIC_BUG_IF(!GetQuicFlag(FLAGS_quic_allow_chlo_buffering))
      << "Shouldn't buffer packets if disabled via flag.";
  QUIC_BUG_IF(is_chlo && QuicContainsKey(connections_with_chlo_, connection_id))
      << "Shouldn't buffer duplicated CHLO on connection " << connection_id;
  QUIC_BUG_IF(!is_chlo && !alpn.empty())
      << "Shouldn't have an ALPN defined for a non-CHLO packet.";
  QUIC_BUG_IF(is_chlo && version.transport_version == QUIC_VERSION_UNSUPPORTED)
      << "Should have version for CHLO packet.";

  if (!QuicContainsKey(undecryptable_packets_, connection_id) &&
      ShouldBufferPacket(is_chlo)) {
    // Drop the packet if the upper limit of undecryptable packets has been
    // reached or the whole capacity of the store has been reached.
    return TOO_MANY_CONNECTIONS;
  } else if (!QuicContainsKey(undecryptable_packets_, connection_id)) {
    undecryptable_packets_.emplace(
        std::make_pair(connection_id, BufferedPacketList()));
    undecryptable_packets_.back().second.ietf_quic = ietf_quic;
    undecryptable_packets_.back().second.version = version;
  }
  CHECK(QuicContainsKey(undecryptable_packets_, connection_id));
  BufferedPacketList& queue =
      undecryptable_packets_.find(connection_id)->second;

  if (!is_chlo) {
    // If current packet is not CHLO, it might not be buffered because store
    // only buffers certain number of undecryptable packets per connection.
    size_t num_non_chlo_packets =
        QuicContainsKey(connections_with_chlo_, connection_id)
            ? (queue.buffered_packets.size() - 1)
            : queue.buffered_packets.size();
    if (num_non_chlo_packets >= kDefaultMaxUndecryptablePackets) {
      // If there are kMaxBufferedPacketsPerConnection packets buffered up for
      // this connection, drop the current packet.
      return TOO_MANY_PACKETS;
    }
  }

  if (queue.buffered_packets.empty()) {
    // If this is the first packet arrived on a new connection, initialize the
    // creation time.
    queue.creation_time = clock_->ApproximateNow();
  }

  BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()),
                           self_address, peer_address);
  if (is_chlo) {
    // Add CHLO to the beginning of buffered packets so that it can be delivered
    // first later.
    queue.buffered_packets.push_front(std::move(new_entry));
    queue.alpn = alpn;
    connections_with_chlo_[connection_id] = false;  // Dummy value.
    // Set the version of buffered packets of this connection on CHLO.
    queue.version = version;
  } else {
    // Buffer non-CHLO packets in arrival order.
    queue.buffered_packets.push_back(std::move(new_entry));
  }
  MaybeSetExpirationAlarm();
  return SUCCESS;
}

bool QuicBufferedPacketStore::HasBufferedPackets(
    QuicConnectionId connection_id) const {
  return QuicContainsKey(undecryptable_packets_, connection_id);
}

bool QuicBufferedPacketStore::HasChlosBuffered() const {
  return !connections_with_chlo_.empty();
}

BufferedPacketList QuicBufferedPacketStore::DeliverPackets(
    QuicConnectionId connection_id) {
  BufferedPacketList packets_to_deliver;
  auto it = undecryptable_packets_.find(connection_id);
  if (it != undecryptable_packets_.end()) {
    packets_to_deliver = std::move(it->second);
    undecryptable_packets_.erase(connection_id);
  }
  return packets_to_deliver;
}

void QuicBufferedPacketStore::DiscardPackets(QuicConnectionId connection_id) {
  undecryptable_packets_.erase(connection_id);
  connections_with_chlo_.erase(connection_id);
}

void QuicBufferedPacketStore::OnExpirationTimeout() {
  QuicTime expiration_time = clock_->ApproximateNow() - connection_life_span_;
  while (!undecryptable_packets_.empty()) {
    auto& entry = undecryptable_packets_.front();
    if (entry.second.creation_time > expiration_time) {
      break;
    }
    QuicConnectionId connection_id = entry.first;
    visitor_->OnExpiredPackets(connection_id, std::move(entry.second));
    undecryptable_packets_.pop_front();
    connections_with_chlo_.erase(connection_id);
  }
  if (!undecryptable_packets_.empty()) {
    MaybeSetExpirationAlarm();
  }
}

void QuicBufferedPacketStore::MaybeSetExpirationAlarm() {
  if (!expiration_alarm_->IsSet()) {
    expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_);
  }
}

bool QuicBufferedPacketStore::ShouldBufferPacket(bool is_chlo) {
  bool is_store_full =
      undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore;

  if (is_chlo) {
    return is_store_full;
  }

  size_t num_connections_without_chlo =
      undecryptable_packets_.size() - connections_with_chlo_.size();
  bool reach_non_chlo_limit =
      num_connections_without_chlo >= kMaxConnectionsWithoutCHLO;

  return is_store_full || reach_non_chlo_limit;
}

BufferedPacketList QuicBufferedPacketStore::DeliverPacketsForNextConnection(
    QuicConnectionId* connection_id) {
  if (connections_with_chlo_.empty()) {
    // Returns empty list if no CHLO has been buffered.
    return BufferedPacketList();
  }
  *connection_id = connections_with_chlo_.front().first;
  connections_with_chlo_.pop_front();

  BufferedPacketList packets = DeliverPackets(*connection_id);
  DCHECK(!packets.buffered_packets.empty())
      << "Try to deliver connectons without CHLO";
  return packets;
}

bool QuicBufferedPacketStore::HasChloForConnection(
    QuicConnectionId connection_id) {
  return QuicContainsKey(connections_with_chlo_, connection_id);
}

}  // namespace quic
<|endoftext|>


<commit_before>#include "jsonfile.hpp"
#include "xmlfile.hpp"
#include "world.hpp"

using namespace Headway;

World::World(QObject* parent) : QObject(parent)
{
    createWorld();
}

World::World(const World& other) : QObject(other.parent()), generations_(other.generations()), count_(other.count()), matrix(new Matrix<bool>(*(other.matrix)))
{
}

World::~World() noexcept
{
    delete matrix;
}

bool World::createWorld(quint32 width, quint32 height, quint64 generations) noexcept
{
    if (width == 0)
    {
        emit error("Width must not be zero.");
        return false;
    }

    if (height == 0)
    {
        emit error("Height must not be zero.");
        return false;
    }

    if (matrix != nullptr)
        delete matrix;

    matrix = new Matrix<bool>(width, height);
    matrix->fill(false);

    generations_ = generations; emit generationsChanged(generations);
    count_ = 0; emit countChanged(0);

    return true;
}

bool World::loadFile(const QUrl& fileUrl) noexcept
{
    QSharedPointer<File> file;
    const QString filePath = fileUrl.toLocalFile();

    try
    {
        if (filePath.endsWith(QStringLiteral(".xml"), Qt::CaseInsensitive))
        {
            file = QSharedPointer<File>(new XmlFile(filePath));
        }

        else if (filePath.endsWith(QStringLiteral(".json"), Qt::CaseInsensitive))
        {
            file = QSharedPointer<File>(new JsonFile(filePath));
        }

        else
        {
            emit error("Unknown file type.");
            return false;
        }

        if (!createWorld(file->readWidth(), file->readHeight(), file->readGenerations()))
            return false;

        while (file->hasNext())
        {
            quint32 x, y;

            file->readCoordinate(x, y);
            createCell(x, y);
        }
    }

    catch (FileException& e)
    {
        emit error(QStringLiteral("File is invalid: ") + e.error());
        return false;
    }

    return true;
}

bool World::saveFile(const QUrl& fileUrl) noexcept
{
    const QString filePath = fileUrl.toLocalFile();

    try
    {
        if (filePath.endsWith(QStringLiteral(".xml"), Qt::CaseInsensitive))
        {
            XmlFile::write(filePath, *this);
        }

        else if (filePath.endsWith(QStringLiteral(".json"), Qt::CaseInsensitive))
        {
            JsonFile::write(filePath, *this);
        }

        else
        {
            emit error("Unknown file type.");
            return false;
        }
    }

    catch (FileException& e)
    {
        emit error(e.error());
        return false;
    }

    return true;
}

bool World::isValid(quint32 x, quint32 y) const noexcept
{
    return x < width() && y < height();
}

bool World::isAlive(quint32 x, quint32 y) const noexcept
{
    if (!isValid(x ,y))
        return false;

    return matrix->get(x, y);
}

bool World::createCell(quint32 x, quint32 y) noexcept
{
    if (isValid(x, y) && !isAlive(x, y))
    {
        matrix->set(x, y, true);
        emit countChanged(++count_);

        return true;
    }

    return false;
}

bool World::killCell(quint32 x, quint32 y) noexcept
{
    if (isValid(x, y) && isAlive(x, y))
    {
        matrix->set(x, y, false);
        emit countChanged(--count_);

        return true;
    }

    return false;
}

quint8 World::neighbors(quint32 x, quint32 y) const noexcept
{
    quint8 amount = 0;

    for (quint32 b = y - 1; b <= y + 1; ++b)
    {
        for (quint32 a = x - 1; a <= x + 1; ++a)
        {
            if (y == b && x == a) continue; // ignore self
            if (isValid(a, b) && isAlive(a, b)) ++amount;
        }
    }

    return amount;
}

bool World::random(quint64 number) noexcept
{
    if (number > matrix->size() - count_)
    {
        emit error("Number of cells exceeds available space.");
        return false;
    }

    QRandomGenerator* chaos = QRandomGenerator::global();

    while (number > 0)
    {
        quint32 x = chaos->bounded(width());
        quint32 y = chaos->bounded(height());

        if (createCell(x, y)) // if cell did not exist
            --number;
    }

    return true;
}

void World::next() noexcept
{
    Headway::Matrix<quint8> cache(width(), height()); // store neighbor information

    for (quint32 y = 0; y < height(); ++y)
    {
        for (quint32 x = 0; x < width(); ++x)
        {
            quint8 n = neighbors(x, y);
            cache.set(x, y, n);
        }
    }

    blockSignals(true); // emit countChanged only once

    for (quint32 y = 0; y < height(); ++y)
    {
        for (quint32 x = 0; x < width(); ++x)
        {
            quint8 n = cache.get(x, y);

            if (n <= 1 || n >= 4) killCell(x, y);
            else if (n == 3) createCell(x, y);
        }
    }

    blockSignals(false);

    emit countChanged(count_);
    emit generationsChanged(++generations_);
}

bool World::operator==(const World& other) const
{
    return *matrix == *(other.matrix) &&
           generations_ == other.generations_ &&
           count_ == other.count_;
}

bool World::operator!=(const World& other) const
{
    return !(*this == other);
}
<commit_msg>constness<commit_after>#include "jsonfile.hpp"
#include "xmlfile.hpp"
#include "world.hpp"

using namespace Headway;

World::World(QObject* parent) : QObject(parent)
{
    createWorld();
}

World::World(const World& other) : QObject(other.parent()), generations_(other.generations()), count_(other.count()), matrix(new Matrix<bool>(*(other.matrix)))
{
}

World::~World() noexcept
{
    delete matrix;
}

bool World::createWorld(quint32 width, quint32 height, quint64 generations) noexcept
{
    if (width == 0)
    {
        emit error("Width must not be zero.");
        return false;
    }

    if (height == 0)
    {
        emit error("Height must not be zero.");
        return false;
    }

    if (matrix != nullptr)
        delete matrix;

    matrix = new Matrix<bool>(width, height);
    matrix->fill(false);

    generations_ = generations; emit generationsChanged(generations);
    count_ = 0; emit countChanged(0);

    return true;
}

bool World::loadFile(const QUrl& fileUrl) noexcept
{
    QSharedPointer<File> file;
    const QString filePath = fileUrl.toLocalFile();

    try
    {
        if (filePath.endsWith(QStringLiteral(".xml"), Qt::CaseInsensitive))
        {
            file = QSharedPointer<File>(new XmlFile(filePath));
        }

        else if (filePath.endsWith(QStringLiteral(".json"), Qt::CaseInsensitive))
        {
            file = QSharedPointer<File>(new JsonFile(filePath));
        }

        else
        {
            emit error("Unknown file type.");
            return false;
        }

        if (!createWorld(file->readWidth(), file->readHeight(), file->readGenerations()))
            return false;

        while (file->hasNext())
        {
            quint32 x, y;

            file->readCoordinate(x, y);
            createCell(x, y);
        }
    }

    catch (FileException& e)
    {
        emit error(QStringLiteral("File is invalid: ") + e.error());
        return false;
    }

    return true;
}

bool World::saveFile(const QUrl& fileUrl) noexcept
{
    const QString filePath = fileUrl.toLocalFile();

    try
    {
        if (filePath.endsWith(QStringLiteral(".xml"), Qt::CaseInsensitive))
        {
            XmlFile::write(filePath, *this);
        }

        else if (filePath.endsWith(QStringLiteral(".json"), Qt::CaseInsensitive))
        {
            JsonFile::write(filePath, *this);
        }

        else
        {
            emit error("Unknown file type.");
            return false;
        }
    }

    catch (FileException& e)
    {
        emit error(e.error());
        return false;
    }

    return true;
}

bool World::isValid(quint32 x, quint32 y) const noexcept
{
    return x < width() && y < height();
}

bool World::isAlive(quint32 x, quint32 y) const noexcept
{
    if (!isValid(x ,y))
        return false;

    return matrix->get(x, y);
}

bool World::createCell(quint32 x, quint32 y) noexcept
{
    if (isValid(x, y) && !isAlive(x, y))
    {
        matrix->set(x, y, true);
        emit countChanged(++count_);

        return true;
    }

    return false;
}

bool World::killCell(quint32 x, quint32 y) noexcept
{
    if (isValid(x, y) && isAlive(x, y))
    {
        matrix->set(x, y, false);
        emit countChanged(--count_);

        return true;
    }

    return false;
}

quint8 World::neighbors(quint32 x, quint32 y) const noexcept
{
    quint8 amount = 0;

    for (quint32 b = y - 1; b <= y + 1; ++b)
    {
        for (quint32 a = x - 1; a <= x + 1; ++a)
        {
            if (y == b && x == a) continue; // ignore self
            if (isValid(a, b) && isAlive(a, b)) ++amount;
        }
    }

    return amount;
}

bool World::random(quint64 number) noexcept
{
    if (number > matrix->size() - count())
    {
        emit error("Number of cells exceeds available space.");
        return false;
    }

    QRandomGenerator* chaos = QRandomGenerator::global();

    while (number > 0)
    {
        const quint32 x = chaos->bounded(width());
        const quint32 y = chaos->bounded(height());

        if (createCell(x, y)) // if cell did not exist
            --number;
    }

    return true;
}

void World::next() noexcept
{
    Headway::Matrix<quint8> cache(width(), height()); // store neighbor information

    for (quint32 y = 0; y < height(); ++y)
    {
        for (quint32 x = 0; x < width(); ++x)
        {
            const quint8 n = neighbors(x, y);
            cache.set(x, y, n);
        }
    }

    blockSignals(true); // emit countChanged only once

    for (quint32 y = 0; y < height(); ++y)
    {
        for (quint32 x = 0; x < width(); ++x)
        {
            const quint8 n = cache.get(x, y);

            if (n <= 1 || n >= 4) killCell(x, y);
            else if (n == 3) createCell(x, y);
        }
    }

    blockSignals(false);

    emit countChanged(count_);
    emit generationsChanged(++generations_);
}

bool World::operator==(const World& other) const
{
    return *matrix == *(other.matrix) &&
           generations_ == other.generations_ &&
           count_ == other.count_;
}

bool World::operator!=(const World& other) const
{
    return !(*this == other);
}
<|endoftext|>


<commit_before>// source changed by mrn@paus.ch/ max rheiner
// original source: henryj@paradise.net.nz

#include <iostream.h>
#include <stdlib.h> // exit()

#ifdef __APPLE_CC__
  #include <GLUT/glut.h>
#else
  #include <GL/glut.h>
#endif

#include "FTGLOutlineFont.h"
#include "FTGLPolygonFont.h"
#include "FTGLBitmapFont.h"
#ifndef FTGL_NO_TEXTURE_FONTS
#include "FTGLTextureFont.h"
#endif
#include "FTGLPixmapFont.h"

static FTFont* fonts[5];
static int width;
static int height;

#ifdef __linux__
const char* DEFAULT_FONT = "/usr/share/fonts/truetype/arial.ttf";
#else
#ifdef __APPLE_CC__
const char* DEFAULT_FONT = "/Users/henry/Development/PROJECTS/FTGL/ftglcvs/FTGL/demo/arial.ttf";
#else
#ifdef WIN32
const char* DEFAULT_FONT = "C:\\WINNT\\Fonts\\arial.ttf";
#else
const char* DEFAULT_FONT = "arial.ttf";
#endif
#endif
#endif

int file_exists( const char * filename );

void draw_scene();

void
my_init( const char* font_filename )
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    fonts[0] = new FTGLOutlineFont;
    fonts[1] = new FTGLPolygonFont;
#ifndef FTGL_NO_TEXTURE_FONTS
    fonts[2] = new FTGLTextureFont;
#endif
    fonts[3] = new FTGLBitmapFont;
    fonts[4] = new FTGLPixmapFont;
    for (int i=0; i< 5; i++) {
#ifdef FTGL_NO_TEXTURE_FONTS
    if (i == 2) continue;
#endif
        if (!fonts[i]->Open(font_filename)) {
            cerr << "ERROR: Unable to open file " << font_filename << "\n";
        }
        else {
			cout << "Reading font " << i << " from " << font_filename << endl;

            int point_size = 24;
            if (!fonts[i]->FaceSize(point_size)) {
                cerr << "ERROR: Unable to set font face size " << point_size << "\n";
            }

            // Try to load AFM font metrics
            const char* ext = strrchr(font_filename, '.');
            if (ext && !strcmp(ext, ".pfb"))
            {
            char *metrics = new char[strlen(font_filename)];
            strncpy(metrics, font_filename, ext - font_filename);
            strcpy(metrics + (ext - font_filename), ".afm");
            if (file_exists(metrics))
              {
              cout << "Attaching font metrics from " << metrics << endl;
              fonts[i]->Attach(metrics);
              }
            }
        }
    }
}

static void
do_ortho()
{
  int w;
  int h;
  GLdouble size;
  GLdouble aspect;

  w = width;
  h = height;
  aspect = (GLdouble)w / (GLdouble)h;

  // Use the whole window.
  glViewport(0, 0, w, h);

  // We are going to do some 2-D orthographic drawing.
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  size = (GLdouble)((w >= h) ? w : h) / 2.0;
  if (w <= h) {
    aspect = (GLdouble)h/(GLdouble)w;
    glOrtho(-size, size, -size*aspect, size*aspect,
            -100000.0, 100000.0);
  }
  else {
    aspect = (GLdouble)w/(GLdouble)h;
    glOrtho(-size*aspect, size*aspect, -size, size,
            -100000.0, 100000.0);
  }

  // Make the world and window coordinates coincide so that 1.0 in
  // model space equals one pixel in window space.
  glScaled(aspect, aspect, 1.0);

   // Now determine where to draw things.
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

#ifndef GLUTCALLBACK
#define GLUTCALLBACK
#endif

extern "C" {

void
GLUTCALLBACK my_display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    draw_scene();

    glutSwapBuffers();
}

void
GLUTCALLBACK my_reshape(int w, int h)
{
  width = w;
  height = h;

  do_ortho( );
}

void
GLUTCALLBACK my_handle_key(unsigned char key, int x, int y)
{
   switch (key) {

	   //!!ELLERS
   case 'q':   // Esc or 'q' Quits the program.
   case 27:
	   {
       for (int i=0; i<5; i++) {
#ifdef FTGL_NO_TEXTURE_FONTS
       if (i == 2) continue;
#endif
           if (fonts[i]) {
               delete fonts[i];
               fonts[i] = 0;
           }
       }
      exit(1);
	   }
      break;

   default:
      break;
   }
}

} // End of extern C

void
draw_scene()
{
   /* Set up some strings with the characters to draw. */
   unsigned int count = 0;
   char string[8][256];
   int i;
   for (i=1; i < 32; i++) { /* Skip zero - it's the null terminator! */
      string[0][count] = i;
      count++;
   }
   string[0][count] = '\0';

   count = 0;
   for (i=32; i < 64; i++) {
      string[1][count] = i;
      count++;
   }
   string[1][count] = '\0';

   count = 0;
   for (i=64; i < 96; i++) {
      string[2][count] = i;
      count++;
   }
   string[2][count] = '\0';

   count = 0;
   for (i=96; i < 128; i++) {
      string[3][count] = i;
      count++;
   }
   string[3][count] = '\0';

   count = 0;
   for (i=128; i < 160; i++) {
      string[4][count] = i;
      count++;
   }
   string[4][count] = '\0';

   count = 0;
   for (i=160; i < 192; i++) {
      string[5][count] = i;
      count++;
   }
   string[5][count] = '\0';

   count = 0;
   for (i=192; i < 224; i++) {
      string[6][count] = i;
      count++;
   }
   string[6][count] = '\0';

   count = 0;
   for (i=224; i < 256; i++) {
      string[7][count] = i;
      count++;
   }
   string[7][count] = '\0';

   glColor3f(1.0, 1.0, 1.0);

   for (int font = 0; font < 5; font++) {
       GLfloat x = -250.0;
       GLfloat y;
       GLfloat yild = 20.0;
       for (int j=0; j<4; j++) {
           y = 275.0-font*120.0-j*yild;
           if (font >= 3) {
               glRasterPos2f(x, y);
               fonts[font]->render(string[j]);
           }
           else {
#ifdef FTGL_NO_TEXTURE_FONTS
           if (font == 2) continue;
#endif
               if (font == 2) {
                   glEnable(GL_TEXTURE_2D);
                   glEnable(GL_BLEND);
                   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
               }
               glPushMatrix(); {
                   glTranslatef(x, y, 0.0);
                   fonts[font]->render(string[j]);
               } glPopMatrix();
               if (font == 2) {
                   glDisable(GL_TEXTURE_2D);
                   glDisable(GL_BLEND);
               }
           }
       }
   }
}

int
file_exists( const char * filename )
{
	FILE * fp = fopen( filename, "r" );

	if ( fp == NULL )
	{
		// That fopen failed does _not_ definitely mean the file isn't there
		// but for now this is ok
		return 0;
	}
	fclose( fp );
	return 1;
}

void
usage( const char * program )
{
	cerr << "Usage: " << program << " <filename.ttf>\n" << endl;
}

int
main(int argc, char **argv)
{
	//!!ELLERS  -- cleaned up
	const char * filename;

	glutInitWindowSize(600, 600);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);

	glutCreateWindow("FTGL demo");

	if ( argc >= 2 )
	{
		if ( !file_exists( argv[ 1 ] ))
		{
			usage( argv[ 0 ]);
			cerr << "Couldn't open file '" << argv[ 1 ] << "'" << endl;
			exit( -1 );
		}
		filename = argv[ 1 ];
	}
	else
	{
		// try a default font
		filename = DEFAULT_FONT;

		if ( !file_exists( filename ))
		{
			usage( argv[ 0 ]);
			cerr << "Couldn't open default file '" << filename << "'" << endl;
			exit( -1 );
		}
	}

	my_init( filename );

	glutDisplayFunc(my_display);
	glutReshapeFunc(my_reshape);
	glutKeyboardFunc(my_handle_key);

	glutMainLoop();
	return 0;
}

<commit_msg>FIX: fix warnings (unused vars)<commit_after>// source changed by mrn@paus.ch/ max rheiner
// original source: henryj@paradise.net.nz

#include <iostream.h>
#include <stdlib.h> // exit()

#ifdef __APPLE_CC__
  #include <GLUT/glut.h>
#else
  #include <GL/glut.h>
#endif

#include "FTGLOutlineFont.h"
#include "FTGLPolygonFont.h"
#include "FTGLBitmapFont.h"
#ifndef FTGL_NO_TEXTURE_FONTS
#include "FTGLTextureFont.h"
#endif
#include "FTGLPixmapFont.h"

static FTFont* fonts[5];
static int width;
static int height;

#ifdef __linux__
const char* DEFAULT_FONT = "/usr/share/fonts/truetype/arial.ttf";
#else
#ifdef __APPLE_CC__
const char* DEFAULT_FONT = "/Users/henry/Development/PROJECTS/FTGL/ftglcvs/FTGL/demo/arial.ttf";
#else
#ifdef WIN32
const char* DEFAULT_FONT = "C:\\WINNT\\Fonts\\arial.ttf";
#else
const char* DEFAULT_FONT = "arial.ttf";
#endif
#endif
#endif

int file_exists( const char * filename );

void draw_scene();

void
my_init( const char* font_filename )
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    fonts[0] = new FTGLOutlineFont;
    fonts[1] = new FTGLPolygonFont;
#ifndef FTGL_NO_TEXTURE_FONTS
    fonts[2] = new FTGLTextureFont;
#endif
    fonts[3] = new FTGLBitmapFont;
    fonts[4] = new FTGLPixmapFont;
    for (int i=0; i< 5; i++) {
#ifdef FTGL_NO_TEXTURE_FONTS
    if (i == 2) continue;
#endif
        if (!fonts[i]->Open(font_filename)) {
            cerr << "ERROR: Unable to open file " << font_filename << "\n";
        }
        else {
			cout << "Reading font " << i << " from " << font_filename << endl;

            int point_size = 24;
            if (!fonts[i]->FaceSize(point_size)) {
                cerr << "ERROR: Unable to set font face size " << point_size << "\n";
            }

            // Try to load AFM font metrics
            const char* ext = strrchr(font_filename, '.');
            if (ext && !strcmp(ext, ".pfb"))
            {
            char *metrics = new char[strlen(font_filename)];
            strncpy(metrics, font_filename, ext - font_filename);
            strcpy(metrics + (ext - font_filename), ".afm");
            if (file_exists(metrics))
              {
              cout << "Attaching font metrics from " << metrics << endl;
              fonts[i]->Attach(metrics);
              }
            }
        }
    }
}

static void
do_ortho()
{
  int w;
  int h;
  GLdouble size;
  GLdouble aspect;

  w = width;
  h = height;
  aspect = (GLdouble)w / (GLdouble)h;

  // Use the whole window.
  glViewport(0, 0, w, h);

  // We are going to do some 2-D orthographic drawing.
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  size = (GLdouble)((w >= h) ? w : h) / 2.0;
  if (w <= h) {
    aspect = (GLdouble)h/(GLdouble)w;
    glOrtho(-size, size, -size*aspect, size*aspect,
            -100000.0, 100000.0);
  }
  else {
    aspect = (GLdouble)w/(GLdouble)h;
    glOrtho(-size*aspect, size*aspect, -size, size,
            -100000.0, 100000.0);
  }

  // Make the world and window coordinates coincide so that 1.0 in
  // model space equals one pixel in window space.
  glScaled(aspect, aspect, 1.0);

   // Now determine where to draw things.
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

#ifndef GLUTCALLBACK
#define GLUTCALLBACK
#endif

extern "C" {

void
GLUTCALLBACK my_display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    draw_scene();

    glutSwapBuffers();
}

void
GLUTCALLBACK my_reshape(int w, int h)
{
  width = w;
  height = h;

  do_ortho( );
}

void
GLUTCALLBACK my_handle_key(unsigned char key, int, int)
{
   switch (key) {

	   //!!ELLERS
   case 'q':   // Esc or 'q' Quits the program.
   case 27:
	   {
       for (int i=0; i<5; i++) {
#ifdef FTGL_NO_TEXTURE_FONTS
       if (i == 2) continue;
#endif
           if (fonts[i]) {
               delete fonts[i];
               fonts[i] = 0;
           }
       }
      exit(1);
	   }
      break;

   default:
      break;
   }
}

} // End of extern C

void
draw_scene()
{
   /* Set up some strings with the characters to draw. */
   unsigned int count = 0;
   char string[8][256];
   int i;
   for (i=1; i < 32; i++) { /* Skip zero - it's the null terminator! */
      string[0][count] = i;
      count++;
   }
   string[0][count] = '\0';

   count = 0;
   for (i=32; i < 64; i++) {
      string[1][count] = i;
      count++;
   }
   string[1][count] = '\0';

   count = 0;
   for (i=64; i < 96; i++) {
      string[2][count] = i;
      count++;
   }
   string[2][count] = '\0';

   count = 0;
   for (i=96; i < 128; i++) {
      string[3][count] = i;
      count++;
   }
   string[3][count] = '\0';

   count = 0;
   for (i=128; i < 160; i++) {
      string[4][count] = i;
      count++;
   }
   string[4][count] = '\0';

   count = 0;
   for (i=160; i < 192; i++) {
      string[5][count] = i;
      count++;
   }
   string[5][count] = '\0';

   count = 0;
   for (i=192; i < 224; i++) {
      string[6][count] = i;
      count++;
   }
   string[6][count] = '\0';

   count = 0;
   for (i=224; i < 256; i++) {
      string[7][count] = i;
      count++;
   }
   string[7][count] = '\0';

   glColor3f(1.0, 1.0, 1.0);

   for (int font = 0; font < 5; font++) {
       GLfloat x = -250.0;
       GLfloat y;
       GLfloat yild = 20.0;
       for (int j=0; j<4; j++) {
           y = 275.0-font*120.0-j*yild;
           if (font >= 3) {
               glRasterPos2f(x, y);
               fonts[font]->render(string[j]);
           }
           else {
#ifdef FTGL_NO_TEXTURE_FONTS
           if (font == 2) continue;
#endif
               if (font == 2) {
                   glEnable(GL_TEXTURE_2D);
                   glEnable(GL_BLEND);
                   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
               }
               glPushMatrix(); {
                   glTranslatef(x, y, 0.0);
                   fonts[font]->render(string[j]);
               } glPopMatrix();
               if (font == 2) {
                   glDisable(GL_TEXTURE_2D);
                   glDisable(GL_BLEND);
               }
           }
       }
   }
}

int
file_exists( const char * filename )
{
	FILE * fp = fopen( filename, "r" );

	if ( fp == NULL )
	{
		// That fopen failed does _not_ definitely mean the file isn't there
		// but for now this is ok
		return 0;
	}
	fclose( fp );
	return 1;
}

void
usage( const char * program )
{
	cerr << "Usage: " << program << " <filename.ttf>\n" << endl;
}

int
main(int argc, char **argv)
{
	//!!ELLERS  -- cleaned up
	const char * filename;

	glutInitWindowSize(600, 600);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);

	glutCreateWindow("FTGL demo");

	if ( argc >= 2 )
	{
		if ( !file_exists( argv[ 1 ] ))
		{
			usage( argv[ 0 ]);
			cerr << "Couldn't open file '" << argv[ 1 ] << "'" << endl;
			exit( -1 );
		}
		filename = argv[ 1 ];
	}
	else
	{
		// try a default font
		filename = DEFAULT_FONT;

		if ( !file_exists( filename ))
		{
			usage( argv[ 0 ]);
			cerr << "Couldn't open default file '" << filename << "'" << endl;
			exit( -1 );
		}
	}

	my_init( filename );

	glutDisplayFunc(my_display);
	glutReshapeFunc(my_reshape);
	glutKeyboardFunc(my_handle_key);

	glutMainLoop();
	return 0;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <math.h>

// an interview question:
// "design a function such that f(f(n)) == -n, where n is a 32 bit signed int,
// and which does not use complex numbers"

int minusItself(int n)
{ // are globals or external state considered "complex numbers"?
  // a very philosophical question.
  static bool hasCalledItself = false;
  if (hasCalledItself) {
    hasCalledItself = false;
    return n;
  }
  hasCalledItself = true;
  return -n;
}

double changesItself(double n)
{ // uses doubles instead of ints. again, this is "extra info"
  // and would fit a liberal definition of a complex number.
  if (n == int(n)) // first time called
    return n + 0.1;
  else
    return int(-n + 0.1);
}

int main()
{
  for (int i = -3; i < 4; i++)
    std::cout << "minusItself(minusItself(" << i << "): " << minusItself(minusItself(i)) << std::endl;
  for (int i = -3; i < 4; i++)
    std::cout << "changesItself(changesItself(" << i << "): " << changesItself(changesItself(i)) << std::endl;
}
<commit_msg>cleaned up puzzles/inverter<commit_after>#include <iostream>

// an interview question:
// "design a function such that f(f(n)) == -n, where n is a 32 bit signed int,
// and which does not use complex numbers"
//
// are globals or external state considered "complex numbers"?
// a philosophical question.

int minusItself(int n)
{
  static bool hasCalledItself = false;
  if (hasCalledItself) {
    hasCalledItself = false;
    return n;
  }
  hasCalledItself = true;
  return -n;
}

double changesItself(double n)
{ // uses doubles instead of ints. again, this is "extra info"
  // and would fit a liberal definition of a complex number.
  return (n == static_cast<int>(n)) ? n + 0.1 : static_cast<int>(-n + 0.1);
}

int main()
{
  for (int i = -1; i < 2; i++)
    std::cout << "minusItself(minusItself(" << i << "): " << minusItself(minusItself(i)) << std::endl;

  std::cout << std::endl;

  for (int i = -1; i < 2; i++)
    std::cout << "changesItself(changesItself(" << i << "): " << changesItself(changesItself(i)) << std::endl;
}

// output:
//
// minusItself(minusItself(-1): 1
// minusItself(minusItself(0): 0
// minusItself(minusItself(1): -1
//
// changesItself(changesItself(-1): 1
// changesItself(changesItself(0): 0
// changesItself(changesItself(1): -1
<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * 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 main.cpp
 */

#include <DBHandler/HeaderFiles/DBHandler.h>
#include <JPetManager/JPetManager.h>
#include <JPetTaskLoader/JPetTaskLoader.h>
#include "../LargeBarrelAnalysisExtended/TimeWindowCreator.h"
#include "../LargeBarrelAnalysisExtended/TimeCalibLoader.h"
#include "../LargeBarrelAnalysisExtended/SignalFinder.h"
#include "../LargeBarrelAnalysisExtended/SignalTransformer.h"
#include "../LargeBarrelAnalysisExtended/HitFinder.h"
#include "../LargeBarrelAnalysisExtended/EventFinder.h"
#include "../LargeBarrelAnalysisExtended/EventCategorizer.h"

using namespace std;

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

  //Connection to the remote database disabled for the moment
  //DB::SERVICES::DBHandler::createDBConnection("../DBConfig/configDB.cfg");

  JPetManager& manager = JPetManager::getManager();
  manager.parseCmdLine(argc, argv);

  //First task - unpacking
  manager.registerTask([]() {
    return new JPetTaskLoader("hld", "tslot.raw",
      new TimeWindowCreator(
        "TimeWindowCreator",
        "Process unpacked HLD file into a tree of JPetTimeWindow objects"
      )
    );
  });

  //Second task - Signal Channel calibration
  manager.registerTask([]() {
    return new JPetTaskLoader("tslot.raw", "tslot.calib",
      new TimeCalibLoader(
        "TimeCalibLoader",
        "Apply time corrections from prepared calibrations"
      )
    );
  });

  //Third task - Raw Signal Creation
  manager.registerTask([]() {
    return new JPetTaskLoader("tslot.calib", "raw.sig",
      new SignalFinder(
        "SignalFinder",
        "Create Raw Signals, optional - draw control histograms",
        true
      )
    );
  });

  ////Fourth task - Reco & Phys signal creation
  manager.registerTask([]() {
    return new JPetTaskLoader("raw.sig", "phys.sig",
      new SignalTransformer(
        "SignalTransformer",
        "Create Reco & Phys Signals"
      )
    );
  });

  ////Fifth task - Hit construction
  manager.registerTask([]() {
    return new JPetTaskLoader("phys.sig", "hits",
      new HitFinder(
        "HitFinder",
        "Create hits from physical signals"
      )
    );
  });

  ////Sixth task - unknown Event construction
  manager.registerTask([]() {
    return new JPetTaskLoader("hits", "unk.evt",
      new EventFinder(
        "EventFinder",
        "Create Events as group of Hits"
      )
    );
  });

  //Seventh task - Event Categorization
  manager.registerTask([]() {
    return new JPetTaskLoader("unk.evt", "cat.evt",
      new EventCategorizer(
        "EventCategorizer",
        "Categorize Events"
      )
    );
  });

  manager.run();
}
<commit_msg>Delete not needed modules from main function<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * 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 main.cpp
 */

#include <DBHandler/HeaderFiles/DBHandler.h>
#include <JPetManager/JPetManager.h>
#include <JPetTaskLoader/JPetTaskLoader.h>
#include "../LargeBarrelAnalysisExtended/TimeWindowCreator.h"
#include "../LargeBarrelAnalysisExtended/TimeCalibLoader.h"
#include "../LargeBarrelAnalysisExtended/SignalFinder.h"
#include "../LargeBarrelAnalysisExtended/SignalTransformer.h"
#include "../LargeBarrelAnalysisExtended/HitFinder.h"

using namespace std;

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

  //Connection to the remote database disabled for the moment
  //DB::SERVICES::DBHandler::createDBConnection("../DBConfig/configDB.cfg");

  JPetManager& manager = JPetManager::getManager();
  manager.parseCmdLine(argc, argv);

  //First task - unpacking
  manager.registerTask([]() {
    return new JPetTaskLoader("hld", "tslot.raw",
      new TimeWindowCreator(
        "TimeWindowCreator",
        "Process unpacked HLD file into a tree of JPetTimeWindow objects"
      )
    );
  });

  //Second task - Signal Channel calibration
  manager.registerTask([]() {
    return new JPetTaskLoader("tslot.raw", "tslot.calib",
      new TimeCalibLoader(
        "TimeCalibLoader",
        "Apply time corrections from prepared calibrations"
      )
    );
  });

  //Third task - Raw Signal Creation
  manager.registerTask([]() {
    return new JPetTaskLoader("tslot.calib", "raw.sig",
      new SignalFinder(
        "SignalFinder",
        "Create Raw Signals, optional - draw control histograms",
        true
      )
    );
  });

  ////Fourth task - Reco & Phys signal creation
  manager.registerTask([]() {
    return new JPetTaskLoader("raw.sig", "phys.sig",
      new SignalTransformer(
        "SignalTransformer",
        "Create Reco & Phys Signals"
      )
    );
  });

  ////Fifth task - Hit construction
  manager.registerTask([]() {
    return new JPetTaskLoader("phys.sig", "hits",
      new HitFinder(
        "HitFinder",
        "Create hits from physical signals"
      )
    );
  });

  manager.run();
}
<|endoftext|>


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

/**
 * @file mavlink_ulog.cpp
 * ULog data streaming via MAVLink
 *
 * @author Beat Küng <beat-kueng@gmx.net>
 */

#include "mavlink_ulog.h"
#include <px4_log.h>
#include <errno.h>
#include <mathlib/mathlib.h>

bool MavlinkULog::_init = false;
MavlinkULog *MavlinkULog::_instance = nullptr;
px4_sem_t MavlinkULog::_lock;
const float MavlinkULog::_rate_calculation_delta_t = 0.1f;

MavlinkULog::MavlinkULog(int datarate, float max_rate_factor, uint8_t target_system, uint8_t target_component)
	: _target_system(target_system), _target_component(target_component),
	_max_rate_factor(max_rate_factor),
	_max_num_messages(math::max(1, (int)ceilf(_rate_calculation_delta_t * _max_rate_factor * datarate /
			(MAVLINK_MSG_ID_LOGGING_DATA_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES)))),
	_current_rate_factor(max_rate_factor)
{
	_ulog_stream_sub = orb_subscribe(ORB_ID(ulog_stream));

	if (_ulog_stream_sub < 0) {
		PX4_ERR("orb_subscribe failed (%i)", errno);
	}
	_waiting_for_initial_ack = true;
	_last_sent_time = hrt_absolute_time(); //(ab)use this timestamp during initialization
	_next_rate_check = _last_sent_time + _rate_calculation_delta_t * 1.e6f;
}

MavlinkULog::~MavlinkULog()
{
	if (_ulog_stream_ack_pub) {
		orb_unadvertise(_ulog_stream_ack_pub);
	}
	if (_ulog_stream_sub >= 0) {
		orb_unsubscribe(_ulog_stream_sub);
	}
}

void MavlinkULog::start_ack_received()
{
	if (_waiting_for_initial_ack) {
		_last_sent_time = 0;
		_waiting_for_initial_ack = false;
		PX4_DEBUG("got logger ack");
	}
}

int MavlinkULog::handle_update(mavlink_channel_t channel)
{
	static_assert(sizeof(ulog_stream_s::data) == MAVLINK_MSG_LOGGING_DATA_FIELD_DATA_LEN, "Invalid uorb ulog_stream.data length");
	static_assert(sizeof(ulog_stream_s::data) == MAVLINK_MSG_LOGGING_DATA_ACKED_FIELD_DATA_LEN, "Invalid uorb ulog_stream.data length");

	if (_waiting_for_initial_ack) {
		if (hrt_elapsed_time(&_last_sent_time) > 3e5) {
			PX4_WARN("no ack from logger (is it running?)");
			return -1;
		}
	}

	// check if we're waiting for an ACK
	if (_last_sent_time) {
		bool check_for_updates = false;
		if (_ack_received) {
			_last_sent_time = 0;
			check_for_updates = true;
		} else {

			if (hrt_elapsed_time(&_last_sent_time) > ulog_stream_ack_s::ACK_TIMEOUT * 1000) {
				if (++_sent_tries > ulog_stream_ack_s::ACK_MAX_TRIES) {
					return -ETIMEDOUT;
				} else {
					PX4_DEBUG("re-sending ulog mavlink message (try=%i)", _sent_tries);
					_last_sent_time = hrt_absolute_time();
					mavlink_logging_data_acked_t msg;
					msg.sequence = _ulog_data.sequence;
					msg.length = _ulog_data.length;
					msg.first_message_offset = _ulog_data.first_message_offset;
					msg.target_system = _target_system;
					msg.target_component = _target_component;
					memcpy(msg.data, _ulog_data.data, sizeof(msg.data));
					mavlink_msg_logging_data_acked_send_struct(channel, &msg);
				}
			}
		}

		if (!check_for_updates) {
			return 0;
		}
	}

	bool updated = false;
	int ret = orb_check(_ulog_stream_sub, &updated);
	while (updated && !ret && _current_num_msgs < _max_num_messages) {
		orb_copy(ORB_ID(ulog_stream), _ulog_stream_sub, &_ulog_data);
		if (_ulog_data.flags & ulog_stream_s::FLAGS_NEED_ACK) {
			_sent_tries = 1;
			_last_sent_time = hrt_absolute_time();
			lock();
			_wait_for_ack_sequence = _ulog_data.sequence;
			_ack_received = false;
			unlock();

			mavlink_logging_data_acked_t msg;
			msg.sequence = _ulog_data.sequence;
			msg.length = _ulog_data.length;
			msg.first_message_offset = _ulog_data.first_message_offset;
			msg.target_system = _target_system;
			msg.target_component = _target_component;
			memcpy(msg.data, _ulog_data.data, sizeof(msg.data));
			mavlink_msg_logging_data_acked_send_struct(channel, &msg);

		} else {
			mavlink_logging_data_t msg;
			msg.sequence = _ulog_data.sequence;
			msg.length = _ulog_data.length;
			msg.first_message_offset = _ulog_data.first_message_offset;
			msg.target_system = _target_system;
			msg.target_component = _target_component;
			memcpy(msg.data, _ulog_data.data, sizeof(msg.data));
			mavlink_msg_logging_data_send_struct(channel, &msg);
		}
		++_current_num_msgs;
		ret = orb_check(_ulog_stream_sub, &updated);
	}

	//need to update the rate?
	hrt_abstime t = hrt_absolute_time();
	if (t > _next_rate_check) {
		if (_current_num_msgs < _max_num_messages) {
			_current_rate_factor = _max_rate_factor * (float)_current_num_msgs / _max_num_messages;
		} else {
			_current_rate_factor = _max_rate_factor;
		}
		_current_num_msgs = 0;
		_next_rate_check = t + _rate_calculation_delta_t * 1.e6f;
		PX4_DEBUG("current rate=%.3f (max=%i msgs in %.3fs)", (double)_current_rate_factor, _max_num_messages,
				(double)_rate_calculation_delta_t);
	}

	return 0;
}

void MavlinkULog::initialize()
{
	if (_init) {
		return;
	}
	px4_sem_init(&_lock, 1, 1);
	_init = true;
}

MavlinkULog* MavlinkULog::try_start(int datarate, float max_rate_factor, uint8_t target_system, uint8_t target_component)
{
	MavlinkULog *ret = nullptr;
	bool failed = false;
	lock();
	if (!_instance) {
		ret = _instance = new MavlinkULog(datarate, max_rate_factor, target_system, target_component);
		if (!_instance) {
			failed = true;
		}
	}
	unlock();

	if (failed) {
		PX4_ERR("alloc failed");
	}
	return ret;
}

void MavlinkULog::stop()
{
	lock();
	if (_instance) {
		delete _instance;
		_instance = nullptr;
	}
	unlock();
}

void MavlinkULog::handle_ack(mavlink_logging_ack_t ack)
{
	lock();
	if (_instance) { // make sure stop() was not called right before
		if (_wait_for_ack_sequence == ack.sequence) {
			_ack_received = true;
			publish_ack(ack.sequence);
		}
	}
	unlock();
}

void MavlinkULog::publish_ack(uint16_t sequence)
{
	ulog_stream_ack_s ack;
	ack.timestamp = hrt_absolute_time();
	ack.sequence = sequence;

	if (_ulog_stream_ack_pub == nullptr) {
		_ulog_stream_ack_pub = orb_advertise_queue(ORB_ID(ulog_stream_ack), &ack, 3);

	} else {
		orb_publish(ORB_ID(ulog_stream_ack), _ulog_stream_ack_pub, &ack);
	}
}
<commit_msg>fix mavlink ulog: return if initial ack not yet received<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mavlink_ulog.cpp
 * ULog data streaming via MAVLink
 *
 * @author Beat Küng <beat-kueng@gmx.net>
 */

#include "mavlink_ulog.h"
#include <px4_log.h>
#include <errno.h>
#include <mathlib/mathlib.h>

bool MavlinkULog::_init = false;
MavlinkULog *MavlinkULog::_instance = nullptr;
px4_sem_t MavlinkULog::_lock;
const float MavlinkULog::_rate_calculation_delta_t = 0.1f;

MavlinkULog::MavlinkULog(int datarate, float max_rate_factor, uint8_t target_system, uint8_t target_component)
	: _target_system(target_system), _target_component(target_component),
	_max_rate_factor(max_rate_factor),
	_max_num_messages(math::max(1, (int)ceilf(_rate_calculation_delta_t * _max_rate_factor * datarate /
			(MAVLINK_MSG_ID_LOGGING_DATA_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES)))),
	_current_rate_factor(max_rate_factor)
{
	_ulog_stream_sub = orb_subscribe(ORB_ID(ulog_stream));

	if (_ulog_stream_sub < 0) {
		PX4_ERR("orb_subscribe failed (%i)", errno);
	}
	_waiting_for_initial_ack = true;
	_last_sent_time = hrt_absolute_time(); //(ab)use this timestamp during initialization
	_next_rate_check = _last_sent_time + _rate_calculation_delta_t * 1.e6f;
}

MavlinkULog::~MavlinkULog()
{
	if (_ulog_stream_ack_pub) {
		orb_unadvertise(_ulog_stream_ack_pub);
	}
	if (_ulog_stream_sub >= 0) {
		orb_unsubscribe(_ulog_stream_sub);
	}
}

void MavlinkULog::start_ack_received()
{
	if (_waiting_for_initial_ack) {
		_last_sent_time = 0;
		_waiting_for_initial_ack = false;
		PX4_DEBUG("got logger ack");
	}
}

int MavlinkULog::handle_update(mavlink_channel_t channel)
{
	static_assert(sizeof(ulog_stream_s::data) == MAVLINK_MSG_LOGGING_DATA_FIELD_DATA_LEN, "Invalid uorb ulog_stream.data length");
	static_assert(sizeof(ulog_stream_s::data) == MAVLINK_MSG_LOGGING_DATA_ACKED_FIELD_DATA_LEN, "Invalid uorb ulog_stream.data length");

	if (_waiting_for_initial_ack) {
		if (hrt_elapsed_time(&_last_sent_time) > 3e5) {
			PX4_WARN("no ack from logger (is it running?)");
			return -1;
		}
		return 0;
	}

	// check if we're waiting for an ACK
	if (_last_sent_time) {
		bool check_for_updates = false;
		if (_ack_received) {
			_last_sent_time = 0;
			check_for_updates = true;
		} else {

			if (hrt_elapsed_time(&_last_sent_time) > ulog_stream_ack_s::ACK_TIMEOUT * 1000) {
				if (++_sent_tries > ulog_stream_ack_s::ACK_MAX_TRIES) {
					return -ETIMEDOUT;
				} else {
					PX4_DEBUG("re-sending ulog mavlink message (try=%i)", _sent_tries);
					_last_sent_time = hrt_absolute_time();
					mavlink_logging_data_acked_t msg;
					msg.sequence = _ulog_data.sequence;
					msg.length = _ulog_data.length;
					msg.first_message_offset = _ulog_data.first_message_offset;
					msg.target_system = _target_system;
					msg.target_component = _target_component;
					memcpy(msg.data, _ulog_data.data, sizeof(msg.data));
					mavlink_msg_logging_data_acked_send_struct(channel, &msg);
				}
			}
		}

		if (!check_for_updates) {
			return 0;
		}
	}

	bool updated = false;
	int ret = orb_check(_ulog_stream_sub, &updated);
	while (updated && !ret && _current_num_msgs < _max_num_messages) {
		orb_copy(ORB_ID(ulog_stream), _ulog_stream_sub, &_ulog_data);
		if (_ulog_data.flags & ulog_stream_s::FLAGS_NEED_ACK) {
			_sent_tries = 1;
			_last_sent_time = hrt_absolute_time();
			lock();
			_wait_for_ack_sequence = _ulog_data.sequence;
			_ack_received = false;
			unlock();

			mavlink_logging_data_acked_t msg;
			msg.sequence = _ulog_data.sequence;
			msg.length = _ulog_data.length;
			msg.first_message_offset = _ulog_data.first_message_offset;
			msg.target_system = _target_system;
			msg.target_component = _target_component;
			memcpy(msg.data, _ulog_data.data, sizeof(msg.data));
			mavlink_msg_logging_data_acked_send_struct(channel, &msg);

		} else {
			mavlink_logging_data_t msg;
			msg.sequence = _ulog_data.sequence;
			msg.length = _ulog_data.length;
			msg.first_message_offset = _ulog_data.first_message_offset;
			msg.target_system = _target_system;
			msg.target_component = _target_component;
			memcpy(msg.data, _ulog_data.data, sizeof(msg.data));
			mavlink_msg_logging_data_send_struct(channel, &msg);
		}
		++_current_num_msgs;
		ret = orb_check(_ulog_stream_sub, &updated);
	}

	//need to update the rate?
	hrt_abstime t = hrt_absolute_time();
	if (t > _next_rate_check) {
		if (_current_num_msgs < _max_num_messages) {
			_current_rate_factor = _max_rate_factor * (float)_current_num_msgs / _max_num_messages;
		} else {
			_current_rate_factor = _max_rate_factor;
		}
		_current_num_msgs = 0;
		_next_rate_check = t + _rate_calculation_delta_t * 1.e6f;
		PX4_DEBUG("current rate=%.3f (max=%i msgs in %.3fs)", (double)_current_rate_factor, _max_num_messages,
				(double)_rate_calculation_delta_t);
	}

	return 0;
}

void MavlinkULog::initialize()
{
	if (_init) {
		return;
	}
	px4_sem_init(&_lock, 1, 1);
	_init = true;
}

MavlinkULog* MavlinkULog::try_start(int datarate, float max_rate_factor, uint8_t target_system, uint8_t target_component)
{
	MavlinkULog *ret = nullptr;
	bool failed = false;
	lock();
	if (!_instance) {
		ret = _instance = new MavlinkULog(datarate, max_rate_factor, target_system, target_component);
		if (!_instance) {
			failed = true;
		}
	}
	unlock();

	if (failed) {
		PX4_ERR("alloc failed");
	}
	return ret;
}

void MavlinkULog::stop()
{
	lock();
	if (_instance) {
		delete _instance;
		_instance = nullptr;
	}
	unlock();
}

void MavlinkULog::handle_ack(mavlink_logging_ack_t ack)
{
	lock();
	if (_instance) { // make sure stop() was not called right before
		if (_wait_for_ack_sequence == ack.sequence) {
			_ack_received = true;
			publish_ack(ack.sequence);
		}
	}
	unlock();
}

void MavlinkULog::publish_ack(uint16_t sequence)
{
	ulog_stream_ack_s ack;
	ack.timestamp = hrt_absolute_time();
	ack.sequence = sequence;

	if (_ulog_stream_ack_pub == nullptr) {
		_ulog_stream_ack_pub = orb_advertise_queue(ORB_ID(ulog_stream_ack), &ack, 3);

	} else {
		orb_publish(ORB_ID(ulog_stream_ack), _ulog_stream_ack_pub, &ack);
	}
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// 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 author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include <stdafx.h>
#include <algorithm>
#include <cursespp/Scrollbar.h>

using namespace cursespp;

void Scrollbar::Draw(ListWindow* list, Window* target) {
    int height = list->GetHeight();
    auto *adapter = &list->GetScrollAdapter();
    if (adapter && height > 2) {
        auto& pos = list->GetScrollPosition();

        /* these are defaults for drawing to an external view, that
        is, when target != list. */
        int xOffset = 0;
        int from = 0, to = height;
        WINDOW* frame = nullptr;
        float range = (float) height;
        size_t minY = 0;

        if (!target || target == list) {
            /* if we're drawing on top of the ListWindow's frame,
            we need to account for the padding it provides. */
            frame = list->GetFrame();
            xOffset = list->GetWidth() - 1;
            ++from; --to;
            range -= 2.0f;
            minY = 1;
        }
        else {
            frame = target->GetFrame();
        }

        float total = (float) std::max(minY, adapter->GetEntryCount());

        int yOffset;
        if (range >= total) {
            yOffset = -1;
        }
        else {
            float percent = (float)pos.logicalIndex / total;
            yOffset = (int)(range * percent) + minY;
        }

        for (int i = from; i < to; i++) {
            wmove(frame, i, xOffset);
            if (i == yOffset) wattron(frame, A_REVERSE);
            waddch(frame, (i == yOffset) ? ' ' : ACS_VLINE);
            if (i == yOffset) wattroff(frame, A_REVERSE);
        }
    }
}
<commit_msg>Use mvwvline() to draw scrollbar -- maybe this will fix the problem some FreeBSD users have?<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// 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 author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include <stdafx.h>
#include <algorithm>
#include <cursespp/Scrollbar.h>

using namespace cursespp;

void Scrollbar::Draw(ListWindow* list, Window* target) {
    int height = list->GetHeight();
    auto *adapter = &list->GetScrollAdapter();
    if (adapter && height > 2) {
        auto& pos = list->GetScrollPosition();

        /* these are defaults for drawing to an external view, that
        is, when target != list. */
        int xOffset = 0;
        int from = 0, to = height;
        WINDOW* frame = nullptr;
        float range = (float) height;
        size_t minY = 0;

        if (!target || target == list) {
            /* if we're drawing on top of the ListWindow's frame,
            we need to account for the padding it provides. */
            frame = list->GetFrame();
            xOffset = list->GetWidth() - 1;
            ++from; --to;
            range -= 2.0f;
            minY = 1;
        }
        else {
            frame = target->GetFrame();
        }

        float total = (float) std::max(minY, adapter->GetEntryCount());

        int yOffset;
        if (range >= total) {
            yOffset = -1;
        }
        else {
            float percent = (float) pos.logicalIndex / total;
            yOffset = (int) (range * percent) + minY;
        }

        mvwvline(frame, from, xOffset, 0, to - from);
        mvwaddch(frame, yOffset, xOffset, ' ' | A_REVERSE);
    }
}
<|endoftext|>