<commit_before>#ifndef MANIFOLDS_FUNCTIONS_POLY_COMPOS_SIMPLIFICATIONS_HH
#define MANIFOLDS_FUNCTIONS_POLY_COMPOS_SIMPLIFICATIONS_HH

namespace manifolds {

  template <class A>
  struct Simplification<
    Addition<A,A>, 0,
    typename std::enable_if<
      is_stateless<A>::value>::type>
  {
    typedef Composition<
      Polynomial<double,int_<2>>,
      A> type;
    static type Combine(Addition<A,A> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying addition of function by itself\n";
#endif
      type b = {GetPolynomial(0.0,2.0), A()};
      return b;
    }
  };

  template <class A>
  struct Simplification<
    Multiplication<A,A>, 0,
    typename std::enable_if<is_stateless<A>::value>::type>
  {
    typedef Composition<
      Polynomial<double,int_<3>>,A> type;

    static type Combine(Multiplication<A,A>)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying multiplication of function "
	"by itself\n";
#endif
      return {GetPolynomial(0,0,1), A()};
    }
  };

  template <class Arg1, class Arg2, class ... Args>
  struct Simplification<
    Multiplication<Composition<Arg1, Args...>,
		   Composition<Arg2, Args...>>, 0,
    typename std::enable_if<
      and_<is_stateless<Args>...>::value &&
      (!std::is_same<Arg1,Arg2>::value ||
       !is_stateless<Arg1>::value ||
       !is_stateless<Arg2>::value) &&
      !std::is_same<
	typename Simplification<Multiplication<Arg1,Arg2>>::type,
	Multiplication<Arg1,Arg2>
	>::value>::type>
  {
    typedef Composition<
      typename Simplification<
	Multiplication<Arg1, Arg2>>::type,
      Args...> type;

    static type Combine(Multiplication<Composition<Arg1, Args...>,
			Composition<Arg2, Args...>> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying multipication of composition of "
	"simplifiable functions\n";
#endif
      auto first = std::get<0>(std::get<0>(a.GetFunctions()).
			       GetFunctions());
      auto second = std::get<0>(std::get<1>(a.GetFunctions()).
				GetFunctions());
      Multiplication<decltype(first),decltype(second)>
	m(first,second);
      auto s = Simplify(m);
      return {s, Args()...};
    }
  };

  template <class CType, int order, class T>
  struct Simplification<
    Addition<Composition<
	       Polynomial<CType, int_<order>>, T>, T>, 0,
    typename std::enable_if<is_stateless<T>::value>::type>
  {
    static const int new_order = 2 > order ? 2 : order;
    typedef Composition<Polynomial<CType, int_<new_order>>, T> type;
    template <class A, class B>
      static auto Add(A a, B b)
    {
      return Addition<A,B>(a,b);
    }
    static type Combine(Addition<Composition<
			Polynomial<CType, int_<order>>, T>, T> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying addition of composed polynomial "
	"by inner function\n";
#endif
      auto p = std::get<0>(std::get<0>(a.GetFunctions()).
			   GetFunctions());
      return Simplify(Add(GetPolynomial(0,1), p))(T());
    }
  };

  template <class CType, int order, class T>
  struct Simplification<
    Multiplication<Composition<
		     Polynomial<CType, int_<order>>, T>, T>, 0,
    typename std::enable_if<is_stateless<T>::value>::type>
  {
    static const int new_order = 1 + order;
    typedef Composition<Polynomial<CType, int_<new_order>>, T> type;

    template <class A, class B>
      static auto Mult(A a, B b)
    {
      return Simplify(Multiplication<A,B>(a,b));
    }

    static type Combine(Multiplication<Composition<
			Polynomial<CType, int_<order>>, T>, T> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying multiplication of composed "
	"polynomial by inner function\n";
#endif
      auto m =
	Mult(GetPolynomial(0,1),
	     std::get<0>(std::get<0>
			 (a.GetFunctions()).
			 GetFunctions()));
      T t;
      return m(t);
    }
  };

  template <template <class...>class Variadic,
	    class CType, int order, class T>
  struct Simplification<
    Variadic<T, Composition<
      Polynomial<CType, int_<order>>, T>>, 1,
      typename std::enable_if<is_stateless<T>::value>::type>
  {
    typedef Simplification<
      Variadic<Composition<
		 Polynomial<CType, int_<order>>,
		 T>, T>> ref_type;
    typedef typename ref_type::type type;

    static type Combine(Variadic<T, Composition<
			Polynomial<CType, int_<order>>, T>> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying inverted composed "
	"polynomial operation\n";
#endif
      auto t = a.GetFunctions();
      typedef typename std::remove_reference<
	decltype(std::get<1>(t))>::type T1;
      typedef typename std::remove_reference<
	decltype(std::get<0>(t))>::type T2;
      Variadic<T1, T2> v(std::get<1>(t), std::get<0>(t));
      return ref_type::Combine(v);
    }
  };

  template <class CoeffType,
	    class ... Functions>
  struct Simplification<
    Composition<Polynomial<CoeffType,int_<1>>,Functions...>,0>
  {
    typedef Polynomial<CoeffType,int_<1>> type;

    static type Combine(Composition<Polynomial<
			CoeffType,int_<1>>,Functions...> p)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying composition of "
	"constant polynomial\n";
#endif
      return std::get<0>(p.GetFunctions());
    }
  };

  template <class T, class C>
  struct Simplification<Addition<T, Polynomial<C, int_<1>>>>
  {
    typedef Addition<T, Polynomial<C, int_<1>>> in_type;
    static auto Combine(in_type a)
    {
      auto t = a.GetFunctions();
      return GetPolynomial(std::get<1>(t).GetCoeffs()[0], (C)1)
	(std::get<0>(t));
    }
    typedef decltype(Combine(std::declval<in_type>())) type;
  };
}

#endif
<commit_msg>Simplification of operations on compositions of polynomials and stateless functions<commit_after>#ifndef MANIFOLDS_FUNCTIONS_POLY_COMPOS_SIMPLIFICATIONS_HH
#define MANIFOLDS_FUNCTIONS_POLY_COMPOS_SIMPLIFICATIONS_HH

namespace manifolds {

  template <class A>
  struct Simplification<
    Addition<A,A>, 0,
    typename std::enable_if<
      is_stateless<A>::value>::type>
  {
    typedef Composition<
      Polynomial<double,int_<2>>,
      A> type;
    static type Combine(Addition<A,A> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying addition of function by itself\n";
#endif
      type b = {GetPolynomial(0.0,2.0), A()};
      return b;
    }
  };

  template <class A>
  struct Simplification<
    Multiplication<A,A>, 0,
    typename std::enable_if<is_stateless<A>::value>::type>
  {
    typedef Composition<
      Polynomial<double,int_<3>>,A> type;

    static type Combine(Multiplication<A,A>)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying multiplication of function "
	"by itself\n";
#endif
      return {GetPolynomial(0,0,1), A()};
    }
  };

  template <class Arg1, class Arg2, class ... Args>
  struct Simplification<
    Multiplication<Composition<Arg1, Args...>,
		   Composition<Arg2, Args...>>, 0,
    typename std::enable_if<
      and_<is_stateless<Args>...>::value &&
      (!std::is_same<Arg1,Arg2>::value ||
       !is_stateless<Arg1>::value ||
       !is_stateless<Arg2>::value) &&
      !std::is_same<
	typename Simplification<Multiplication<Arg1,Arg2>>::type,
	Multiplication<Arg1,Arg2>
	>::value>::type>
  {
    typedef Composition<
      typename Simplification<
	Multiplication<Arg1, Arg2>>::type,
      Args...> type;

    static type Combine(Multiplication<Composition<Arg1, Args...>,
			Composition<Arg2, Args...>> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying multipication of composition of "
	"simplifiable functions\n";
#endif
      auto first = std::get<0>(std::get<0>(a.GetFunctions()).
			       GetFunctions());
      auto second = std::get<0>(std::get<1>(a.GetFunctions()).
				GetFunctions());
      Multiplication<decltype(first),decltype(second)>
	m(first,second);
      auto s = Simplify(m);
      return {s, Args()...};
    }
  };

  template <class CType, int order, class T>
  struct Simplification<
    Addition<Composition<
	       Polynomial<CType, int_<order>>, T>, T>, 0,
    typename std::enable_if<is_stateless<T>::value>::type>
  {
    static const int new_order = 2 > order ? 2 : order;
    typedef Composition<Polynomial<CType, int_<new_order>>, T> type;
    template <class A, class B>
      static auto Add(A a, B b)
    {
      return Addition<A,B>(a,b);
    }
    static type Combine(Addition<Composition<
			Polynomial<CType, int_<order>>, T>, T> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying addition of composed polynomial "
	"by inner function\n";
#endif
      auto p = std::get<0>(std::get<0>(a.GetFunctions()).
			   GetFunctions());
      return Simplify(Add(GetPolynomial(0,1), p))(T());
    }
  };

  template <class CType, int order, class T>
  struct Simplification<
    Multiplication<Composition<
		     Polynomial<CType, int_<order>>, T>, T>, 0,
    typename std::enable_if<is_stateless<T>::value>::type>
  {
    static const int new_order = 1 + order;
    typedef Composition<Polynomial<CType, int_<new_order>>, T> type;

    template <class A, class B>
      static auto Mult(A a, B b)
    {
      return Simplify(Multiplication<A,B>(a,b));
    }

    static type Combine(Multiplication<Composition<
			Polynomial<CType, int_<order>>, T>, T> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying multiplication of composed "
	"polynomial by inner function\n";
#endif
      auto m =
	Mult(GetPolynomial(0,1),
	     std::get<0>(std::get<0>
			 (a.GetFunctions()).
			 GetFunctions()));
      T t;
      return m(t);
    }
  };

  template <template <class...>class Variadic,
	    class CType, int order, class T>
  struct Simplification<
    Variadic<T, Composition<
      Polynomial<CType, int_<order>>, T>>, 1,
      typename std::enable_if<is_stateless<T>::value>::type>
  {
    typedef Simplification<
      Variadic<Composition<
		 Polynomial<CType, int_<order>>,
		 T>, T>> ref_type;
    typedef typename ref_type::type type;

    static type Combine(Variadic<T, Composition<
			Polynomial<CType, int_<order>>, T>> a)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying inverted composed "
	"polynomial operation\n";
#endif
      auto t = a.GetFunctions();
      typedef typename std::remove_reference<
	decltype(std::get<1>(t))>::type T1;
      typedef typename std::remove_reference<
	decltype(std::get<0>(t))>::type T2;
      Variadic<T1, T2> v(std::get<1>(t), std::get<0>(t));
      return ref_type::Combine(v);
    }
  };

  template <class CoeffType,
	    class ... Functions>
  struct Simplification<
    Composition<Polynomial<CoeffType,int_<1>>,Functions...>,0>
  {
    typedef Polynomial<CoeffType,int_<1>> type;

    static type Combine(Composition<Polynomial<
			CoeffType,int_<1>>,Functions...> p)
    {
#ifdef PRINT_SIMPLIFIES
      std::cout << "Simplifying composition of "
	"constant polynomial\n";
#endif
      return std::get<0>(p.GetFunctions());
    }
  };

  template <class T, class C>
  struct Simplification<Addition<T, Polynomial<C, int_<1>>>>
  {
    typedef Addition<T, Polynomial<C, int_<1>>> in_type;
    static auto Combine(in_type a)
    {
      auto t = a.GetFunctions();
      return GetPolynomial(std::get<1>(t).GetCoeffs()[0], (C)1)
	(std::get<0>(t));
    }
    typedef decltype(Combine(std::declval<in_type>())) type;
  };

  template <template<class...>class Variadic,
	    class C1, class O1,
	    class C2, class O2,
	    class ... F1s>
  struct Simplification<
    Variadic<Composition<Polynomial<C1,O1>,F1s...>,
	     Composition<Polynomial<C2,O2>,F1s...>>, 1,
    typename std::enable_if<
      is_stateless<Composition<F1s...>>::value>::type>
  {
    typedef Variadic<Polynomial<C1,O2>,
		     Polynomial<C2,O2>> inter_type;
    typedef Composition<
      SimplifiedType<inter_type>,
      F1s...> type;
    static type Combine(Variadic<Composition<
			Polynomial<C1,O1>,F1s...>,
			Composition<
			Polynomial<C2,O2>,F1s...>> v)
    {
      auto t = v.GetFunctions();
      inter_type i(std::get<0>(std::get<0>(t).GetFunctions()),
		   std::get<0>(std::get<1>(t).GetFunctions()));
      return std::make_tuple(Simplify(i), F1s()...);
    }
  };
}

#endif
<|endoftext|>


<commit_before><commit_msg>Reset the default browser choice on windows 10 on install<commit_after><|endoftext|>


<commit_before>#ifndef STATIC_LINK
#define IMPLEMENT_API
#endif

#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
#define NEKO_COMPATIBLE
#endif

#include <hx/CFFI.h>
#include "Extension.h"

using namespace extension;

AutoGCRoot* onEventHandle = 0;

static void extension_set_event_handle(value onEvent) {

	onEventHandle = new AutoGCRoot(onEvent);

}
DEFINE_PRIM(extension_set_event_handle, 1);

extern "C" void sendEvent(int type, const char *data)
{
	value o = alloc_empty_object();
	alloc_field(o,val_id("type"),alloc_int(type));
	alloc_field(o,val_id("data"),alloc_string(data));
	val_call1(onEventHandle->get(), o);
}

static value extension_sample_method (value inputValue) {

	int returnValue = SampleMethod(val_int(inputValue));
	return alloc_int(returnValue);

}
DEFINE_PRIM (extension_sample_method, 1);

static value extension_init_datePicker() {
	bool result = initDatePicker();
	return alloc_bool(result);
}
DEFINE_PRIM (extension_init_datePicker, 0);

void extension_show_datePicker () {
	showDatePicker();
}
DEFINE_PRIM (extension_show_datePicker, 0);

void extension_remove_datePicker () {
	removeDatePicker();
}
DEFINE_PRIM (extension_remove_datePicker, 0);

extern "C" void extension_main () {}
DEFINE_ENTRY_POINT (extension_main);

extern "C" int extension_register_prims () { return 0; }
<commit_msg>Add extension_set_datePickerMode in cpp.<commit_after>#ifndef STATIC_LINK
#define IMPLEMENT_API
#endif

#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
#define NEKO_COMPATIBLE
#endif

#include <hx/CFFI.h>
#include "Extension.h"

using namespace extension;

AutoGCRoot* onEventHandle = 0;

static void extension_set_event_handle(value onEvent) {

	onEventHandle = new AutoGCRoot(onEvent);

}
DEFINE_PRIM(extension_set_event_handle, 1);

extern "C" void sendEvent(int type, const char *data)
{
	value o = alloc_empty_object();
	alloc_field(o,val_id("type"),alloc_int(type));
	alloc_field(o,val_id("data"),alloc_string(data));
	val_call1(onEventHandle->get(), o);
}

static value extension_sample_method (value inputValue) {

	int returnValue = SampleMethod(val_int(inputValue));
	return alloc_int(returnValue);

}
DEFINE_PRIM (extension_sample_method, 1);

static value extension_init_datePicker() {
	bool result = initDatePicker();
	return alloc_bool(result);
}
DEFINE_PRIM (extension_init_datePicker, 0);

void extension_show_datePicker () {
	showDatePicker();
}
DEFINE_PRIM (extension_show_datePicker, 0);

void extension_remove_datePicker () {
	removeDatePicker();
}
DEFINE_PRIM (extension_remove_datePicker, 0);

void extension_set_datePickerMode (value modeValue) {
	setDatePickerMode(val_int(modeValue));
}
DEFINE_PRIM (extension_set_datePickerMode, 1);

extern "C" void extension_main () {}
DEFINE_ENTRY_POINT (extension_main);

extern "C" int extension_register_prims () { return 0; }
<|endoftext|>


<commit_before>#include "OldFile.hpp"
#include <algorithm>
#include <fstream>

OldFile::OldFile(const std::string &name /*= "unknownFile"*/) :
fullPath_(name)
{
}

OldFile::OldFile(const char *name) :
fullPath_(name)
{
}

bool OldFile::exists() const
{
	std::ifstream file(this->fullPath_.c_str());
	bool isOpen = file.is_open();
	if (isOpen)
		file.close();
	return isOpen;
}

const std::string OldFile::getFullName() const
{
	return this->fullPath_;
}

std::string OldFile::getFileName() const
{
	std::string::size_type		pos;
	auto path = fullPath_;

	pos = path.find_last_of("\\/");

	if (pos != std::string::npos)
		return path.substr(pos + 1, std::string::npos);
	else
		return path;
}

std::string OldFile::getFolder() const
{
	std::string::size_type		pos;
	auto path = fullPath_;

	pos = path.find_last_of("\\/");
	if (pos != std::string::npos)
		return path.substr(0, pos + 1);
	else
		return "";
}

std::string OldFile::getShortFileName() const
{
	return this->getFileName().substr(0, this->getFileName().find_last_of("."));
}

std::string OldFile::getExtension() const
{
	std::string::size_type		pos;
	auto path = fullPath_;
	pos = path.find_last_of(".");
	if (pos != std::string::npos)
		return path.substr(pos + 1, std::string::npos);
	else
		return "";
}

std::string OldFile::getFileContent() const
{
	std::ifstream			stream(fullPath_.c_str());

	if (!stream.is_open())
		return "";
	std::string				res;

	res.assign((std::istreambuf_iterator<char>(stream)),
		(std::istreambuf_iterator<char>()));

	return res;
}<commit_msg>Case fixed on old files<commit_after>#include "OldFile.hpp"
#include <algorithm>
#include <fstream>
#include <locale>

OldFile::OldFile(const std::string &name /*= "unknownFile"*/)
{
	std::locale loc;
	std::string tmp(name);
	for (auto &e : tmp)
	{
		fullPath_ += std::tolower(e, loc);
	}
}

OldFile::OldFile(const char *name)
{
	std::locale loc;
	std::string tmp(name);
	for (auto &e : tmp)
	{
		fullPath_ += std::tolower(e, loc);
	}
}

bool OldFile::exists() const
{
	std::ifstream file(this->fullPath_.c_str());
	bool isOpen = file.is_open();
	if (isOpen)
		file.close();
	return isOpen;
}

const std::string OldFile::getFullName() const
{
	return this->fullPath_;
}

std::string OldFile::getFileName() const
{
	std::string::size_type		pos;
	auto path = fullPath_;

	pos = path.find_last_of("\\/");

	if (pos != std::string::npos)
		return path.substr(pos + 1, std::string::npos);
	else
		return path;
}

std::string OldFile::getFolder() const
{
	std::string::size_type		pos;
	auto path = fullPath_;

	pos = path.find_last_of("\\/");
	if (pos != std::string::npos)
		return path.substr(0, pos + 1);
	else
		return "";
}

std::string OldFile::getShortFileName() const
{
	return this->getFileName().substr(0, this->getFileName().find_last_of("."));
}

std::string OldFile::getExtension() const
{
	std::string::size_type		pos;
	auto path = fullPath_;
	pos = path.find_last_of(".");
	if (pos != std::string::npos)
		return path.substr(pos + 1, std::string::npos);
	else
		return "";
}

std::string OldFile::getFileContent() const
{
	std::ifstream			stream(fullPath_.c_str());

	if (!stream.is_open())
		return "";
	std::string				res;

	res.assign((std::istreambuf_iterator<char>(stream)),
		(std::istreambuf_iterator<char>()));

	return res;
}<|endoftext|>


<commit_before>void InitLevel(playerControl *player);
void InitGame(playerControl *player) {//M. Hisyam A
    initScore(player);
    initLives(player);
    player->level = 1;
    InitLevel(player);
}
void GameRoundCheck();

void InitLevel(playerControl *player) { //M. Hisyam A
    switch(player->level) {
        case 1 : CreateMap(level4, player);break;
        case 2 : CreateMap(level2, player);break;
        case 3 : CreateMap(level3, player);break;
    }
}
void ResetPosition(playerControl *player) {//M. Hisyam A
    player->peciman.pos.x = player->peciman.initPos.x;
    player->peciman.pos.y = player->peciman.initPos.y;
    player->ghost1.pos.x = player->ghost1.initPos.x;
    player->ghost1.pos.y = player->ghost1.initPos.y;
    player->ghost2.pos.x = player->ghost2.initPos.x;
    player->ghost2.pos.y = player->ghost2.initPos.y;
    player->ghost3.pos.x = player->ghost3.initPos.x;
    player->ghost3.pos.y = player->ghost3.initPos.y;
    player->ghost4.pos.x = player->ghost4.initPos.x;
    player->ghost4.pos.y = player->ghost4.initPos.y;
}
void GameStart(playerControl *player) { //Hisyam, Fadhit, Fahmi
    clock_t begin;
    clock_t end;
    char choose;
    int time_spent;
    int step = 0;
    char scoreText[20];
    char livesText[20];
    int liveGiven=0;
    char lepel[2];
    Stack path;
    CreateStack(&path);
    int prev[32];
    bfs(20, prev);
    GeneratePath(prev, 20, 0, &path);
    //PrintPath(path);
    while (player->lives>0 && player->level<=3) {
        cleardevice();
        DrawSideMenu();
        settextstyle(8, HORIZ_DIR,1);
        outtextxy(660, 165,player->name);
        ResetPosition(player);
        DrawMap();
        DrawGhost(player->ghost1);
        DrawPacman(player->peciman);
        begin = clock();
        srand(time(NULL));
        PlaySound("sounds/pacman_beginning.wav",NULL,SND_ASYNC);
        printScore(player->score, 660, 285);
        printLives(player->lives, 627, 405);
        sprintf(lepel, "%d", player->level);
        //BlackSquare(24*GRIDSIZE,GRIDSIZE*2.8);
        outtextxy(720,84, lepel);
        while(player->foodCount > 0) {
            if((player->peciman.pos.x==player->ghost1.pos.x) && (player->peciman.pos.y == player->ghost1.pos.y))
                break;
            //printf("%d ",player->foodCount);
            step++;
            if(kbhit())
            {
                choose = getch();
                switch(choose){ // untuk menyimpan direction yang akan dilakukan
                case RIGHTARROW :
                    player->peciman.nextDirection = RIGHT;
                    break;

                case LEFTARROW :
                    player->peciman.nextDirection = LEFT;
                    break;

                case DOWNARROW :
                    player->peciman.nextDirection = DOWN;
                    break;

                case UPARROW :
                     player->peciman.nextDirection = UP;
                    break;

                //case 13: spawnFood(&levelMap[9][12],9,12); break;
                }
            }
            if (step%8 == 0){
                if (CanMovePeciman(player->peciman , player->peciman.nextDirection)) // dicek apakah ada penghalang tembok atau tidak
                {
                    player->peciman.direction = player->peciman.nextDirection; // perubahan arah jika tidak ada tembok
                }
                Move(&player->peciman);
                if(levelMap[player->peciman.pos.x][player->peciman.pos.y].Food != 0){
                    eatFood(player);
                    printScore(player->score, 660, 285);
                    incLives(player, &liveGiven);
                    printLives(player->lives, 627, 405);
                }
                changeState(&player->peciman); // mengubah keadaan pacman dari membuka menjadi tertutup
            }
            if (step%16 == 0) {
                if (Top(path)!=Nil) {
                    if (player->ghost1.pos.x!=nodepos[Info(Top(path))][0] || player->ghost1.pos.y!=nodepos[Info(Top(path))][1]) {
                        GhostAutoMove(&player->ghost1, nodepos[Info(Top(path))]);
                        printf("%d %d %d %d\n", player->ghost1.pos.x,player->ghost1.pos.y, nodepos[Info(Top(path))][0], nodepos[Info(Top(path))][1]);
                        // gotoXY(startX, startY, nodepos[Info(Top(*path))][0], nodepos[Info(Top(*path))][1]);
                    }
                    else {
                        Pop(&path);
                    }
                }
            }
            GetCursorPos(&cursorPosition);
            mX=cursorPosition.x;
            mY=cursorPosition.y;

            if (GetAsyncKeyState(VK_LBUTTON) && mX>=624 && mX<=780 && mY>=550 && mY<=600){
                menuutama();
                break;
            }
            delay(10);
            end = clock();
            time_spent = (int)(end - begin) / CLOCKS_PER_SEC; // Ulah di hapus
            // printf("%d %d %d\n", player->score, player->lives, time_spent);
            if(time_spent==60){
                spawnFood(&levelMap[9][12],9,12);
                begin=clock();
            }
            if((time_spent==20 && (levelMap[9][12].Food==FOOD2 || levelMap[9][12].Food==FOOD3)) || (time_spent==15 && levelMap[9][12].Food==FOOD4) || (time_spent==10 && levelMap[9][12].Food==FOOD5)){
                despawnFood(&levelMap[9][12],9,12);
            }
        }
        if (player->foodCount == 0) {
            printf("Game End");
            player->level++;
            InitLevel(player);
        }
        else {
            PlaySound("sounds/pacman_death.wav",NULL,SND_ASYNC);
            player->lives--;
            delay(1500);
        }

    }
    cleardevice();
    settextstyle(8, HORIZ_DIR,30);
    setcolor(WHITE);
    if (player->lives==0){
        outtext("GAME OVER");
        PlaySound("sounds/pacman_intermission.wav",NULL,SND_ASYNC);
    }
    else{
        outtext("PLAYER WIN");
        PlaySound("sounds/pacman_intermission.wav",NULL,SND_ASYNC);
    }
}
<commit_msg>Add next level 4<commit_after>void InitLevel(playerControl *player);
void InitGame(playerControl *player) {//M. Hisyam A
    initScore(player);
    initLives(player);
    player->level = 1;
    InitLevel(player);
}
void GameRoundCheck();

void InitLevel(playerControl *player) { //M. Hisyam A
    switch(player->level) {
        case 1 : CreateMap(level1, player);break;
        case 2 : CreateMap(level2, player);break;
        case 3 : CreateMap(level3, player);break;
        case 4 : CreateMap(level4, player);break;
    }
}
void ResetPosition(playerControl *player) {//M. Hisyam A
    player->peciman.pos.x = player->peciman.initPos.x;
    player->peciman.pos.y = player->peciman.initPos.y;
    player->ghost1.pos.x = player->ghost1.initPos.x;
    player->ghost1.pos.y = player->ghost1.initPos.y;
    player->ghost2.pos.x = player->ghost2.initPos.x;
    player->ghost2.pos.y = player->ghost2.initPos.y;
    player->ghost3.pos.x = player->ghost3.initPos.x;
    player->ghost3.pos.y = player->ghost3.initPos.y;
    player->ghost4.pos.x = player->ghost4.initPos.x;
    player->ghost4.pos.y = player->ghost4.initPos.y;
}
void GameStart(playerControl *player) { //Hisyam, Fadhit, Fahmi
    clock_t begin;
    clock_t end;
    char choose;
    int time_spent;
    int step = 0;
    char scoreText[20];
    char livesText[20];
    int liveGiven=0;
    char lepel[2];
    Stack path;
    CreateStack(&path);
    int prev[32];
    bfs(20, prev);
    GeneratePath(prev, 20, 0, &path);
    //PrintPath(path);
    while (player->lives>0 && player->level<=3) {
        cleardevice();
        DrawSideMenu();
        settextstyle(8, HORIZ_DIR,1);
        outtextxy(660, 165,player->name);
        ResetPosition(player);
        DrawMap();
        DrawGhost(player->ghost1);
        DrawPacman(player->peciman);
        begin = clock();
        srand(time(NULL));
        PlaySound("sounds/pacman_beginning.wav",NULL,SND_ASYNC);
        printScore(player->score, 660, 285);
        printLives(player->lives, 627, 405);
        sprintf(lepel, "%d", player->level);
        //BlackSquare(24*GRIDSIZE,GRIDSIZE*2.8);
        outtextxy(720,84, lepel);
        while(player->foodCount > 0) {
            if((player->peciman.pos.x==player->ghost1.pos.x) && (player->peciman.pos.y == player->ghost1.pos.y))
                break;
            //printf("%d ",player->foodCount);
            step++;
            if(kbhit())
            {
                choose = getch();
                switch(choose){ // untuk menyimpan direction yang akan dilakukan
                case RIGHTARROW :
                    player->peciman.nextDirection = RIGHT;
                    break;

                case LEFTARROW :
                    player->peciman.nextDirection = LEFT;
                    break;

                case DOWNARROW :
                    player->peciman.nextDirection = DOWN;
                    break;

                case UPARROW :
                     player->peciman.nextDirection = UP;
                    break;

                //case 13: spawnFood(&levelMap[9][12],9,12); break;
                }
            }
            if (step%8 == 0){
                if (CanMovePeciman(player->peciman , player->peciman.nextDirection)) // dicek apakah ada penghalang tembok atau tidak
                {
                    player->peciman.direction = player->peciman.nextDirection; // perubahan arah jika tidak ada tembok
                }
                Move(&player->peciman);
                if(levelMap[player->peciman.pos.x][player->peciman.pos.y].Food != 0){
                    eatFood(player);
                    printScore(player->score, 660, 285);
                    incLives(player, &liveGiven);
                    printLives(player->lives, 627, 405);
                }
                changeState(&player->peciman); // mengubah keadaan pacman dari membuka menjadi tertutup
            }
            if (step%16 == 0) {
                if (Top(path)!=Nil) {
                    if (player->ghost1.pos.x!=nodepos[Info(Top(path))][0] || player->ghost1.pos.y!=nodepos[Info(Top(path))][1]) {
                        GhostAutoMove(&player->ghost1, nodepos[Info(Top(path))]);
                        printf("%d %d %d %d\n", player->ghost1.pos.x,player->ghost1.pos.y, nodepos[Info(Top(path))][0], nodepos[Info(Top(path))][1]);
                        // gotoXY(startX, startY, nodepos[Info(Top(*path))][0], nodepos[Info(Top(*path))][1]);
                    }
                    else {
                        Pop(&path);
                    }
                }
            }
            GetCursorPos(&cursorPosition);
            mX=cursorPosition.x;
            mY=cursorPosition.y;

            if (GetAsyncKeyState(VK_LBUTTON) && mX>=624 && mX<=780 && mY>=550 && mY<=600){
                menuutama();
                break;
            }
            delay(10);
            end = clock();
            time_spent = (int)(end - begin) / CLOCKS_PER_SEC; // Ulah di hapus
            // printf("%d %d %d\n", player->score, player->lives, time_spent);
            if(time_spent==60){
                spawnFood(&levelMap[9][12],9,12);
                begin=clock();
            }
            if((time_spent==20 && (levelMap[9][12].Food==FOOD2 || levelMap[9][12].Food==FOOD3)) || (time_spent==15 && levelMap[9][12].Food==FOOD4) || (time_spent==10 && levelMap[9][12].Food==FOOD5)){
                despawnFood(&levelMap[9][12],9,12);
            }
        }
        if (player->foodCount == 0) {
            printf("Game End");
            player->level++;
            InitLevel(player);
        }
        else {
            PlaySound("sounds/pacman_death.wav",NULL,SND_ASYNC);
            player->lives--;
            delay(1500);
        }

    }
    cleardevice();
    settextstyle(8, HORIZ_DIR,30);
    setcolor(WHITE);
    if (player->lives==0){
        outtext("GAME OVER");
        PlaySound("sounds/pacman_intermission.wav",NULL,SND_ASYNC);
    }
    else{
        outtext("PLAYER WIN");
        PlaySound("sounds/pacman_intermission.wav",NULL,SND_ASYNC);
    }
}
<|endoftext|>


<commit_before>#include "searchresult.h"
#include <QJsonDocument> /// for testing
///TODO: Re-add spotify

/*!
 * \brief This object handles the entire lifecycle of a search.
 * \param query
 */
SearchResult::SearchResult(QString query, QObject *parent) : QObject(parent)
{
    dbRes = new QJsonArray();
    scRes = new QJsonArray();
    spotifyRes = new QJsonArray();
    resultsList = QJsonArray();
    crypto = new SimpleCrypt(Q_UINT64_C(0xb8828ee3d4532131));

    this->query = query;
    qDebug() << "SearchResult object created for" << query;
}

/*!
 * \brief Callback for when local database searches complete.
 *
 * This function receives a QJsonArray that contains the full search results
 * from the local database's search query. It then sets the global dbRes pointer
 * so that the SearchResult object can keep track of these results after the callback
 * completes, and flags the DB_COMPLETE boolean as true.
 *
 * Finally, it checks if all the callbacks have fired, and if it has, constructs
 * the full result.
 * \param obj A pointer to the QJsonArray containing the database's search results.
 */
void SearchResult::onDbSearchComplete(QJsonArray *obj)
{
    qDebug() << "DB search has completed for query" << query;
    if (SEARCH_COMPLETE) {
        qDebug() << "search query already complete; db";
        return;
    }
    dbRes = obj;
    DB_COMPLETE = true;
`    if (SPOTIFY_COMPLETE && SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
        constructFullResult();
    }
//    if (SOUNDCLOUD_COMPLETE && SPOTIFY_COMPLETE) {
//        constructFullResult();
//    }
    if (SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
        constructFullResult();
    }
}

/*!
 * \brief Callback for when SoundCloud searches complete.
 *
 * This function receives a QJsonArray that contains the full search results
 * from SoundCloud's search query. It then sets the global scRes pointer
 * so that the SearchResult object can keep track of these results after the callback
 * completes, and flags the SOUNDCLOUD_COMPLETE boolean as true.
 *
 * Finally, it checks if all the callbacks have fired, and if it has, constructs
 * the full result.
 * \param obj A pointer to the QJsonArray containing the SoundCloud search results.
 */
void SearchResult::onSoundcloudSearchComplete(QJsonArray *obj)
{
    qDebug() << "Soundcloud search has completed for query" << query;
    if (SEARCH_COMPLETE) {
        qDebug() << "search query already complete; soundcloud";
        return;
    }
    scRes = obj;
    SOUNDCLOUD_COMPLETE = true;
        if (SPOTIFY_COMPLETE && SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
            constructFullResult();
        }
//    if (SPOTIFY_COMPLETE && DB_COMPLETE) {
//        constructFullResult();
//    }
}

/*!
 * \brief Callback for when Spotify searches complete.
 *
 * This function receives a QJsonArray that contains the full search results
 * from Spotify's search query. It then sets the global spotifyRes pointer
 * so that the SearchResult object can keep track of these results after the callback
 * completes, and flags the SPOTIFY_COMPLETE boolean as true.
 *
 * Finally, it checks if all the callbacks have fired, and if it has, constructs
 * the full result.
 * \param obj A pointer to the QJsonArray containing the Spotify search results.
 */
void SearchResult::onSpotifySearchComplete(QJsonArray *obj)
{
    qDebug() << "Spotify search has completed for query" << query;
    if (SEARCH_COMPLETE) {
        return;
    }
    spotifyRes = obj;
    SPOTIFY_COMPLETE = true;
        if (SPOTIFY_COMPLETE && SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
            constructFullResult();
        }
//    if (SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
//        constructFullResult();
//    }
}

/*!
 * \brief Appends the input array of json objects into the class's results list.
 *
 * This function takes in an input array of media objects, creates their unique
 * media hashes, and stores the new json object with the hash into the fullResults
 * object for later serialization.
 * \param arr the array of input objects
 * \param type The type of search result. used in generating the hash.
 */
void SearchResult::insertObjectsIntoResults(QJsonArray *arr, SearchResultType type)
{
    QString input;
    QString resType;

    switch(type) {
    case SearchResultType::DB: resType = "db: ";
        break;
    case SearchResultType::SoundCloud: resType = "soundcloud: ";
        break;
    case SearchResultType::Spotify: resType = "spotify: ";
        break;
    }

    for (int i = 0; i < arr->size() ; i++) {
        QJsonValue val = arr->at(i);
        QJsonObject obj1 = val.toObject();

        if (obj1["hash"].isString()) {
            input = obj1["hash"].toString();
        } else if (obj1["hash"].isDouble()) {
            input = QString::number(obj1["hash"].toDouble());
        } else {
            qWarning() << "Object has invalid hash";
            continue;
        }

        QString hash = crypto->encryptToString(resType + input);
        qDebug() << "hashed value is" << hash;
        obj1["hash"] = hash;
        qDebug() << "Inserting object" << QString(QJsonDocument(obj1).toJson());
        resultsList.append(obj1);
    }
}

/*!
 * \brief Return a pointer to the fully generated results object.
 *
 * Used when retrieving cached result.
 * \return
 */
QJsonObject *SearchResult::getSearchResults()
{
    return &fullResult; /// I wonder how memory management works here, probably have
                       /// to store the pointer. Potential static memory leak here,
                       /// check with Valgrind.
}

/*!
 * \brief Constructs the full JSON search result to be sent to the client.
 *
 * It inserts all the search results into the object's fullResults object, then constructs
 * the QJsonObject containing the full search result.
 *
 * Once it finishes all this, it sets the SEARCH_COMPLETE flag to true and emits
 * the searchProcessingComplete() signal for the ClientConnection object.
 */
void SearchResult::constructFullResult()
{
    int i;
    QString hash;

    /// we begin by concatenating the media objects into one big array.
    insertObjectsIntoResults(dbRes, SearchResultType::DB);
    insertObjectsIntoResults(scRes, SearchResultType::SoundCloud);
    insertObjectsIntoResults(spotifyRes, SearchResultType::Spotify);

    /// at this point, we get to build the full object.
    fullResult = QJsonObject
    {
        {"query", query}
    };

    /// \todo Bolster this by splitting everything up into the appropriate
    /// categories.
    QJsonObject results = QJsonObject
    {
        {"number", (resultsList.size())},
    };

    results["results"] = resultsList;

    qDebug() << "full results are" << QJsonDocument(results).toJson();

    fullResult["results"] = results;

    /// at this point, we're done. So we set the SEARCH_COMPLETE flag to true
    /// and (maybe?) emit a signal indicating this to the parent object, so that
    /// it can remove this result from the queue.
    SEARCH_COMPLETE = true;
    emit searchProcessingComplete();
}

/*!
 * \brief Handles destruction of the object in a safe and secure way.
 */
SearchResult::~SearchResult()
{

}

<commit_msg>fixed typo<commit_after>#include "searchresult.h"
#include <QJsonDocument> /// for testing
///TODO: Re-add spotify

/*!
 * \brief This object handles the entire lifecycle of a search.
 * \param query
 */
SearchResult::SearchResult(QString query, QObject *parent) : QObject(parent)
{
    dbRes = new QJsonArray();
    scRes = new QJsonArray();
    spotifyRes = new QJsonArray();
    resultsList = QJsonArray();
    crypto = new SimpleCrypt(Q_UINT64_C(0xb8828ee3d4532131));

    this->query = query;
    qDebug() << "SearchResult object created for" << query;
}

/*!
 * \brief Callback for when local database searches complete.
 *
 * This function receives a QJsonArray that contains the full search results
 * from the local database's search query. It then sets the global dbRes pointer
 * so that the SearchResult object can keep track of these results after the callback
 * completes, and flags the DB_COMPLETE boolean as true.
 *
 * Finally, it checks if all the callbacks have fired, and if it has, constructs
 * the full result.
 * \param obj A pointer to the QJsonArray containing the database's search results.
 */
void SearchResult::onDbSearchComplete(QJsonArray *obj)
{
    qDebug() << "DB search has completed for query" << query;
    if (SEARCH_COMPLETE) {
        qDebug() << "search query already complete; db";
        return;
    }
    dbRes = obj;
    DB_COMPLETE = true;
    if (SPOTIFY_COMPLETE && SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
        constructFullResult();
    }
//    if (SOUNDCLOUD_COMPLETE && SPOTIFY_COMPLETE) {
//        constructFullResult();
//    }
    if (SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
        constructFullResult();
    }
}

/*!
 * \brief Callback for when SoundCloud searches complete.
 *
 * This function receives a QJsonArray that contains the full search results
 * from SoundCloud's search query. It then sets the global scRes pointer
 * so that the SearchResult object can keep track of these results after the callback
 * completes, and flags the SOUNDCLOUD_COMPLETE boolean as true.
 *
 * Finally, it checks if all the callbacks have fired, and if it has, constructs
 * the full result.
 * \param obj A pointer to the QJsonArray containing the SoundCloud search results.
 */
void SearchResult::onSoundcloudSearchComplete(QJsonArray *obj)
{
    qDebug() << "Soundcloud search has completed for query" << query;
    if (SEARCH_COMPLETE) {
        qDebug() << "search query already complete; soundcloud";
        return;
    }
    scRes = obj;
    SOUNDCLOUD_COMPLETE = true;
        if (SPOTIFY_COMPLETE && SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
            constructFullResult();
        }
//    if (SPOTIFY_COMPLETE && DB_COMPLETE) {
//        constructFullResult();
//    }
}

/*!
 * \brief Callback for when Spotify searches complete.
 *
 * This function receives a QJsonArray that contains the full search results
 * from Spotify's search query. It then sets the global spotifyRes pointer
 * so that the SearchResult object can keep track of these results after the callback
 * completes, and flags the SPOTIFY_COMPLETE boolean as true.
 *
 * Finally, it checks if all the callbacks have fired, and if it has, constructs
 * the full result.
 * \param obj A pointer to the QJsonArray containing the Spotify search results.
 */
void SearchResult::onSpotifySearchComplete(QJsonArray *obj)
{
    qDebug() << "Spotify search has completed for query" << query;
    if (SEARCH_COMPLETE) {
        return;
    }
    spotifyRes = obj;
    SPOTIFY_COMPLETE = true;
        if (SPOTIFY_COMPLETE && SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
            constructFullResult();
        }
//    if (SOUNDCLOUD_COMPLETE && DB_COMPLETE) {
//        constructFullResult();
//    }
}

/*!
 * \brief Appends the input array of json objects into the class's results list.
 *
 * This function takes in an input array of media objects, creates their unique
 * media hashes, and stores the new json object with the hash into the fullResults
 * object for later serialization.
 * \param arr the array of input objects
 * \param type The type of search result. used in generating the hash.
 */
void SearchResult::insertObjectsIntoResults(QJsonArray *arr, SearchResultType type)
{
    QString input;
    QString resType;

    switch(type) {
    case SearchResultType::DB: resType = "db: ";
        break;
    case SearchResultType::SoundCloud: resType = "soundcloud: ";
        break;
    case SearchResultType::Spotify: resType = "spotify: ";
        break;
    }

    for (int i = 0; i < arr->size() ; i++) {
        QJsonValue val = arr->at(i);
        QJsonObject obj1 = val.toObject();

        if (obj1["hash"].isString()) {
            input = obj1["hash"].toString();
        } else if (obj1["hash"].isDouble()) {
            input = QString::number(obj1["hash"].toDouble());
        } else {
            qWarning() << "Object has invalid hash";
            continue;
        }

        QString hash = crypto->encryptToString(resType + input);
        qDebug() << "hashed value is" << hash;
        obj1["hash"] = hash;
        qDebug() << "Inserting object" << QString(QJsonDocument(obj1).toJson());
        resultsList.append(obj1);
    }
}

/*!
 * \brief Return a pointer to the fully generated results object.
 *
 * Used when retrieving cached result.
 * \return
 */
QJsonObject *SearchResult::getSearchResults()
{
    return &fullResult; /// I wonder how memory management works here, probably have
                       /// to store the pointer. Potential static memory leak here,
                       /// check with Valgrind.
}

/*!
 * \brief Constructs the full JSON search result to be sent to the client.
 *
 * It inserts all the search results into the object's fullResults object, then constructs
 * the QJsonObject containing the full search result.
 *
 * Once it finishes all this, it sets the SEARCH_COMPLETE flag to true and emits
 * the searchProcessingComplete() signal for the ClientConnection object.
 */
void SearchResult::constructFullResult()
{
    int i;
    QString hash;

    /// we begin by concatenating the media objects into one big array.
    insertObjectsIntoResults(dbRes, SearchResultType::DB);
    insertObjectsIntoResults(scRes, SearchResultType::SoundCloud);
    insertObjectsIntoResults(spotifyRes, SearchResultType::Spotify);

    /// at this point, we get to build the full object.
    fullResult = QJsonObject
    {
        {"query", query}
    };

    /// \todo Bolster this by splitting everything up into the appropriate
    /// categories.
    QJsonObject results = QJsonObject
    {
        {"number", (resultsList.size())},
    };

    results["results"] = resultsList;

    qDebug() << "full results are" << QJsonDocument(results).toJson();

    fullResult["results"] = results;

    /// at this point, we're done. So we set the SEARCH_COMPLETE flag to true
    /// and (maybe?) emit a signal indicating this to the parent object, so that
    /// it can remove this result from the queue.
    SEARCH_COMPLETE = true;
    emit searchProcessingComplete();
}

/*!
 * \brief Handles destruction of the object in a safe and secure way.
 */
SearchResult::~SearchResult()
{

}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <math.h>
#include <thread>
#include <algorithm>
#include <vector>
#include "PO8e.h"

#include "po8e_conf.h" // parse po8e conf files

#define SRATE_HZ	(24414.0625)
#define SRATE_KHZ	(24.4140625)
//#define SRATE_HZ	(48828.1250)
//#define SRATE_KHZ	(48.8281250)
#define NCHAN		96

#define READ_SIZE	100 // po8e block read size

bool	g_die = false;
long double g_startTime = 0.0;
long double gettime()  //in seconds!
{
	timespec pt ;
	clock_gettime(CLOCK_MONOTONIC, &pt);
	long double ret = (long double)(pt.tv_sec) ;
	ret += (long double)(pt.tv_nsec) / 1e9 ;
	return ret - g_startTime;
}

// service the po8e buffer
// 96 channels of spike/lfp, followed by time (ticks) split across two chans
// if there is no po8e card, simulate data with sines

void po8_thread(PO8e *p)
{
	size_t bufmax = 10000;	// must be >= 10000

	printf("Waiting for the stream to start ...\n");
	//p->waitForDataReady(0x3e8);
	while (p->samplesReady() == 0) {
		usleep(5000);
	}

	// start the timer used to compute the speed and set the collected bytes to 0
	//long double starttime = gettime();
	//long long bytes = 0;
	unsigned int frame = 0;

	if (p == nullptr) {
		return;
	}

	auto nchan = p->numChannels();
	auto bps = p->dataSampleSize(); // bytes/sample
	printf("Card %p: %d channels @ %d bytes/sample\n", (void *)p, nchan, bps);

	// 10000 samples * 2 bytes/sample * nChannels
	auto buffs = new short[bufmax*(nchan)];
	auto ticks = new int64_t[bufmax];

	// get the initial tick value. hopefully a small number
	p->readBlock(buffs, 1, ticks);
	int64_t last_tick = ticks[0] - 1;

	while (!g_die) {

		bool stopped = false;
		size_t numSamples = p->samplesReady(&stopped);
		if (stopped) {
			break;
		}

		if (numSamples >= READ_SIZE) {
			if (numSamples > bufmax) {
				printf("samplesReady() returned too many samples (buffer wrap?): %zu\n",
				       numSamples);
				numSamples = bufmax;
			}

			p->readBlock(buffs, READ_SIZE, ticks);
			p->flushBufferedData(READ_SIZE);

			//bytes += READ_SIZE * nchan * bps;

			if (ticks[0] != last_tick + 1) {
				printf("%p: PO8e tick glitch between blocks. Expected %zu got %zu\n",
				       p, last_tick+1, ticks[0]);
			}
			for (int i=0; i<READ_SIZE-1; i++) {
				if (ticks[i+1] != ticks[i] + 1) {
					printf("%p: PO8e tick glitch within block. Expected %zu got %zu\n",
					       p, ticks[i]+1, ticks[i+1]);
				}
			}
			last_tick = ticks[READ_SIZE-1];

			if (frame %200 == 0) { //need to move this to the UI.
				printf("%p: %u samples (%d Bps, %d ch) Last Tick: %zu\n",
				       p, READ_SIZE, bps, nchan, ticks[READ_SIZE-1]);
			}
			frame++;
		}
	}

	// delete buffers since we have dynamically allocated;
	delete[] buffs;
	delete[] ticks;

	printf("  stopped collecting data\n");
	p->stopCollecting();
	printf("  releasing card %p\n", (void *)p);
	PO8e::releaseCard(p);

	printf("\n");
	sleep(1);
}

int main(void)
{
	po8eConf pc;

	pc.loadConf("gtkclient.rc");

	for (size_t i=0; i<pc.cards.size(); i++) {
		printf("card %lu in conf (%d channels)\n",
		       pc.cards[i]->id(),
		       pc.cards[i]->channel_size()
		      );
		for (int j=0; j<pc.cards[i]->channel_size(); j++) {
			auto channel = pc.cards[i]->channel(j);
			printf("  ch: %02lu (%s) scale_factor: %lu data_type: ",
			       channel.id(),
			       channel.name().c_str(),
			       channel.scale_factor());
			switch (channel.data_type()) {
				case po8eChannel::NEURAL:
					printf("NEURAL\n"); break;
				case po8eChannel::EVENT:
					printf("EVENT\n"); break;
				case po8eChannel::ANALOG:
					printf("NEURAL\n"); break;
				case po8eChannel::STIM_PULSES:
					printf("STIM_PULSES\n"); break;
				case po8eChannel::BLANK_CLOCK:
					printf("BLANK_CLOCK\n"); break;
			}
		}
	}

	std::vector <std::thread> threads;
	std::vector <PO8e *> cards;

	printf("PO8e API Version %s\n", revisionString());
	int totalcards = PO8e::cardCount();
	printf("Found %d PO8e card(s) in the system.\n", totalcards);
	if (totalcards < 1) {
		printf("Quitting.\n");
		return 1;
	}

	for (int i=0; i<totalcards; i++) {
		PO8e *p = PO8e::connectToCard(i);
		if (p != nullptr) {
			printf("Connection established to card %d at %p\n", i, (void *)p);
			cards.push_back(p);
		}
	}
	if (cards.size() < 1) {
		printf("Connected to 0 cards. Quitting.\n");
		return 1;
	}

	auto configureCard = [&](PO8e* p) -> bool {
		// return zero on success
		// return one on failure
		if (!p->startCollecting())
		{
			printf("startCollecting() failed with: %d\n", p->getLastError());
			p->flushBufferedData();
			p->stopCollecting();
			printf("Releasing card %p\n", (void *)p);
			PO8e::releaseCard(p);
			return 1;
		}
		printf("Card %p is collecting incoming data.\n", (void *)p);
		return 0;
	};

	cards.erase(std::remove_if(
	                cards.begin(),
	                cards.end(),
	                configureCard),
	            cards.end()
	           );

	for (auto &card : cards) {
		threads.push_back(std::thread(po8_thread, card));
	}

	printf("press enter to quit.\n");
	getchar(); // wait for enter
	g_die = true;

	for (auto &thread : threads) {
		thread.join();
	}

	usleep(4e5);
}
<commit_msg>make pretty<commit_after>#include <stdio.h>
#include <math.h>
#include <thread>
#include <algorithm>
#include <vector>
#include "PO8e.h"

#include "po8e_conf.h" // parse po8e conf files

#define SRATE_HZ	(24414.0625)
#define SRATE_KHZ	(24.4140625)
//#define SRATE_HZ	(48828.1250)
//#define SRATE_KHZ	(48.8281250)
#define NCHAN		96

#define READ_SIZE	100 // po8e block read size

bool	g_die = false;
long double g_startTime = 0.0;
long double gettime()  //in seconds!
{
	timespec pt ;
	clock_gettime(CLOCK_MONOTONIC, &pt);
	long double ret = (long double)(pt.tv_sec) ;
	ret += (long double)(pt.tv_nsec) / 1e9 ;
	return ret - g_startTime;
}

// service the po8e buffer
// 96 channels of spike/lfp, followed by time (ticks) split across two chans
// if there is no po8e card, simulate data with sines

void po8_thread(PO8e *p)
{
	size_t bufmax = 10000;	// must be >= 10000

	printf("Waiting for the stream to start ...\n");
	//p->waitForDataReady(0x3e8);
	while (p->samplesReady() == 0) {
		usleep(5000);
	}

	// start the timer used to compute the speed and set the collected bytes to 0
	//long double starttime = gettime();
	//long long bytes = 0;
	unsigned int frame = 0;

	if (p == nullptr) {
		return;
	}

	auto nchan = p->numChannels();
	auto bps = p->dataSampleSize(); // bytes/sample
	printf("Card %p: %d channels @ %d bytes/sample\n", (void *)p, nchan, bps);

	// 10000 samples * 2 bytes/sample * nChannels
	auto buffs = new short[bufmax*(nchan)];
	auto ticks = new int64_t[bufmax];

	// get the initial tick value. hopefully a small number
	p->readBlock(buffs, 1, ticks);
	int64_t last_tick = ticks[0] - 1;

	while (!g_die) {

		bool stopped = false;
		size_t numSamples = p->samplesReady(&stopped);
		if (stopped) {
			break;
		}

		if (numSamples >= READ_SIZE) {
			if (numSamples > bufmax) {
				printf("samplesReady() returned too many samples (buffer wrap?): %zu\n",
				       numSamples);
				numSamples = bufmax;
			}

			p->readBlock(buffs, READ_SIZE, ticks);
			p->flushBufferedData(READ_SIZE);

			//bytes += READ_SIZE * nchan * bps;

			if (ticks[0] != last_tick + 1) {
				printf("%p: PO8e tick glitch between blocks. Expected %zu got %zu\n",
				       p, last_tick+1, ticks[0]);
			}
			for (int i=0; i<READ_SIZE-1; i++) {
				if (ticks[i+1] != ticks[i] + 1) {
					printf("%p: PO8e tick glitch within block. Expected %zu got %zu\n",
					       p, ticks[i]+1, ticks[i+1]);
				}
			}
			last_tick = ticks[READ_SIZE-1];

			if (frame %200 == 0) { //need to move this to the UI.
				printf("%p: %u samples (%d Bps, %d ch) Last Tick: %zu\n",
				       p, READ_SIZE, bps, nchan, ticks[READ_SIZE-1]);
			}
			frame++;
		}
	}

	// delete buffers since we have dynamically allocated;
	delete[] buffs;
	delete[] ticks;

	printf("  stopped collecting data\n");
	p->stopCollecting();
	printf("  releasing card %p\n", (void *)p);
	PO8e::releaseCard(p);

	printf("\n");
	sleep(1);
}

int main(void)
{
	po8eConf pc;

	pc.loadConf("gtkclient.rc");

	for (size_t i=0; i<pc.cards.size(); i++) {
		printf("card %lu in conf (%d channels)\n",
		       pc.cards[i]->id(),
		       pc.cards[i]->channel_size()
		      );
		for (int j=0; j<pc.cards[i]->channel_size(); j++) {
			auto channel = pc.cards[i]->channel(j);
			printf("  ch: %02lu (%s) scale_factor: %lu data_type: ",
			       channel.id(),
			       channel.name().c_str(),
			       channel.scale_factor());
			switch (channel.data_type()) {
			case po8eChannel::NEURAL:
				printf("NEURAL\n");
				break;
			case po8eChannel::EVENT:
				printf("EVENT\n");
				break;
			case po8eChannel::ANALOG:
				printf("NEURAL\n");
				break;
			case po8eChannel::STIM_PULSES:
				printf("STIM_PULSES\n");
				break;
			case po8eChannel::BLANK_CLOCK:
				printf("BLANK_CLOCK\n");
				break;
			}
		}
	}

	std::vector <std::thread> threads;
	std::vector <PO8e *> cards;

	printf("PO8e API Version %s\n", revisionString());
	int totalcards = PO8e::cardCount();
	printf("Found %d PO8e card(s) in the system.\n", totalcards);
	if (totalcards < 1) {
		printf("Quitting.\n");
		return 1;
	}

	for (int i=0; i<totalcards; i++) {
		PO8e *p = PO8e::connectToCard(i);
		if (p != nullptr) {
			printf("Connection established to card %d at %p\n", i, (void *)p);
			cards.push_back(p);
		}
	}
	if (cards.size() < 1) {
		printf("Connected to 0 cards. Quitting.\n");
		return 1;
	}

	auto configureCard = [&](PO8e* p) -> bool {
		// return zero on success
		// return one on failure
		if (!p->startCollecting())
		{
			printf("startCollecting() failed with: %d\n", p->getLastError());
			p->flushBufferedData();
			p->stopCollecting();
			printf("Releasing card %p\n", (void *)p);
			PO8e::releaseCard(p);
			return 1;
		}
		printf("Card %p is collecting incoming data.\n", (void *)p);
		return 0;
	};

	cards.erase(std::remove_if(
	                cards.begin(),
	                cards.end(),
	                configureCard),
	            cards.end()
	           );

	for (auto &card : cards) {
		threads.push_back(std::thread(po8_thread, card));
	}

	printf("press enter to quit.\n");
	getchar(); // wait for enter
	g_die = true;

	for (auto &thread : threads) {
		thread.join();
	}

	usleep(4e5);
}
<|endoftext|>


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

#ifndef __PROCESS_MIME_HPP__
#define __PROCESS_MIME_HPP__

namespace process {
namespace mime {

extern std::map<std::string, std::string> types;

inline void initialize()
{
  // These MIME types were collected via:
  /*
    python -c '
    import mimetypes
    for extension, type in mimetypes.types_map.iteritems():
      print "types[\"%s\"] = \"%s\";" % (extension, type)
    '
  */

  types[".obj"] = "application/octet-stream";
  types[".ra"] = "audio/x-pn-realaudio";
  types[".wsdl"] = "application/xml";
  types[".dll"] = "application/octet-stream";
  types[".ras"] = "image/x-cmu-raster";
  types[".ram"] = "application/x-pn-realaudio";
  types[".bcpio"] = "application/x-bcpio";
  types[".sh"] = "application/x-sh";
  types[".m1v"] = "video/mpeg";
  types[".xwd"] = "image/x-xwindowdump";
  types[".doc"] = "application/msword";
  types[".bmp"] = "image/x-ms-bmp";
  types[".shar"] = "application/x-shar";
  types[".js"] = "application/x-javascript";
  types[".src"] = "application/x-wais-source";
  types[".dvi"] = "application/x-dvi";
  types[".aif"] = "audio/x-aiff";
  types[".ksh"] = "text/plain";
  types[".dot"] = "application/msword";
  types[".mht"] = "message/rfc822";
  types[".p12"] = "application/x-pkcs12";
  types[".css"] = "text/css";
  types[".csh"] = "application/x-csh";
  types[".pwz"] = "application/vnd.ms-powerpoint";
  types[".pdf"] = "application/pdf";
  types[".cdf"] = "application/x-netcdf";
  types[".pl"] = "text/plain";
  types[".ai"] = "application/postscript";
  types[".jpe"] = "image/jpeg";
  types[".jpg"] = "image/jpeg";
  types[".py"] = "text/x-python";
  types[".xml"] = "text/xml";
  types[".jpeg"] = "image/jpeg";
  types[".ps"] = "application/postscript";
  types[".gtar"] = "application/x-gtar";
  types[".xpm"] = "image/x-xpixmap";
  types[".hdf"] = "application/x-hdf";
  types[".nws"] = "message/rfc822";
  types[".tsv"] = "text/tab-separated-values";
  types[".xpdl"] = "application/xml";
  types[".p7c"] = "application/pkcs7-mime";
  types[".eps"] = "application/postscript";
  types[".ief"] = "image/ief";
  types[".so"] = "application/octet-stream";
  types[".xlb"] = "application/vnd.ms-excel";
  types[".pbm"] = "image/x-portable-bitmap";
  types[".texinfo"] = "application/x-texinfo";
  types[".xls"] = "application/vnd.ms-excel";
  types[".tex"] = "application/x-tex";
  types[".rtx"] = "text/richtext";
  types[".html"] = "text/html";
  types[".aiff"] = "audio/x-aiff";
  types[".aifc"] = "audio/x-aiff";
  types[".exe"] = "application/octet-stream";
  types[".sgm"] = "text/x-sgml";
  types[".tif"] = "image/tiff";
  types[".mpeg"] = "video/mpeg";
  types[".ustar"] = "application/x-ustar";
  types[".gif"] = "image/gif";
  types[".ppt"] = "application/vnd.ms-powerpoint";
  types[".pps"] = "application/vnd.ms-powerpoint";
  types[".sgml"] = "text/x-sgml";
  types[".ppm"] = "image/x-portable-pixmap";
  types[".latex"] = "application/x-latex";
  types[".bat"] = "text/plain";
  types[".mov"] = "video/quicktime";
  types[".ppa"] = "application/vnd.ms-powerpoint";
  types[".tr"] = "application/x-troff";
  types[".rdf"] = "application/xml";
  types[".xsl"] = "application/xml";
  types[".eml"] = "message/rfc822";
  types[".nc"] = "application/x-netcdf";
  types[".sv4cpio"] = "application/x-sv4cpio";
  types[".bin"] = "application/octet-stream";
  types[".h"] = "text/plain";
  types[".tcl"] = "application/x-tcl";
  types[".wiz"] = "application/msword";
  types[".o"] = "application/octet-stream";
  types[".a"] = "application/octet-stream";
  types[".c"] = "text/plain";
  types[".wav"] = "audio/x-wav";
  types[".vcf"] = "text/x-vcard";
  types[".xbm"] = "image/x-xbitmap";
  types[".txt"] = "text/plain";
  types[".au"] = "audio/basic";
  types[".t"] = "application/x-troff";
  types[".tiff"] = "image/tiff";
  types[".texi"] = "application/x-texinfo";
  types[".oda"] = "application/oda";
  types[".ms"] = "application/x-troff-ms";
  types[".rgb"] = "image/x-rgb";
  types[".me"] = "application/x-troff-me";
  types[".sv4crc"] = "application/x-sv4crc";
  types[".qt"] = "video/quicktime";
  types[".mpa"] = "video/mpeg";
  types[".mpg"] = "video/mpeg";
  types[".mpe"] = "video/mpeg";
  types[".avi"] = "video/x-msvideo";
  types[".pgm"] = "image/x-portable-graymap";
  types[".pot"] = "application/vnd.ms-powerpoint";
  types[".mif"] = "application/x-mif";
  types[".roff"] = "application/x-troff";
  types[".htm"] = "text/html";
  types[".man"] = "application/x-troff-man";
  types[".etx"] = "text/x-setext";
  types[".zip"] = "application/zip";
  types[".movie"] = "video/x-sgi-movie";
  types[".pyc"] = "application/x-python-code";
  types[".png"] = "image/png";
  types[".pfx"] = "application/x-pkcs12";
  types[".mhtml"] = "message/rfc822";
  types[".tar"] = "application/x-tar";
  types[".pnm"] = "image/x-portable-anymap";
  types[".pyo"] = "application/x-python-code";
  types[".snd"] = "audio/basic";
  types[".cpio"] = "application/x-cpio";
  types[".swf"] = "application/x-shockwave-flash";
  types[".mp3"] = "audio/mpeg";
  types[".mp2"] = "audio/mpeg";
  types[".mp4"] = "video/mp4";
}

} // } namespace mime {
} // } namespace process {

#endif // __PROCESS_MIME_HPP__
<commit_msg>Process: Added headers to make `process/mime.hpp` standalone.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

#ifndef __PROCESS_MIME_HPP__
#define __PROCESS_MIME_HPP__

#include <map>
#include <string>

namespace process {
namespace mime {

extern std::map<std::string, std::string> types;

inline void initialize()
{
  // These MIME types were collected via:
  /*
    python -c '
    import mimetypes
    for extension, type in mimetypes.types_map.iteritems():
      print "types[\"%s\"] = \"%s\";" % (extension, type)
    '
  */

  types[".obj"] = "application/octet-stream";
  types[".ra"] = "audio/x-pn-realaudio";
  types[".wsdl"] = "application/xml";
  types[".dll"] = "application/octet-stream";
  types[".ras"] = "image/x-cmu-raster";
  types[".ram"] = "application/x-pn-realaudio";
  types[".bcpio"] = "application/x-bcpio";
  types[".sh"] = "application/x-sh";
  types[".m1v"] = "video/mpeg";
  types[".xwd"] = "image/x-xwindowdump";
  types[".doc"] = "application/msword";
  types[".bmp"] = "image/x-ms-bmp";
  types[".shar"] = "application/x-shar";
  types[".js"] = "application/x-javascript";
  types[".src"] = "application/x-wais-source";
  types[".dvi"] = "application/x-dvi";
  types[".aif"] = "audio/x-aiff";
  types[".ksh"] = "text/plain";
  types[".dot"] = "application/msword";
  types[".mht"] = "message/rfc822";
  types[".p12"] = "application/x-pkcs12";
  types[".css"] = "text/css";
  types[".csh"] = "application/x-csh";
  types[".pwz"] = "application/vnd.ms-powerpoint";
  types[".pdf"] = "application/pdf";
  types[".cdf"] = "application/x-netcdf";
  types[".pl"] = "text/plain";
  types[".ai"] = "application/postscript";
  types[".jpe"] = "image/jpeg";
  types[".jpg"] = "image/jpeg";
  types[".py"] = "text/x-python";
  types[".xml"] = "text/xml";
  types[".jpeg"] = "image/jpeg";
  types[".ps"] = "application/postscript";
  types[".gtar"] = "application/x-gtar";
  types[".xpm"] = "image/x-xpixmap";
  types[".hdf"] = "application/x-hdf";
  types[".nws"] = "message/rfc822";
  types[".tsv"] = "text/tab-separated-values";
  types[".xpdl"] = "application/xml";
  types[".p7c"] = "application/pkcs7-mime";
  types[".eps"] = "application/postscript";
  types[".ief"] = "image/ief";
  types[".so"] = "application/octet-stream";
  types[".xlb"] = "application/vnd.ms-excel";
  types[".pbm"] = "image/x-portable-bitmap";
  types[".texinfo"] = "application/x-texinfo";
  types[".xls"] = "application/vnd.ms-excel";
  types[".tex"] = "application/x-tex";
  types[".rtx"] = "text/richtext";
  types[".html"] = "text/html";
  types[".aiff"] = "audio/x-aiff";
  types[".aifc"] = "audio/x-aiff";
  types[".exe"] = "application/octet-stream";
  types[".sgm"] = "text/x-sgml";
  types[".tif"] = "image/tiff";
  types[".mpeg"] = "video/mpeg";
  types[".ustar"] = "application/x-ustar";
  types[".gif"] = "image/gif";
  types[".ppt"] = "application/vnd.ms-powerpoint";
  types[".pps"] = "application/vnd.ms-powerpoint";
  types[".sgml"] = "text/x-sgml";
  types[".ppm"] = "image/x-portable-pixmap";
  types[".latex"] = "application/x-latex";
  types[".bat"] = "text/plain";
  types[".mov"] = "video/quicktime";
  types[".ppa"] = "application/vnd.ms-powerpoint";
  types[".tr"] = "application/x-troff";
  types[".rdf"] = "application/xml";
  types[".xsl"] = "application/xml";
  types[".eml"] = "message/rfc822";
  types[".nc"] = "application/x-netcdf";
  types[".sv4cpio"] = "application/x-sv4cpio";
  types[".bin"] = "application/octet-stream";
  types[".h"] = "text/plain";
  types[".tcl"] = "application/x-tcl";
  types[".wiz"] = "application/msword";
  types[".o"] = "application/octet-stream";
  types[".a"] = "application/octet-stream";
  types[".c"] = "text/plain";
  types[".wav"] = "audio/x-wav";
  types[".vcf"] = "text/x-vcard";
  types[".xbm"] = "image/x-xbitmap";
  types[".txt"] = "text/plain";
  types[".au"] = "audio/basic";
  types[".t"] = "application/x-troff";
  types[".tiff"] = "image/tiff";
  types[".texi"] = "application/x-texinfo";
  types[".oda"] = "application/oda";
  types[".ms"] = "application/x-troff-ms";
  types[".rgb"] = "image/x-rgb";
  types[".me"] = "application/x-troff-me";
  types[".sv4crc"] = "application/x-sv4crc";
  types[".qt"] = "video/quicktime";
  types[".mpa"] = "video/mpeg";
  types[".mpg"] = "video/mpeg";
  types[".mpe"] = "video/mpeg";
  types[".avi"] = "video/x-msvideo";
  types[".pgm"] = "image/x-portable-graymap";
  types[".pot"] = "application/vnd.ms-powerpoint";
  types[".mif"] = "application/x-mif";
  types[".roff"] = "application/x-troff";
  types[".htm"] = "text/html";
  types[".man"] = "application/x-troff-man";
  types[".etx"] = "text/x-setext";
  types[".zip"] = "application/zip";
  types[".movie"] = "video/x-sgi-movie";
  types[".pyc"] = "application/x-python-code";
  types[".png"] = "image/png";
  types[".pfx"] = "application/x-pkcs12";
  types[".mhtml"] = "message/rfc822";
  types[".tar"] = "application/x-tar";
  types[".pnm"] = "image/x-portable-anymap";
  types[".pyo"] = "application/x-python-code";
  types[".snd"] = "audio/basic";
  types[".cpio"] = "application/x-cpio";
  types[".swf"] = "application/x-shockwave-flash";
  types[".mp3"] = "audio/mpeg";
  types[".mp2"] = "audio/mpeg";
  types[".mp4"] = "video/mp4";
}

} // } namespace mime {
} // } namespace process {

#endif // __PROCESS_MIME_HPP__
<|endoftext|>


<commit_before>// Scene tool

#include "sceneTool.hh"
#include "sceneOpCodes.hh"
#include "sceneOpCodeNames.hh"

#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>

#include <sstream>
#include <fstream>
#include <cstring>

uint16_t read16(std::ifstream& input) {
    uint16_t data;
    input.read((char*)&data, (int)sizeof(data));
    return data;
}

uint32_t read32(std::ifstream& input) {
    uint32_t data;
    input.read((char*)&data, (int)sizeof(data));
    return data;
}

uint64_t read64(std::ifstream& input) {
    uint64_t data;
    input.read((char*)&data, (int)sizeof(data));
    return data;
}

// Checksum reverse by weaknespase
uint32_t checksum(const char* in, const uint32_t length, int last = 0){
    const char* end = in + length;
    int acc = last;
    while (in < end)
        acc = (acc * 33) ^ (unsigned char) *in++;
    return acc;
}

#define read_elem(fh, elem) fh.read((char*)&elem, (int)sizeof(elem))

void process_segment( std::ifstream& fh, SEGMENT_HEADER& segHead );

void print_hex(uint8_t *data, uint32_t size)
{
    for (uint32_t i = 0; i < size; ++i) {
        std::cout << " " << std::hex << std::setfill('0') << std::setw(2)
    		<< (int)data[i] << std::dec;
    }
}

int main(int argc, char *argv[])
{
    if ( argc < 2 ) {
        std::cerr << "Usage : " << argv[0] << " <script>" << std::endl;
        return -1;
    }

    std::string iPath = argv[1];

    std::ifstream iFile( iPath.c_str(), std::ios_base::binary );

    if ( !iFile.is_open() )
        return -2;

    FILE_HEADER_V2 headerV2;
    read_elem( iFile, headerV2 );

    SEGMENT_HEADER segHeads[ headerV2.segs_count ];
    read_elem( iFile, segHeads );

    for ( int i = 0; i < headerV2.segs_count; i++ ) {
        process_segment( iFile, segHeads[i] );
    }

    iFile.close();

    return 0;
}

inline bool isJapOpCode( uint16_t code )
{
	return (0x8000 <= code && code <= 0x8181);
}

inline bool isOpCode( uint16_t code )
{
	return (0x8000 <= code && code <= 0x8182);
}

void process_segment( std::ifstream& fh, SEGMENT_HEADER& segHead )
{
	fh.seekg( segHead.offset );

	uint32_t size = segHead.size;
	char *segment = (char*)malloc( size );

	fh.read( segment, size );

	std::cout << std::endl;
	std::cout << "0x" << std::hex << (int)segHead.offset << std::dec << std::endl;
	std::cout << segHead.name << std::endl;
	std::cout << "Size : 0x" << std::hex << (int)segHead.size << std::dec << std::endl;

	char *pSeg = segment, *pEnd = segment + size;

	while ( pSeg < (pEnd-1) ) {

		OpCode opcode = (OpCode)*((uint16_t*)pSeg);

		if ( !isOpCode( opcode ) ) {
			std::cerr << std::endl << "ERROR : bad opcode 0x"
				<< std::hex << (int)opcode
				<< " at offset 0x" << (pSeg - segment + segHead.offset)
				<< std::dec;
			// return;
		}

		else if ( !isJapOpCode( opcode ) ) {
			std::cerr << std::endl << "WARNING : unsupported english opcode 0x"
				<< std::hex << (int)opcode
				<< " at offset 0x" << (pSeg - segment + segHead.offset)
				<< std::dec;
			// return;
		}

		std::cout << std::endl << "0x" << std::hex << std::setfill('0') << std::setw(4)
			<< (int)(pSeg - segment) << ": "
			<< std::dec;

		uint32_t opcode_idx = opcode - OPCODE_exit;
		std::string opcode_name;

		if ( opcode_idx < sizeof(opCodeNames)/sizeof(char*) ) {
			opcode_name = opCodeNames[ opcode_idx ];
			std::cout << opcode_name;
		}
		else {
			std::cout << std::hex << "0x" << opcode << std::dec;
		}

		// std::cerr << std::endl << "pSeg = " << std::hex << (int)pSeg << std::dec;
		pSeg += sizeof(uint16_t);
		// std::cerr << std::endl << "sizeof(uint16_t) = " << sizeof(uint16_t);
		// std::cerr << std::endl << "pSeg = " << std::hex << (int)pSeg << std::dec;
		// std::cerr << std::endl << "opcode = " << std::hex << (int)opcode << std::dec;

		// if ( opcode == OPCODE_exit ) {
		// 	std::cout << std::endl;
		// 	return;
		// }

		bool is_opcode = false;
		uint16_t nargs = 0;

		while ( !is_opcode && (pSeg < (pEnd-1)) ) {

			const char *pArg = pSeg;
			GENERIC_ARG arg = *((GENERIC_ARG*)pSeg);
			DataTag tag = (DataTag)arg.tag;
			is_opcode = isOpCode( tag );
			uint32_t tag_val;

			if ( is_opcode || ++nargs >= 16 ) {
				// std::cerr << std::endl << "New OPCODE detected";
				break;
			}

			else {
				// std::cerr << "New ARG detected" << std::endl;
				// pSeg += sizeof(uint16_t);

				// tag_val = *((uint32_t*)pSeg);
				// pSeg += sizeof(uint32_t);

				pSeg += sizeof(GENERIC_ARG);

				// std::cout << " ";
			}

			// std::cerr << "Switch ARG" << std::endl;

			switch ( tag ) {

			case INT_TAG:
				std::cout << ", #" << arg.iVal;
				break;

			case FLOAT_TAG:
				std::cout << ", f" << arg.fVal;
				break;

			case STRING_TAG: {
				std::cout << ", s\"";
				// std::cout << ", "<<arg.uVal<<"\"";

				uint32_t len = arg.uVal;
				char data[len+1];

				strncpy(data, pSeg, len);
				data[len] = 0;
				pSeg += len;

				// TODO : find unambiguous string delimiters
				std::cout << data << "\""; }
				break;

			case POPUP_TAG: {
				std::cout << ", popup (" << arg.uVal << ":";

				POPUP_ARG popup = *(POPUP_ARG*)pArg;
				uint32_t nLines = popup.nLines;
				uint32_t len = popup.len;
				pSeg += sizeof(uint32_t);

				uint32_t args[ nLines ];

				for (uint32_t i = 0; i < nLines; i++) {
					args[i] = *((uint32_t*)pSeg);
					pSeg += sizeof(uint32_t);

					std::cout << args[i] << ";";
				}

				std::cout << " \"";

				char data[len+1];

				strncpy(data, pSeg, len);
				data[len] = 0;
				pSeg += len;

				// TODO : find unambiguous string delimiters
				std::cout << data << "\")"; }
				break;

			case UNK0_TAG: {
				std::cout << ", o";

				uint32_t count = arg.uVal;

				// if ( count != 8 ) {
				// 	std::cerr << std::endl << "WARNING : 0x82E0 ARG size = " << count;
				// }

				if ( count > (pEnd - pSeg) ) {
					std::cerr << std::endl << "FATAL ERROR, segment aborted";
					std::cout << std::endl << "FATAL ERROR, segment aborted";
					return;
				}

				print_hex((uint8_t*)pSeg, count);

				pSeg += count; }
				break;

			default:
				std::cerr << std::endl
					<< "ERROR : Unknown argument 0x" << std::hex << (int)tag
					<< " at offset 0x" << (pArg - segment + segHead.offset)
					<< std::dec << ", stopping argument parsing";

				is_opcode = true;
				pSeg = (char*)pArg;
				break;

				// std::cout << ", " << std::hex << "0x" << (int)tag << " : 0x" << arg.uVal << std::dec;
				// break;
			}
		}
	}

	std::cout << std::endl;
}
<commit_msg>Added header magic check<commit_after>// Scene tool

#include "sceneTool.hh"
#include "sceneOpCodes.hh"
#include "sceneOpCodeNames.hh"

#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>

#include <sstream>
#include <fstream>
#include <cstring>

uint16_t read16(std::ifstream& input) {
    uint16_t data;
    input.read((char*)&data, (int)sizeof(data));
    return data;
}

uint32_t read32(std::ifstream& input) {
    uint32_t data;
    input.read((char*)&data, (int)sizeof(data));
    return data;
}

uint64_t read64(std::ifstream& input) {
    uint64_t data;
    input.read((char*)&data, (int)sizeof(data));
    return data;
}

// Checksum reverse by weaknespase
uint32_t checksum(const char* in, const uint32_t length, int last = 0){
    const char* end = in + length;
    int acc = last;
    while (in < end)
        acc = (acc * 33) ^ (unsigned char) *in++;
    return acc;
}

#define read_elem(fh, elem) fh.read((char*)&elem, (int)sizeof(elem))

void process_segment( std::ifstream& fh, SEGMENT_HEADER& segHead );

void print_hex(uint8_t *data, uint32_t size)
{
    for (uint32_t i = 0; i < size; ++i) {
        std::cout << " " << std::hex << std::setfill('0') << std::setw(2)
    		<< (int)data[i] << std::dec;
    }
}

int main(int argc, char *argv[])
{
    if ( argc < 2 ) {
        std::cerr << "Usage : " << argv[0] << " <script>" << std::endl;
        return -1;
    }

    std::string iPath = argv[1];

    std::ifstream iFile( iPath.c_str(), std::ios_base::binary );

    if ( !iFile.is_open() ) {
    	std::cerr << iPath << " not found" << std::endl;
        return -2;
    }

    FILE_HEADER_V2 headerV2;
    read_elem( iFile, headerV2 );

    if ( strncmp( headerV2.magic, "YS7_SCP", 8 ) ) {
        std::cerr << "Invalid input file" << std::endl;
        iFile.close();
        return 1;
    }

    SEGMENT_HEADER segHeads[ headerV2.segs_count ];
    read_elem( iFile, segHeads );

    for ( int i = 0; i < headerV2.segs_count; i++ ) {
        process_segment( iFile, segHeads[i] );
    }

    iFile.close();

    return 0;
}

inline bool isJapOpCode( uint16_t code )
{
	return (0x8000 <= code && code <= 0x8181);
}

inline bool isOpCode( uint16_t code )
{
	return (0x8000 <= code && code <= 0x8182);
}

void process_segment( std::ifstream& fh, SEGMENT_HEADER& segHead )
{
	fh.seekg( segHead.offset );

	uint32_t size = segHead.size;
	char *segment = (char*)malloc( size );

	fh.read( segment, size );

	std::cout << std::endl;
	std::cout << "0x" << std::hex << (int)segHead.offset << std::dec << std::endl;
	std::cout << segHead.name << std::endl;
	std::cout << "Size : 0x" << std::hex << (int)segHead.size << std::dec << std::endl;

	char *pSeg = segment, *pEnd = segment + size;

	while ( pSeg < (pEnd-1) ) {

		OpCode opcode = (OpCode)*((uint16_t*)pSeg);

		if ( !isOpCode( opcode ) ) {
			std::cerr << std::endl << "ERROR : bad opcode 0x"
				<< std::hex << (int)opcode
				<< " at offset 0x" << (pSeg - segment + segHead.offset)
				<< std::dec;
			// return;
		}

		else if ( !isJapOpCode( opcode ) ) {
			std::cerr << std::endl << "WARNING : unsupported english opcode 0x"
				<< std::hex << (int)opcode
				<< " at offset 0x" << (pSeg - segment + segHead.offset)
				<< std::dec;
			// return;
		}

		std::cout << std::endl << "0x" << std::hex << std::setfill('0') << std::setw(4)
			<< (int)(pSeg - segment) << ": "
			<< std::dec;

		uint32_t opcode_idx = opcode - OPCODE_exit;
		std::string opcode_name;

		if ( opcode_idx < sizeof(opCodeNames)/sizeof(char*) ) {
			opcode_name = opCodeNames[ opcode_idx ];
			std::cout << opcode_name;
		}
		else {
			std::cout << std::hex << "0x" << opcode << std::dec;
		}

		// std::cerr << std::endl << "pSeg = " << std::hex << (int)pSeg << std::dec;
		pSeg += sizeof(uint16_t);
		// std::cerr << std::endl << "sizeof(uint16_t) = " << sizeof(uint16_t);
		// std::cerr << std::endl << "pSeg = " << std::hex << (int)pSeg << std::dec;
		// std::cerr << std::endl << "opcode = " << std::hex << (int)opcode << std::dec;

		// if ( opcode == OPCODE_exit ) {
		// 	std::cout << std::endl;
		// 	return;
		// }

		bool is_opcode = false;
		uint16_t nargs = 0;

		while ( !is_opcode && (pSeg < (pEnd-1)) ) {

			const char *pArg = pSeg;
			GENERIC_ARG arg = *((GENERIC_ARG*)pSeg);
			DataTag tag = (DataTag)arg.tag;
			is_opcode = isOpCode( tag );
			uint32_t tag_val;

			if ( is_opcode || ++nargs >= 16 ) {
				// std::cerr << std::endl << "New OPCODE detected";
				break;
			}

			else {
				// std::cerr << "New ARG detected" << std::endl;
				// pSeg += sizeof(uint16_t);

				// tag_val = *((uint32_t*)pSeg);
				// pSeg += sizeof(uint32_t);

				pSeg += sizeof(GENERIC_ARG);

				// std::cout << " ";
			}

			// std::cerr << "Switch ARG" << std::endl;

			switch ( tag ) {

			case INT_TAG:
				std::cout << ", #" << arg.iVal;
				break;

			case FLOAT_TAG:
				std::cout << ", f" << arg.fVal;
				break;

			case STRING_TAG: {
				std::cout << ", s\"";
				// std::cout << ", "<<arg.uVal<<"\"";

				uint32_t len = arg.uVal;
				char data[len+1];

				strncpy(data, pSeg, len);
				data[len] = 0;
				pSeg += len;

				// TODO : find unambiguous string delimiters
				std::cout << data << "\""; }
				break;

			case POPUP_TAG: {
				std::cout << ", popup (" << arg.uVal << ":";

				POPUP_ARG popup = *(POPUP_ARG*)pArg;
				uint32_t nLines = popup.nLines;
				uint32_t len = popup.len;
				pSeg += sizeof(uint32_t);

				uint32_t args[ nLines ];

				for (uint32_t i = 0; i < nLines; i++) {
					args[i] = *((uint32_t*)pSeg);
					pSeg += sizeof(uint32_t);

					std::cout << args[i] << ";";
				}

				std::cout << " \"";

				char data[len+1];

				strncpy(data, pSeg, len);
				data[len] = 0;
				pSeg += len;

				// TODO : find unambiguous string delimiters
				std::cout << data << "\")"; }
				break;

			case UNK0_TAG: {
				std::cout << ", o";

				uint32_t count = arg.uVal;

				// if ( count != 8 ) {
				// 	std::cerr << std::endl << "WARNING : 0x82E0 ARG size = " << count;
				// }

				if ( count > (pEnd - pSeg) ) {
					std::cerr << std::endl << "FATAL ERROR, segment aborted";
					std::cout << std::endl << "FATAL ERROR, segment aborted";
					return;
				}

				print_hex((uint8_t*)pSeg, count);

				pSeg += count; }
				break;

			default:
				std::cerr << std::endl
					<< "ERROR : Unknown argument 0x" << std::hex << (int)tag
					<< " at offset 0x" << (pArg - segment + segHead.offset)
					<< std::dec << ", stopping argument parsing";

				is_opcode = true;
				pSeg = (char*)pArg;
				break;

				// std::cout << ", " << std::hex << "0x" << (int)tag << " : 0x" << arg.uVal << std::dec;
				// break;
			}
		}
	}

	std::cout << std::endl;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Rhys Ulerich
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef DESCENDU_SEXP_HPP
#define DESCENDU_SEXP_HPP

#include <cctype>
#include <iostream>
#include <iterator>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>

namespace descendu {

namespace sexp {

// TODO Track line/column as input processed
// TODO Record line/column within each node

enum struct node_type { list=1, symbol, string };

// switch (node.type) {
//     case node_type::list:    /* Use list-like methods */ break;
//     case node_type::symbol:  /* Use node.string */       break;
//     case node_type::string:  /* Use node.string */       break;
// }
class node : std::vector<node>
{
    typedef std::vector<node> base_type;

public:

    // Discern which type of data is contained.
    node_type type;

    // For string node access
    std::string string;

    // For list node access
    using base_type::back;
    using base_type::begin;
    using base_type::cbegin;
    using base_type::cend;
    using base_type::emplace_back;
    using base_type::end;
    using base_type::front;
    using base_type::operator[];
    using base_type::pop_back;
    using base_type::size;

    // Construct a string node
    explicit node(const std::string& s, const bool is_symbol = true)
        : base_type(0)
        , type(is_symbol ? node_type::symbol : node_type::string)
        , string(s)
    {};

    // Move into a string node
    explicit node(std::string&& s, const bool is_symbol = true)
        : base_type(0)
        , type(is_symbol ? node_type::symbol : node_type::string)
        , string(s)
    {};

    // Construct an empty list node
    node()
        : base_type()
        , type(node_type::list)
        , string()
    {};
};

namespace impl {

// Helper to process C99 and S-expression escapes for parse(...) just below
template<typename InputIt>
std::string& append_maybe_escaped(
    const char c,
    std::string &acc,  // Reference!
    InputIt& next,     // Reference!
    InputIt end,
    const bool quoted)
{
    if (c != '\\') return acc += c;
    if (next == end) throw std::invalid_argument("backslash precedes EOF");
    const char q = *next++;
    switch (q) {
    case 'a': return acc += '\a';
    case 'b': return acc += '\b';
    case 'f': return acc += '\f';
    case 'n': return acc += '\n';
    case 'r': return acc += '\r';
    case 't': return acc += '\t';
    case 'v': return acc += '\v';
    case '\'':
    case '"':
    case '?': return acc += q;
    case 'x':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        throw new std::logic_error("Escaping via numeric codes unimplemented");
    case '(': case ')': if (!quoted) return acc += q;  // Possibly fall through
    }
    throw new std::invalid_argument(std::string("Improper escape \\" + q));
}

} // namespace impl

// Parse zero or more S-expressions in the input returning a list.
// Notice parsed input is wrapped in one additional list.  That is,
//     1) "(foo)(bar)" returned as ((foo)(bar))
//     2) "(foo)"      returned as ((foo))
//     3) "foo"        returned as (foo)
//     4) ""           returned as ()
// as otherwise non-list or trivial inputs problematic.
// Based upon https://en.wikipedia.org/wiki/S-expression#Parsing
// and grotesquely extended to handle different input with checking.
template<typename InputIt>
node parse(InputIt next, InputIt end) {

    node sexp;
    sexp.emplace_back();
    std::string word;
    int level = 0;
    bool in_string = 0;

    while (next != end) {
        const char c = *next++;
        if (std::isspace(c)) {
            if (in_string) {
                sexp.back().emplace_back(std::move(word));
                word.clear();
            }
            in_string = false;
        } else if (c == '(') {
            ++level;
            sexp.emplace_back();
        } else if (c == ')') {
            if (level == 0) {
                throw std::invalid_argument("unopened right parenthesis");
            }
            if (in_string) {
                sexp.back().emplace_back(std::move(word));
                word.clear();
            }
            in_string = false;
            node temp(std::move(sexp.back()));
            sexp.pop_back();
            sexp.back().emplace_back(std::move(temp));
            --level;
        } else if (c == '"') {
            if (in_string) {
                sexp.back().emplace_back(std::move(word));
                word.clear();
            }
            in_string = false;
            for (;;) {
                if (next == end) throw std::invalid_argument("unclosed quote");
                const char q = *next++;
                if (q == '"') break;
                impl::append_maybe_escaped(q, word, next, end, /*quoted*/true);
            }
            sexp.back().emplace_back(std::move(word), /*string*/false);
            word.clear();
        } else {
            impl::append_maybe_escaped(c, word, next, end, /*quoted*/false);
            in_string = true;
        }
    }

    if (level != 0) {
        throw std::invalid_argument("unclosed left parenthesis");
    }
    if (in_string) { // Required for final top-level string
        sexp.back().emplace_back(word);
    }
    if (!sexp.size()) {
        throw std::logic_error("sanity failure on size");
    }
    if (sexp.front().type != node_type::list) {
        throw std::logic_error("sanity failure on type");
    }

    return sexp.front();
}

node parse(const std::string& in) {
    return parse(in.cbegin(), in.cend());
}

node parse(std::istream& is) {
    return parse(
        std::istream_iterator<char>(is),
        std::istream_iterator<char>());
}

template<typename OutputIterator>
void copy(const node& sexp, OutputIterator out) {
    switch (sexp.type) {
    case node_type::list:
        {
            *out++ = '(';
            std::size_t count = 0;
            for (const auto& term : sexp) {
                if (count++) {
                    *out++ = ' ';
                }
                copy(term, out);
            }
            *out++ = ')';
        }
        break;
    case node_type::symbol:
        for (const char c : sexp.string) {
            switch (c) {
            case '\a': *out++ = '\\'; *out++ = 'a';  break;
            case '\b': *out++ = '\\'; *out++ = 'b';  break;
            case '\f': *out++ = '\\'; *out++ = 'f';  break;
            case '\n': *out++ = '\\'; *out++ = 'n';  break;
            case '\r': *out++ = '\\'; *out++ = 'r';  break;
            case '\t': *out++ = '\\'; *out++ = 't';  break;
            case '\v': *out++ = '\\'; *out++ = 'v';  break;
            case '\'': *out++ = '\\'; *out++ = '\''; break;
            case '"':  *out++ = '\\'; *out++ = '"';  break;
            case '?':  *out++ = '\\'; *out++ = '?';  break;
            case ' ':  *out++ = '\\'; *out++ = ' ';  break;
            case '(':  *out++ = '\\'; *out++ = '(';  break;
            case ')':  *out++ = '\\'; *out++ = ')';  break;
            default:
                *out++ = c;
            }
        }
        break;
    case node_type::string:
        *out++ = '"';
        for (const char c : sexp.string) {
            switch (c) {
            case '\a': *out++ = '\\'; *out++ = 'a';  break;
            case '\b': *out++ = '\\'; *out++ = 'b';  break;
            case '\f': *out++ = '\\'; *out++ = 'f';  break;
            case '"':  *out++ = '\\'; *out++ = '"';  break;
            default:
                *out++ = c;
            }
        }
        *out++ = '"';
        break;
    default:
        throw std::logic_error("Unimplemented case");
    }
}

void copy(const node& sexp, std::ostream& os) {
    return copy(sexp, std::ostream_iterator<char>(os));
}

std::string to_string(const node& sexp) {
    std::ostringstream oss;
    std::ostream_iterator<char> it(oss);
    copy(sexp, it);
    return oss.str();
}

} // namespace

} // namespace

#endif
<commit_msg>Add missing \<commit_after>/*
 * Copyright (C) 2017 Rhys Ulerich
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef DESCENDU_SEXP_HPP
#define DESCENDU_SEXP_HPP

#include <cctype>
#include <iostream>
#include <iterator>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>

namespace descendu {

namespace sexp {

// TODO Track line/column as input processed
// TODO Record line/column within each node

enum struct node_type { list=1, symbol, string };

// switch (node.type) {
//     case node_type::list:    /* Use list-like methods */ break;
//     case node_type::symbol:  /* Use node.string */       break;
//     case node_type::string:  /* Use node.string */       break;
// }
class node : std::vector<node>
{
    typedef std::vector<node> base_type;

public:

    // Discern which type of data is contained.
    node_type type;

    // For string node access
    std::string string;

    // For list node access
    using base_type::back;
    using base_type::begin;
    using base_type::cbegin;
    using base_type::cend;
    using base_type::emplace_back;
    using base_type::end;
    using base_type::front;
    using base_type::operator[];
    using base_type::pop_back;
    using base_type::size;

    // Construct a string node
    explicit node(const std::string& s, const bool is_symbol = true)
        : base_type(0)
        , type(is_symbol ? node_type::symbol : node_type::string)
        , string(s)
    {};

    // Move into a string node
    explicit node(std::string&& s, const bool is_symbol = true)
        : base_type(0)
        , type(is_symbol ? node_type::symbol : node_type::string)
        , string(s)
    {};

    // Construct an empty list node
    node()
        : base_type()
        , type(node_type::list)
        , string()
    {};
};

namespace impl {

// Helper to process C99 and S-expression escapes for parse(...) just below
template<typename InputIt>
std::string& append_maybe_escaped(
    const char c,
    std::string &acc,  // Reference!
    InputIt& next,     // Reference!
    InputIt end,
    const bool quoted)
{
    if (c != '\\') return acc += c;
    if (next == end) throw std::invalid_argument("backslash precedes EOF");
    const char q = *next++;
    switch (q) {
    case 'a': return acc += '\a';
    case 'b': return acc += '\b';
    case 'f': return acc += '\f';
    case 'n': return acc += '\n';
    case 'r': return acc += '\r';
    case 't': return acc += '\t';
    case 'v': return acc += '\v';
    case '\'':
    case '\\':
    case '"':
    case '?': return acc += q;
    case 'x':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        throw new std::logic_error("Escaping via numeric codes unimplemented");
    case '(': case ')': if (!quoted) return acc += q;  // Possibly fall through
    }
    throw new std::invalid_argument(std::string("Improper escape \\" + q));
}

} // namespace impl

// Parse zero or more S-expressions in the input returning a list.
// Notice parsed input is wrapped in one additional list.  That is,
//     1) "(foo)(bar)" returned as ((foo)(bar))
//     2) "(foo)"      returned as ((foo))
//     3) "foo"        returned as (foo)
//     4) ""           returned as ()
// as otherwise non-list or trivial inputs problematic.
// Based upon https://en.wikipedia.org/wiki/S-expression#Parsing
// and grotesquely extended to handle different input with checking.
template<typename InputIt>
node parse(InputIt next, InputIt end) {

    node sexp;
    sexp.emplace_back();
    std::string word;
    int level = 0;
    bool in_string = 0;

    while (next != end) {
        const char c = *next++;
        if (std::isspace(c)) {
            if (in_string) {
                sexp.back().emplace_back(std::move(word));
                word.clear();
            }
            in_string = false;
        } else if (c == '(') {
            ++level;
            sexp.emplace_back();
        } else if (c == ')') {
            if (level == 0) {
                throw std::invalid_argument("unopened right parenthesis");
            }
            if (in_string) {
                sexp.back().emplace_back(std::move(word));
                word.clear();
            }
            in_string = false;
            node temp(std::move(sexp.back()));
            sexp.pop_back();
            sexp.back().emplace_back(std::move(temp));
            --level;
        } else if (c == '"') {
            if (in_string) {
                sexp.back().emplace_back(std::move(word));
                word.clear();
            }
            in_string = false;
            for (;;) {
                if (next == end) throw std::invalid_argument("unclosed quote");
                const char q = *next++;
                if (q == '"') break;
                impl::append_maybe_escaped(q, word, next, end, /*quoted*/true);
            }
            sexp.back().emplace_back(std::move(word), /*string*/false);
            word.clear();
        } else {
            impl::append_maybe_escaped(c, word, next, end, /*quoted*/false);
            in_string = true;
        }
    }

    if (level != 0) {
        throw std::invalid_argument("unclosed left parenthesis");
    }
    if (in_string) { // Required for final top-level string
        sexp.back().emplace_back(word);
    }
    if (!sexp.size()) {
        throw std::logic_error("sanity failure on size");
    }
    if (sexp.front().type != node_type::list) {
        throw std::logic_error("sanity failure on type");
    }

    return sexp.front();
}

node parse(const std::string& in) {
    return parse(in.cbegin(), in.cend());
}

node parse(std::istream& is) {
    return parse(
        std::istream_iterator<char>(is),
        std::istream_iterator<char>());
}

template<typename OutputIterator>
void copy(const node& sexp, OutputIterator out) {
    switch (sexp.type) {
    case node_type::list:
        {
            *out++ = '(';
            std::size_t count = 0;
            for (const auto& term : sexp) {
                if (count++) {
                    *out++ = ' ';
                }
                copy(term, out);
            }
            *out++ = ')';
        }
        break;
    case node_type::symbol:
        for (const char c : sexp.string) {
            switch (c) {
            case '\a': *out++ = '\\'; *out++ = 'a';  break;
            case '\b': *out++ = '\\'; *out++ = 'b';  break;
            case '\f': *out++ = '\\'; *out++ = 'f';  break;
            case '\n': *out++ = '\\'; *out++ = 'n';  break;
            case ' ':  *out++ = '\\'; *out++ = ' ';  break;
            case '?':  *out++ = '\\'; *out++ = '?';  break;
            case '"':  *out++ = '\\'; *out++ = '"';  break;
            case '(':  *out++ = '\\'; *out++ = '(';  break;
            case ')':  *out++ = '\\'; *out++ = ')';  break;
            case '\'': *out++ = '\\'; *out++ = '\''; break;
            case '\\': *out++ = '\\'; *out++ = '\\'; break;
            case '\r': *out++ = '\\'; *out++ = 'r';  break;
            case '\t': *out++ = '\\'; *out++ = 't';  break;
            case '\v': *out++ = '\\'; *out++ = 'v';  break;
            default:
                *out++ = c;
            }
        }
        break;
    case node_type::string:
        *out++ = '"';
        for (const char c : sexp.string) {
            switch (c) {
            case '\a': *out++ = '\\'; *out++ = 'a';  break;
            case '\b': *out++ = '\\'; *out++ = 'b';  break;
            case '\f': *out++ = '\\'; *out++ = 'f';  break;
            case '"':  *out++ = '\\'; *out++ = '"';  break;
            case '\\': *out++ = '\\'; *out++ = '\\'; break;
            default:
                *out++ = c;
            }
        }
        *out++ = '"';
        break;
    default:
        throw std::logic_error("Unimplemented case");
    }
}

void copy(const node& sexp, std::ostream& os) {
    return copy(sexp, std::ostream_iterator<char>(os));
}

std::string to_string(const node& sexp) {
    std::ostringstream oss;
    std::ostream_iterator<char> it(oss);
    copy(sexp, it);
    return oss.str();
}

} // namespace

} // namespace

#endif
<|endoftext|>