<commit_before>/*
 * File:   codegenClassTM.cpp
 * Author: tehlizard
 *
 * Created on December 4, 2015, 12:40 PM
 */

#include "codegenClassTM.h"
#include "cminus.h"
#include "types.h"
//#include "emit.h"
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <iomanip>
#include <time.h>

using namespace std;

codegenTM::codegenTM ( TreeNode * t, SymbolTable * s, int g, string of)
{
    symtable = s;
    aTree = t;

    outfilename = of;
    //infilename = input_filename;

    if(outfilename != "stdout")
        emitToFile = true;
    else
        emitToFile = false;

    gOffset = g;
    fOffset = 0;
    tOffset = 0;

    emitLoc = 0;
    highEmitLoc = 0;
}

codegenTM::~codegenTM ( )
{
    if(emitToFile && outfile.is_open())
    {
        outfile.flush();
        outfile.close();
    }
    else
    {
        cout.flush();
    }
}

void codegenTM::generateCode()
{
    /* Header comments*/
    if(emitToFile)
    {
        outfile.open(outfilename, ofstream::out);
        emitComment( outfilename );
    }
    emitComment( "Cgoes Cminus Compiler (CCC)" );
    emitComment( "Author: Christopher Goes");
    //emitComment( "File compiled: " + infilename );
    emitComment( "Generated at: " + timestamp() );

    /* Instruction generation */
    emitRMAbs( "LDA", PC, highEmitLoc, "Jump to init");
    treeTraversal(aTree);
    initSetup();
}

void codegenTM::generateDeclaration(TreeNode* node)
{
    TreeNode * tree;

    if(node != NULL)
        tree = node;
    else
    {
        cerr << "NULL node in generateDeclaration!" << endl;
        return;
    }

    TreeNode * p1, * p2, * p3;
    int savedLoc1,savedLoc2,currentLoc;
    int loc;

    string treestr = svalResolve(tree);

    switch(tree->kind) {
        case VarK:
            break;

        case FunK:
            emitComment("FUNCTION " + treestr);

            emitRM("ST", RET, -1, FP, "Store return address");

            if(treestr == "input")
            {

            }
            else if(treestr == "output")
            {

            }

            emitRM("LDA", PC, 0, RET, "Return");

            emitComment("END FUNCTION " + treestr);
            break;

        case ParamK:
            break;

        default:
            cerr << "Hit default in generateDeclaration switch(kind)!" << endl;
            break;
    }
}

void codegenTM::generateStatement( TreeNode * node )
{
    TreeNode * tree;

    if(node != NULL)
        tree = node;
    else
    {
        cerr << "NULL node in generateStatement!" << endl;
        return;
    }

    TreeNode * p1, * p2, * p3;
    int savedLoc1,savedLoc2,currentLoc;
    int loc;

    switch(tree->kind) {
        case IfK:
            break;

        case WhileK:
            break;

        case ForeachK:
            break;

        case CompoundK:
            break;

        case ReturnK:
            break;

        case BreakK:
            break;

        default:
            cerr << "Hit default in generateStatement switch(kind)!" << endl;
            break;
    }
}

void codegenTM::generateExpression( TreeNode * node )
{
    TreeNode * tree;

    if(node != NULL)
        tree = node;
    else
    {
        cerr << "NULL node in generateExpression!" << endl;
        return;
    }

    int loc;
    TreeNode * p1, * p2;

    switch(tree->kind) {
        case AssignK:
            break;

        case OpK:

            switch(tree->token->bval) {
                default:
                    break;
            }
            break;

        case UnaryK:

            switch(tree->token->bval) {
                case MULTIPLY:
                    break;

                case NOT:
                    break;

                case QUESTION:
                    break;

                case MINUS:
                    break;

                default:
                    break;
            }
            break;

        case IdK:
            break;

        case ConstK:
            break;

        case CallK:
            break;

        default:
            cerr << "Hit default in generateExpression switch(kind)!" << endl;
            break;
    }
}

void codegenTM::treeTraversal( TreeNode * node )
{
    TreeNode * tree = node;

    while( tree != NULL )
    {
        switch (tree->nodekind) {
            case DeclK:
                generateDeclaration(tree);
                break;
            case StmtK:
                generateStatement(tree);
                break;
            case ExpK:
                generateExpression(tree);
                break;
            default:
                cerr << "Hit default in treeTraversal switch(nodekind)!" << endl;
                break;
        }
        tree = tree->sibling;
    }
}

void codegenTM::initSetup()
{
    // TODO: keep track of init start
    emitComment("INIT");

    initGlobals();

    emitComment("END INIT");
}

void codegenTM::initGlobals()
{
    emitComment("INIT GLOBALS/STATICS");

    emitComment("END INIT GLOBALS/STATICS");
}

// Prints a comment line with comment s in the code file
void codegenTM::emitComment( string s )
{
    if(emitToFile)
        outfile << "* " << s << endl;
    else
        cout << "* " << s << endl;
}

/* Procedure emitRO emits a register-only
 * TM instruction
 * op = the opcode
 * r = target register
 * s = 1st source register
 * t = 2nd source register
 * c = a comment to be printed
 */
void codegenTM::emitRO( const char *op, int r, int s, int t, string c )
{
    //printf("%3d:  %5s  %d,%d,%d ",emitLoc++,op,r,s,t);
    //printf("\t%s",c) ;
    //printf("\n") ;

    if(emitToFile)
    {
    outfile << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << s << "," << t
            << " \t" << c << endl; /* append comment */
    }
    else
    {
    cout << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << s << "," << t
            << " \t" << c << endl; /* append comment */
    }

    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;

} /* emitRO */

/* Procedure emitRM emits a register-to-memory
 * TM instruction
 * op = the opcode
 * r = target register
 * d = the offset
 * s = the base register
 * c = a comment to be printed
 */
void codegenTM::emitRM( const char * op, int r, int d, int s, string c )
{
    //printf("%3d:  %5s  %d,%d(%d) ",emitLoc++,op,r,d,s);
    //printf("\t%s",c) ;
    //printf("\n") ;

    if(emitToFile)
    {
    outfile << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << d << "(" << s << ")"
            << " \t" << c << endl; /* append comment */
    }
    else
    {
    cout << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << d << "(" << s << ")"
            << " \t" << c << endl; /* append comment */
    }

    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;

} /* emitRM */

/* Function emitSkip skips "howMany" code
 * locations for later backpatch. It also
 * returns the current code position
 */
int codegenTM::emitSkip( int howMany )
{
    int i = emitLoc;
    emitLoc += howMany ;
    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;
    return i;

} /* emitSkip */

/* Procedure emitBackup backs up to
 * loc = a previously skipped location
 */
void codegenTM::emitBackup( int loc )
{
    if (loc > highEmitLoc)
        emitComment("BUG in emitBackup");

    emitLoc = loc ;

} /* emitBackup */

/* Procedure emitRestore restores the current
 * code position to the highest previously
 * unemitted position
 */
void codegenTM::emitRestore()
{
    emitLoc = highEmitLoc;
}

/* Procedure emitRM_Abs converts an absolute reference
 * to a pc-relative reference when emitting a
 * register-to-memory TM instruction
 * op = the opcode
 * r = target register
 * a = the absolute location in memory
 * c = a comment to be printed
 */
void codegenTM::emitRMAbs( const char *op, int r, int a, string c )
{
    //printf("%3d:  %5s  %d,%d(%d) ", emitLoc,op,r,a-(emitLoc+1),pc);
    //++emitLoc ;
    //printf("\t%s",c) ;
    //printf("\n") ;

    if(emitToFile)
    {
    outfile << setw(3) << emitLoc
            << ":  " << setw(5) << op
            << "  " << r << "," << a - (emitLoc + 1) << "(" << PC << ")"
            << " \t" << c << endl; /* append comment */
    }
    else
    {
    cout << setw(3) << emitLoc
            << ":  " << setw(5) << op
            << "  " << r << "," << a - (emitLoc + 1) << "(" << PC << ")"
            << " \t" << c << endl; /* append comment */
    }
    emitLoc++;

    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;

} /* emitRMAbs */

string codegenTM::timestamp()
{
    // Getting current local time because ADHD
    // Source: http://www.cplusplus.com/reference/ctime/localtime/
    time_t rawtime;
    struct tm * timeinfo;
    time (&rawtime);
    timeinfo = localtime (&rawtime);
    string ts = asctime(timeinfo);

    return ts;
}

<commit_msg>Added IO instructions<commit_after>/*
 * File:   codegenClassTM.cpp
 * Author: tehlizard
 *
 * Created on December 4, 2015, 12:40 PM
 */

#include "codegenClassTM.h"
#include "cminus.h"
#include "types.h"
//#include "emit.h"
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <iomanip>
#include <time.h>

using namespace std;

codegenTM::codegenTM ( TreeNode * t, SymbolTable * s, int g, string of)
{
    symtable = s;
    aTree = t;

    outfilename = of;
    //infilename = input_filename;

    if(outfilename != "stdout")
        emitToFile = true;
    else
        emitToFile = false;

    gOffset = g;
    fOffset = 0;
    tOffset = 0;

    emitLoc = 0;
    highEmitLoc = 0;
}

codegenTM::~codegenTM ( )
{
    if(emitToFile && outfile.is_open())
    {
        outfile.flush();
        outfile.close();
    }
    else
    {
        cout.flush();
    }
}

void codegenTM::generateCode()
{
    /* Header comments*/
    if(emitToFile)
    {
        outfile.open(outfilename, ofstream::out);
        emitComment( outfilename );
    }
    emitComment( "Cgoes Cminus Compiler (CCC)" );
    emitComment( "Author: Christopher Goes");
    //emitComment( "File compiled: " + infilename );
    emitComment( "Generated at: " + timestamp() );

    /* Instruction generation */
    emitRMAbs( "LDA", PC, highEmitLoc, "Jump to init");
    treeTraversal(aTree);
    initSetup();
}

void codegenTM::generateDeclaration(TreeNode* node)
{
    TreeNode * tree;

    if(node != NULL)
        tree = node;
    else
    {
        cerr << "NULL node in generateDeclaration!" << endl;
        return;
    }

    TreeNode * p1, * p2, * p3;
    int savedLoc1,savedLoc2,currentLoc;
    int loc;

    string treestr = svalResolve(tree);

    switch(tree->kind) {
        case VarK:
            break;

        case FunK:
            emitComment("FUNCTION " + treestr);

            emitRM("ST", RET, -1, FP, "Store return address");

            switch(tree->isIO) {
                case Nopeput:
                    break;

                case InputI:
                    emitRO("IN", 2, 2, 2, "Input integer");
                    break;

                case OutputI:
                    emitRO("OUT", 3, 3, 3, "Output integer");
                    break;

                case InputB:
                    emitRO("INB", 2, 2, 2, "Input boolean");
                    break;

                case OutputB:
                    emitRO("OUTB", 3, 3, 3, "Output boolean");
                    break;

                case InputC:
                    emitRO("INC", 2, 2, 2, "Input character");
                    break;

                case OutputC:
                    emitRO("OUTC", 3, 3, 3, "Output character");
                    break;

                case OutNL:
                    emitRO("OUTNL", 3, 3, 3, "Output newline");
                    break;

                default:
                    break;
            }

            emitRM("LDA", PC, 0, RET, "Return");

            emitComment("END FUNCTION " + treestr);
            break;

        case ParamK:
            break;

        default:
            cerr << "Hit default in generateDeclaration switch(kind)!" << endl;
            break;
    }
}

void codegenTM::generateStatement( TreeNode * node )
{
    TreeNode * tree;

    if(node != NULL)
        tree = node;
    else
    {
        cerr << "NULL node in generateStatement!" << endl;
        return;
    }

    TreeNode * p1, * p2, * p3;
    int savedLoc1,savedLoc2,currentLoc;
    int loc;

    switch(tree->kind) {
        case IfK:
            break;

        case WhileK:
            break;

        case ForeachK:
            break;

        case CompoundK:
            break;

        case ReturnK:
            break;

        case BreakK:
            break;

        default:
            cerr << "Hit default in generateStatement switch(kind)!" << endl;
            break;
    }
}

void codegenTM::generateExpression( TreeNode * node )
{
    TreeNode * tree;

    if(node != NULL)
        tree = node;
    else
    {
        cerr << "NULL node in generateExpression!" << endl;
        return;
    }

    int loc;
    TreeNode * p1, * p2;

    switch(tree->kind) {
        case AssignK:
            break;

        case OpK:

            switch(tree->token->bval) {
                default:
                    break;
            }
            break;

        case UnaryK:

            switch(tree->token->bval) {
                case MULTIPLY:
                    break;

                case NOT:
                    break;

                case QUESTION:
                    break;

                case MINUS:
                    break;

                default:
                    break;
            }
            break;

        case IdK:
            break;

        case ConstK:
            break;

        case CallK:
            break;

        default:
            cerr << "Hit default in generateExpression switch(kind)!" << endl;
            break;
    }
}

void codegenTM::treeTraversal( TreeNode * node )
{
    TreeNode * tree = node;

    while( tree != NULL )
    {
        switch (tree->nodekind) {
            case DeclK:
                generateDeclaration(tree);
                break;
            case StmtK:
                generateStatement(tree);
                break;
            case ExpK:
                generateExpression(tree);
                break;
            default:
                cerr << "Hit default in treeTraversal switch(nodekind)!" << endl;
                break;
        }
        tree = tree->sibling;
    }
}

void codegenTM::initSetup()
{
    // TODO: keep track of init start
    emitComment("INIT");

    initGlobals();

    emitComment("END INIT");
}

void codegenTM::initGlobals()
{
    emitComment("INIT GLOBALS/STATICS");

    emitComment("END INIT GLOBALS/STATICS");
}

// Prints a comment line with comment s in the code file
void codegenTM::emitComment( string s )
{
    if(emitToFile)
        outfile << "* " << s << endl;
    else
        cout << "* " << s << endl;
}

/* Procedure emitRO emits a register-only
 * TM instruction
 * op = the opcode
 * r = target register
 * s = 1st source register
 * t = 2nd source register
 * c = a comment to be printed
 */
void codegenTM::emitRO( const char *op, int r, int s, int t, string c )
{
    //printf("%3d:  %5s  %d,%d,%d ",emitLoc++,op,r,s,t);
    //printf("\t%s",c) ;
    //printf("\n") ;

    if(emitToFile)
    {
    outfile << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << s << "," << t
            << " \t" << c << endl; /* append comment */
    }
    else
    {
    cout << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << s << "," << t
            << " \t" << c << endl; /* append comment */
    }

    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;

} /* emitRO */

/* Procedure emitRM emits a register-to-memory
 * TM instruction
 * op = the opcode
 * r = target register
 * d = the offset
 * s = the base register
 * c = a comment to be printed
 */
void codegenTM::emitRM( const char * op, int r, int d, int s, string c )
{
    //printf("%3d:  %5s  %d,%d(%d) ",emitLoc++,op,r,d,s);
    //printf("\t%s",c) ;
    //printf("\n") ;

    if(emitToFile)
    {
    outfile << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << d << "(" << s << ")"
            << " \t" << c << endl; /* append comment */
    }
    else
    {
    cout << setw(3) << emitLoc++
            << ":  " << setw(5) << op
            << "  " << r << "," << d << "(" << s << ")"
            << " \t" << c << endl; /* append comment */
    }

    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;

} /* emitRM */

/* Function emitSkip skips "howMany" code
 * locations for later backpatch. It also
 * returns the current code position
 */
int codegenTM::emitSkip( int howMany )
{
    int i = emitLoc;
    emitLoc += howMany ;
    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;
    return i;

} /* emitSkip */

/* Procedure emitBackup backs up to
 * loc = a previously skipped location
 */
void codegenTM::emitBackup( int loc )
{
    if (loc > highEmitLoc)
        emitComment("BUG in emitBackup");

    emitLoc = loc ;

} /* emitBackup */

/* Procedure emitRestore restores the current
 * code position to the highest previously
 * unemitted position
 */
void codegenTM::emitRestore()
{
    emitLoc = highEmitLoc;
}

/* Procedure emitRM_Abs converts an absolute reference
 * to a pc-relative reference when emitting a
 * register-to-memory TM instruction
 * op = the opcode
 * r = target register
 * a = the absolute location in memory
 * c = a comment to be printed
 */
void codegenTM::emitRMAbs( const char *op, int r, int a, string c )
{
    //printf("%3d:  %5s  %d,%d(%d) ", emitLoc,op,r,a-(emitLoc+1),pc);
    //++emitLoc ;
    //printf("\t%s",c) ;
    //printf("\n") ;

    if(emitToFile)
    {
    outfile << setw(3) << emitLoc
            << ":  " << setw(5) << op
            << "  " << r << "," << a - (emitLoc + 1) << "(" << PC << ")"
            << " \t" << c << endl; /* append comment */
    }
    else
    {
    cout << setw(3) << emitLoc
            << ":  " << setw(5) << op
            << "  " << r << "," << a - (emitLoc + 1) << "(" << PC << ")"
            << " \t" << c << endl; /* append comment */
    }
    emitLoc++;

    if (highEmitLoc < emitLoc)
        highEmitLoc = emitLoc ;

} /* emitRMAbs */

string codegenTM::timestamp()
{
    // Getting current local time because ADHD
    // Source: http://www.cplusplus.com/reference/ctime/localtime/
    time_t rawtime;
    struct tm * timeinfo;
    time (&rawtime);
    timeinfo = localtime (&rawtime);
    string ts = asctime(timeinfo);

    return ts;
}

<|endoftext|>


<commit_before><commit_msg>- more win32 os tidy up<commit_after><|endoftext|>


<commit_before>/*
 * nt loader
 *
 * Copyright 2006-2008 Mike McCormack
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"

#include "timer.h"
#include "ntcall.h"
#include "object.h"
#include "debug.h"
#include "object.inl"

timeout_list_t timeout_t::g_timeouts;
LARGE_INTEGER boot_time;

bool timeout_t::has_expired()
{
	return !entry[0].is_linked();
}

bool timeout_t::queue_is_valid()
{
	timeout_iter_t i(g_timeouts);
	timeout_t *prev = 0;

	i.reset();
	while (i)
	{
		timeout_t* x = i;
		if (prev && prev->expires.QuadPart > x->expires.QuadPart)
			return false;
		i.next();
		prev = x;
	}

	return true;
}

// returns false if there were no timers
bool timeout_t::check_timers(LARGE_INTEGER& ret)
{
	LARGE_INTEGER now = current_time();
	timeout_t *t;

	if (!g_timeouts.head())
		return false;

	ret.QuadPart = 0LL;
	while (1)
	{
		t = g_timeouts.head();
		if (!t)
			return true;

		if (t->expires.QuadPart > now.QuadPart)
			break;

		t->do_timeout();
	}

	// calculate the timeout
	ret.QuadPart = t->expires.QuadPart - now.QuadPart;

	return true;
}

// FIXME: consider unifying this with logic in check_timers
//        to avoid conflicting return values
void timeout_t::time_remaining( LARGE_INTEGER& remaining )
{
	LARGE_INTEGER now = current_time();
	remaining.QuadPart = expires.QuadPart - now.QuadPart;
}

timeout_t::timeout_t(PLARGE_INTEGER t)
{
	set_timeout(t);
}

void timeout_t::set_timeout(PLARGE_INTEGER t)
{
	if (!t)
	{
		remove();
		expires.QuadPart = 0LL;
		return;
	}

	LARGE_INTEGER now = current_time();
	if (t->QuadPart <= 0LL)
		expires.QuadPart = now.QuadPart - t->QuadPart;
	else
		expires.QuadPart = t->QuadPart;

	// check there wasn't an overflow
	if (expires.QuadPart < 0LL)
		expires.QuadPart = 0x7fffffffffffffffLL;

	add();
	assert(!g_timeouts.empty());
	assert( queue_is_valid() );
}

void timeout_t::add()
{
	timeout_iter_t i(g_timeouts);
	timeout_t* x;

	while ( (x = i) )
	{
		if (x->expires.QuadPart > expires.QuadPart)
			break;
		i.next();
	}

	// if there's a timer before this one, no need to set the interval timer
	if (x)
		g_timeouts.insert_before(x, this);
	else
		g_timeouts.append(this);
}

void timeout_t::remove()
{
	if (entry[0].is_linked())
		g_timeouts.unlink(this);
}

extern KUSER_SHARED_DATA *shared_memory_address;

// numbers from Wine's dlls/ntdll/time.c
/* 1601 to 1970 is 369 years plus 89 leap days */
const ULONGLONG tickspersec = 10000000;
const ULONGLONG secsperday = 86400;
const ULONGLONG secs_1601_to_1970 = (369 * 365 + 89) * secsperday;
const ULONGLONG ticks_1601_to_1970 = secs_1601_to_1970 * tickspersec;

LARGE_INTEGER timeout_t::current_time()
{
	struct timeval tv;

	// timeofday gives seconds and milliseconds since 01-01-1970 00:00:00
	// windows uses 01-01-1601 00:00:00
	gettimeofday(&tv, NULL);
	LARGE_INTEGER ret;
	ret.QuadPart = (tv.tv_sec * 1000000LL + tv.tv_usec) * 10LL;
	ret.QuadPart += ticks_1601_to_1970;

	// update the time in shared memory
	// High1Time and High2Time need to be the same,
	// as userspace loops waiting for them to be equal
	// presumable to avoid a race when the LowPart overflows
	if (shared_memory_address)
	{
		KSYSTEM_TIME& st = shared_memory_address->SystemTime;
		st.LowPart = ret.LowPart;
		st.High1Time = ret.HighPart;
		st.High2Time = ret.HighPart;
	}
	return ret;
}

ULONG timeout_t::get_tick_count()
{
	LARGE_INTEGER now = current_time();
	return (now.QuadPart - boot_time.QuadPart) / 10000;
}

void get_system_time_of_day( SYSTEM_TIME_OF_DAY_INFORMATION& time_of_day )
{
	if (!boot_time.QuadPart)
		boot_time = timeout_t::current_time();

	time_of_day.CurrentTime = timeout_t::current_time();
	time_of_day.BootTime = boot_time;
	time_of_day.TimeZoneBias.QuadPart = 0LL;
	time_of_day.CurrentTimeZoneId = 0;
}

void timeout_t::do_timeout()
{
	// remove first so we can be added again
	remove();
	signal_timeout();
}

timeout_t::~timeout_t()
{
	remove();
}

class nttimer_t : public sync_object_t, public timeout_t
{
protected:
	BOOLEAN expired;
	ULONG interval;
	thread_t *thread;
	PKNORMAL_ROUTINE apc_routine;
	PVOID apc_context;
public:
	nttimer_t();
	~nttimer_t();
	NTSTATUS set(LARGE_INTEGER& DueTime, PKNORMAL_ROUTINE apc, PVOID context, BOOLEAN Resume, ULONG Period, BOOLEAN& prev);
	virtual BOOLEAN is_signalled( void );
	virtual BOOLEAN satisfy( void );
	virtual void signal_timeout();
	void cancel( BOOLEAN& prev );
};

nttimer_t::nttimer_t() :
	expired(FALSE),
	interval(0),
	thread(0),
	apc_routine(0),
	apc_context(0)
{
}

nttimer_t::~nttimer_t()
{
	if (thread)
		release( thread );
}

nttimer_t *nttimer_from_obj( object_t *obj )
{
	return dynamic_cast<nttimer_t*>( obj );
}

BOOLEAN nttimer_t::is_signalled( void )
{
	return expired;
}

BOOLEAN nttimer_t::satisfy( void )
{
	// FIXME: user correct time values
	if (apc_routine)
		thread->queue_apc_thread( apc_routine, apc_context, 0, 0 );

	// restart the timer
	if (interval)
	{
		LARGE_INTEGER when;
		when.QuadPart = interval * -10000LL;
		set_timeout( &when );
	}
	return TRUE;
}

void nttimer_t::signal_timeout()
{
	expired = TRUE;
	notify_watchers();
}

NTSTATUS nttimer_t::set(
	LARGE_INTEGER& DueTime,
	PKNORMAL_ROUTINE apc,
	PVOID context,
	BOOLEAN Resume,
	ULONG Period,
	BOOLEAN& prev)
{
	//dprintf("%ld %p %p %d %ld\n", (ULONG)DueTime.QuadPart, apc, context, Resume, Period );

	prev = expired;
	interval = Period;
	thread = current;
	addref( thread );
	apc_routine = apc;
	apc_context = context;

	if (DueTime.QuadPart == 0LL)
	{
		expired = TRUE;
		return STATUS_SUCCESS;
	}

	expired = FALSE;
	set_timeout( &DueTime );

	return STATUS_SUCCESS;
}

void nttimer_t::cancel( BOOLEAN& prev )
{
	prev = expired;
	set_timeout( 0 );
	expired = FALSE;
}

// sync_timer_t is a specialized timer
class sync_timer_t : public nttimer_t
{
public:
	virtual BOOLEAN satisfy( void );
};

BOOLEAN sync_timer_t::satisfy()
{
	expired = FALSE;
	return nttimer_t::satisfy();
}

class timer_factory : public object_factory
{
private:
	TIMER_TYPE Type;
public:
	timer_factory(TIMER_TYPE t) : Type(t) {}
	virtual NTSTATUS alloc_object(object_t** obj);
};

NTSTATUS timer_factory::alloc_object(object_t** obj)
{
	switch (Type)
	{
	case SynchronizationTimer:
		*obj = new sync_timer_t();
		break;
	case NotificationTimer:
		//*obj = new notify_timer_t();
		*obj = new nttimer_t();
		break;
	default:
		return STATUS_INVALID_PARAMETER_4;
	}
	if (!*obj)
		return STATUS_NO_MEMORY;
	return STATUS_SUCCESS;
}

NTSTATUS NTAPI NtCreateTimer(
	PHANDLE TimerHandle,
	ACCESS_MASK AccessMask,
	POBJECT_ATTRIBUTES ObjectAttributes,
	TIMER_TYPE Type)
{
	dprintf("%p %08lx %p %u\n", TimerHandle, AccessMask, ObjectAttributes, Type );

	timer_factory factory( Type );
	return factory.create( TimerHandle, AccessMask, ObjectAttributes );
}

NTSTATUS NtOpenTimer(
	PHANDLE TimerHandle,
	ACCESS_MASK AccessMask,
	POBJECT_ATTRIBUTES ObjectAttributes)
{
	dprintf("\n");
	return nt_open_object<nttimer_t>( TimerHandle, AccessMask, ObjectAttributes );
}

NTSTATUS NtCancelTimer(
	HANDLE TimerHandle,
	PBOOLEAN PreviousState)
{
	NTSTATUS r;

	nttimer_t* timer = 0;
	r = object_from_handle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (PreviousState)
	{
		r = verify_for_write( PreviousState, sizeof *PreviousState );
		if (r < STATUS_SUCCESS)
			return r;
	}

	BOOLEAN prev = 0;
	timer->cancel(prev);

	if (PreviousState)
		copy_to_user( PreviousState, &prev, sizeof prev );

	return STATUS_SUCCESS;
}

NTSTATUS NtSetTimer(
	HANDLE TimerHandle,
	PLARGE_INTEGER DueTime,
	PTIMER_APC_ROUTINE TimerApcRoutine,
	PVOID TimerContext,
	BOOLEAN Resume,
	LONG Period,
	PBOOLEAN PreviousState)
{
	LARGE_INTEGER due;

	NTSTATUS r = copy_from_user( &due, DueTime, sizeof due );
	if (r < STATUS_SUCCESS)
		return r;

	dprintf("due = %llx\n", due.QuadPart);

	nttimer_t* timer = 0;
	r = object_from_handle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (PreviousState)
	{
		r = verify_for_write( PreviousState, sizeof *PreviousState );
		if (r < STATUS_SUCCESS)
			return r;
	}

	BOOLEAN prev = FALSE;
	r = timer->set( due, (PKNORMAL_ROUTINE)TimerApcRoutine, TimerContext, Resume, Period, prev );
	if (r == STATUS_SUCCESS && PreviousState )
		 copy_to_user( PreviousState, &prev, sizeof prev );

	return r;
}

NTSTATUS NTAPI NtQueryTimer(
	HANDLE TimerHandle,
	TIMER_INFORMATION_CLASS TimerInformationClass,
	PVOID TimerInformation,
	ULONG TimerInformationLength,
	PULONG ResultLength)
{
	NTSTATUS r;

	nttimer_t* timer = 0;
	r = object_from_handle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	union {
		TIMER_BASIC_INFORMATION basic;
	} info;
	ULONG sz = 0;

	switch (TimerInformationClass)
	{
	case TimerBasicInformation:
		sz = sizeof info.basic;
		break;
	default:
		return STATUS_INVALID_INFO_CLASS;
	}

	// this seems like the wrong order, but agrees with what tests show
	r = verify_for_write( TimerInformation, sz );
	if (r < STATUS_SUCCESS)
		return r;

	if (sz != TimerInformationLength)
		return STATUS_INFO_LENGTH_MISMATCH;

	switch (TimerInformationClass)
	{
	case TimerBasicInformation:
		info.basic.SignalState = timer->is_signalled();
		timer->time_remaining( info.basic.TimeRemaining );
		break;
	default:
		assert(0);
	}

	r = copy_to_user( TimerInformation, &info, sz );
	if (r < STATUS_SUCCESS)
		return r;

	if (ResultLength)
		copy_to_user( ResultLength, &sz, sizeof sz );

	return r;
}

NTSTATUS NTAPI NtQuerySystemTime(PLARGE_INTEGER CurrentTime)
{
	LARGE_INTEGER now = timeout_t::current_time();

	return copy_to_user( CurrentTime, &now, sizeof now );
}
<commit_msg>Update the tick count<commit_after>/*
 * nt loader
 *
 * Copyright 2006-2008 Mike McCormack
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"

#include "timer.h"
#include "ntcall.h"
#include "object.h"
#include "debug.h"
#include "object.inl"

timeout_list_t timeout_t::g_timeouts;
static LARGE_INTEGER boot_time;
static ULONG tick_count;

bool timeout_t::has_expired()
{
	return !entry[0].is_linked();
}

bool timeout_t::queue_is_valid()
{
	timeout_iter_t i(g_timeouts);
	timeout_t *prev = 0;

	i.reset();
	while (i)
	{
		timeout_t* x = i;
		if (prev && prev->expires.QuadPart > x->expires.QuadPart)
			return false;
		i.next();
		prev = x;
	}

	return true;
}

// returns false if there were no timers
bool timeout_t::check_timers(LARGE_INTEGER& ret)
{
	LARGE_INTEGER now = current_time();
	timeout_t *t;

	if (!g_timeouts.head())
		return false;

	ret.QuadPart = 0LL;
	while (1)
	{
		t = g_timeouts.head();
		if (!t)
			return true;

		if (t->expires.QuadPart > now.QuadPart)
			break;

		t->do_timeout();
	}

	// calculate the timeout
	ret.QuadPart = t->expires.QuadPart - now.QuadPart;

	return true;
}

// FIXME: consider unifying this with logic in check_timers
//        to avoid conflicting return values
void timeout_t::time_remaining( LARGE_INTEGER& remaining )
{
	LARGE_INTEGER now = current_time();
	remaining.QuadPart = expires.QuadPart - now.QuadPart;
}

timeout_t::timeout_t(PLARGE_INTEGER t)
{
	set_timeout(t);
}

void timeout_t::set_timeout(PLARGE_INTEGER t)
{
	if (!t)
	{
		remove();
		expires.QuadPart = 0LL;
		return;
	}

	LARGE_INTEGER now = current_time();
	if (t->QuadPart <= 0LL)
		expires.QuadPart = now.QuadPart - t->QuadPart;
	else
		expires.QuadPart = t->QuadPart;

	// check there wasn't an overflow
	if (expires.QuadPart < 0LL)
		expires.QuadPart = 0x7fffffffffffffffLL;

	add();
	assert(!g_timeouts.empty());
	assert( queue_is_valid() );
}

void timeout_t::add()
{
	timeout_iter_t i(g_timeouts);
	timeout_t* x;

	while ( (x = i) )
	{
		if (x->expires.QuadPart > expires.QuadPart)
			break;
		i.next();
	}

	// if there's a timer before this one, no need to set the interval timer
	if (x)
		g_timeouts.insert_before(x, this);
	else
		g_timeouts.append(this);
}

void timeout_t::remove()
{
	if (entry[0].is_linked())
		g_timeouts.unlink(this);
}

extern KUSER_SHARED_DATA *shared_memory_address;

// numbers from Wine's dlls/ntdll/time.c
/* 1601 to 1970 is 369 years plus 89 leap days */
const ULONGLONG tickspersec = 10000000;
const ULONGLONG secsperday = 86400;
const ULONGLONG secs_1601_to_1970 = (369 * 365 + 89) * secsperday;
const ULONGLONG ticks_1601_to_1970 = secs_1601_to_1970 * tickspersec;

LARGE_INTEGER timeout_t::current_time()
{
	struct timeval tv;

	// timeofday gives seconds and milliseconds since 01-01-1970 00:00:00
	// windows uses 01-01-1601 00:00:00
	gettimeofday(&tv, NULL);
	LARGE_INTEGER ret;
	ret.QuadPart = (tv.tv_sec * 1000000LL + tv.tv_usec) * 10LL;
	ret.QuadPart += ticks_1601_to_1970;

	// calculate the tick count
	tick_count = (ret.QuadPart - boot_time.QuadPart) / 10000LL;

	// update the time in shared memory
	// High1Time and High2Time need to be the same,
	// as userspace loops waiting for them to be equal
	// presumably to avoid a race when the LowPart overflows
	if (shared_memory_address)
	{
		KSYSTEM_TIME& st = shared_memory_address->SystemTime;
		st.LowPart = ret.LowPart;
		st.High1Time = ret.HighPart;
		st.High2Time = ret.HighPart;

		// http://uninformed.org/index.cgi?v=2&a=2&p=18
		// milliseconds since boot (T)
		// T = shr(TickCountLow * TickCountMultiplier, 24)
		shared_memory_address->TickCountMultiplier = 0x100000;
		shared_memory_address->TickCountLow = ((tick_count * 0x01000000LL)/shared_memory_address->TickCountMultiplier);
	}

	return ret;
}

ULONG timeout_t::get_tick_count()
{
	current_time();
	return tick_count;
}

void get_system_time_of_day( SYSTEM_TIME_OF_DAY_INFORMATION& time_of_day )
{
	if (!boot_time.QuadPart)
		boot_time = timeout_t::current_time();

	time_of_day.CurrentTime = timeout_t::current_time();
	time_of_day.BootTime = boot_time;
	time_of_day.TimeZoneBias.QuadPart = 0LL;
	time_of_day.CurrentTimeZoneId = 0;
}

void timeout_t::do_timeout()
{
	// remove first so we can be added again
	remove();
	signal_timeout();
}

timeout_t::~timeout_t()
{
	remove();
}

class nttimer_t : public sync_object_t, public timeout_t
{
protected:
	BOOLEAN expired;
	ULONG interval;
	thread_t *thread;
	PKNORMAL_ROUTINE apc_routine;
	PVOID apc_context;
public:
	nttimer_t();
	~nttimer_t();
	NTSTATUS set(LARGE_INTEGER& DueTime, PKNORMAL_ROUTINE apc, PVOID context, BOOLEAN Resume, ULONG Period, BOOLEAN& prev);
	virtual BOOLEAN is_signalled( void );
	virtual BOOLEAN satisfy( void );
	virtual void signal_timeout();
	void cancel( BOOLEAN& prev );
};

nttimer_t::nttimer_t() :
	expired(FALSE),
	interval(0),
	thread(0),
	apc_routine(0),
	apc_context(0)
{
}

nttimer_t::~nttimer_t()
{
	if (thread)
		release( thread );
}

nttimer_t *nttimer_from_obj( object_t *obj )
{
	return dynamic_cast<nttimer_t*>( obj );
}

BOOLEAN nttimer_t::is_signalled( void )
{
	return expired;
}

BOOLEAN nttimer_t::satisfy( void )
{
	// FIXME: user correct time values
	if (apc_routine)
		thread->queue_apc_thread( apc_routine, apc_context, 0, 0 );

	// restart the timer
	if (interval)
	{
		LARGE_INTEGER when;
		when.QuadPart = interval * -10000LL;
		set_timeout( &when );
	}
	return TRUE;
}

void nttimer_t::signal_timeout()
{
	expired = TRUE;
	notify_watchers();
}

NTSTATUS nttimer_t::set(
	LARGE_INTEGER& DueTime,
	PKNORMAL_ROUTINE apc,
	PVOID context,
	BOOLEAN Resume,
	ULONG Period,
	BOOLEAN& prev)
{
	//dprintf("%ld %p %p %d %ld\n", (ULONG)DueTime.QuadPart, apc, context, Resume, Period );

	prev = expired;
	interval = Period;
	thread = current;
	addref( thread );
	apc_routine = apc;
	apc_context = context;

	if (DueTime.QuadPart == 0LL)
	{
		expired = TRUE;
		return STATUS_SUCCESS;
	}

	expired = FALSE;
	set_timeout( &DueTime );

	return STATUS_SUCCESS;
}

void nttimer_t::cancel( BOOLEAN& prev )
{
	prev = expired;
	set_timeout( 0 );
	expired = FALSE;
}

// sync_timer_t is a specialized timer
class sync_timer_t : public nttimer_t
{
public:
	virtual BOOLEAN satisfy( void );
};

BOOLEAN sync_timer_t::satisfy()
{
	expired = FALSE;
	return nttimer_t::satisfy();
}

class timer_factory : public object_factory
{
private:
	TIMER_TYPE Type;
public:
	timer_factory(TIMER_TYPE t) : Type(t) {}
	virtual NTSTATUS alloc_object(object_t** obj);
};

NTSTATUS timer_factory::alloc_object(object_t** obj)
{
	switch (Type)
	{
	case SynchronizationTimer:
		*obj = new sync_timer_t();
		break;
	case NotificationTimer:
		//*obj = new notify_timer_t();
		*obj = new nttimer_t();
		break;
	default:
		return STATUS_INVALID_PARAMETER_4;
	}
	if (!*obj)
		return STATUS_NO_MEMORY;
	return STATUS_SUCCESS;
}

NTSTATUS NTAPI NtCreateTimer(
	PHANDLE TimerHandle,
	ACCESS_MASK AccessMask,
	POBJECT_ATTRIBUTES ObjectAttributes,
	TIMER_TYPE Type)
{
	dprintf("%p %08lx %p %u\n", TimerHandle, AccessMask, ObjectAttributes, Type );

	timer_factory factory( Type );
	return factory.create( TimerHandle, AccessMask, ObjectAttributes );
}

NTSTATUS NtOpenTimer(
	PHANDLE TimerHandle,
	ACCESS_MASK AccessMask,
	POBJECT_ATTRIBUTES ObjectAttributes)
{
	dprintf("\n");
	return nt_open_object<nttimer_t>( TimerHandle, AccessMask, ObjectAttributes );
}

NTSTATUS NtCancelTimer(
	HANDLE TimerHandle,
	PBOOLEAN PreviousState)
{
	NTSTATUS r;

	nttimer_t* timer = 0;
	r = object_from_handle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (PreviousState)
	{
		r = verify_for_write( PreviousState, sizeof *PreviousState );
		if (r < STATUS_SUCCESS)
			return r;
	}

	BOOLEAN prev = 0;
	timer->cancel(prev);

	if (PreviousState)
		copy_to_user( PreviousState, &prev, sizeof prev );

	return STATUS_SUCCESS;
}

NTSTATUS NtSetTimer(
	HANDLE TimerHandle,
	PLARGE_INTEGER DueTime,
	PTIMER_APC_ROUTINE TimerApcRoutine,
	PVOID TimerContext,
	BOOLEAN Resume,
	LONG Period,
	PBOOLEAN PreviousState)
{
	LARGE_INTEGER due;

	NTSTATUS r = copy_from_user( &due, DueTime, sizeof due );
	if (r < STATUS_SUCCESS)
		return r;

	dprintf("due = %llx\n", due.QuadPart);

	nttimer_t* timer = 0;
	r = object_from_handle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (PreviousState)
	{
		r = verify_for_write( PreviousState, sizeof *PreviousState );
		if (r < STATUS_SUCCESS)
			return r;
	}

	BOOLEAN prev = FALSE;
	r = timer->set( due, (PKNORMAL_ROUTINE)TimerApcRoutine, TimerContext, Resume, Period, prev );
	if (r == STATUS_SUCCESS && PreviousState )
		 copy_to_user( PreviousState, &prev, sizeof prev );

	return r;
}

NTSTATUS NTAPI NtQueryTimer(
	HANDLE TimerHandle,
	TIMER_INFORMATION_CLASS TimerInformationClass,
	PVOID TimerInformation,
	ULONG TimerInformationLength,
	PULONG ResultLength)
{
	NTSTATUS r;

	nttimer_t* timer = 0;
	r = object_from_handle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	union {
		TIMER_BASIC_INFORMATION basic;
	} info;
	ULONG sz = 0;

	switch (TimerInformationClass)
	{
	case TimerBasicInformation:
		sz = sizeof info.basic;
		break;
	default:
		return STATUS_INVALID_INFO_CLASS;
	}

	// this seems like the wrong order, but agrees with what tests show
	r = verify_for_write( TimerInformation, sz );
	if (r < STATUS_SUCCESS)
		return r;

	if (sz != TimerInformationLength)
		return STATUS_INFO_LENGTH_MISMATCH;

	switch (TimerInformationClass)
	{
	case TimerBasicInformation:
		info.basic.SignalState = timer->is_signalled();
		timer->time_remaining( info.basic.TimeRemaining );
		break;
	default:
		assert(0);
	}

	r = copy_to_user( TimerInformation, &info, sz );
	if (r < STATUS_SUCCESS)
		return r;

	if (ResultLength)
		copy_to_user( ResultLength, &sz, sizeof sz );

	return r;
}

NTSTATUS NTAPI NtQuerySystemTime(PLARGE_INTEGER CurrentTime)
{
	LARGE_INTEGER now = timeout_t::current_time();

	return copy_to_user( CurrentTime, &now, sizeof now );
}
<|endoftext|>


<commit_before>/*
* Boost.Python module definition
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/rsa.h>
#include <botan/look_pk.h>
#include <botan/pubkey.h>
#include <botan/x509_key.h>
using namespace Botan;

#include "python_botan.h"
#include <sstream>

std::string bigint2str(const BigInt& n)
   {
   std::ostringstream out;
   out << n;
   return out.str();
   }

std::string secvec2str(const MemoryRegion<byte>& vec)
   {
   std::string str(vec.size(), 0);
   memcpy(&str[0], vec.begin(), vec.size());
   return str;
   }

class Py_RSA_PrivateKey
   {
   public:
      Py_RSA_PrivateKey(std::string pem_str,
                        Python_RandomNumberGenerator& rng,
                        std::string pass);

      Py_RSA_PrivateKey(u32bit bits, Python_RandomNumberGenerator& rng);
      ~Py_RSA_PrivateKey() { delete rsa_key; }

      std::string to_string() const
         {
         return PKCS8::PEM_encode(*rsa_key);
         }

      std::string get_N() const { return bigint2str(get_bigint_N()); }
      std::string get_E() const { return bigint2str(get_bigint_E()); }

      const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
      const BigInt& get_bigint_E() const { return rsa_key->get_e(); }

      std::string decrypt(const std::string& in,
                          const std::string& padding);

      std::string sign(const std::string& in,
                       const std::string& padding,
                       Python_RandomNumberGenerator& rng);
   private:
      RSA_PrivateKey* rsa_key;
   };

std::string Py_RSA_PrivateKey::decrypt(const std::string& in,
                                       const std::string& padding)
   {
   std::auto_ptr<PK_Decryptor> enc(get_pk_decryptor(*rsa_key, padding));

   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());

   return secvec2str(enc->decrypt(in_bytes, in.size()));
   }

std::string Py_RSA_PrivateKey::sign(const std::string& in,
                                    const std::string& padding,
                                    Python_RandomNumberGenerator& rng)
   {
   std::auto_ptr<PK_Signer> sign(get_pk_signer(*rsa_key, padding));
   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
   sign->update(in_bytes, in.size());
   return secvec2str(sign->signature(rng.get_underlying_rng()));
   }

Py_RSA_PrivateKey::Py_RSA_PrivateKey(u32bit bits,
                                     Python_RandomNumberGenerator& rng)
   {
   rsa_key = new RSA_PrivateKey(rng.get_underlying_rng(), bits);
   }

Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str,
                                     Python_RandomNumberGenerator& rng,
                                     std::string passphrase)
   {
   DataSource_Memory in(pem_str);

   Private_Key* pkcs8_key =
      PKCS8::load_key(in,
                      rng.get_underlying_rng(),
                      passphrase);

   rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key);

   if(!rsa_key)
      throw std::invalid_argument("Key is not an RSA key");
   }

class Py_RSA_PublicKey
   {
   public:
      Py_RSA_PublicKey(std::string pem_str);
      Py_RSA_PublicKey(const Py_RSA_PrivateKey&);
      ~Py_RSA_PublicKey() { delete rsa_key; }

      std::string get_N() const { return bigint2str(get_bigint_N()); }
      std::string get_E() const { return bigint2str(get_bigint_E()); }

      const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
      const BigInt& get_bigint_E() const { return rsa_key->get_e(); }

      std::string to_string() const
         {
         return X509::PEM_encode(*rsa_key);
         }

      std::string encrypt(const std::string& in,
                          const std::string& padding,
                          Python_RandomNumberGenerator& rng);

      bool verify(const std::string& in,
                  const std::string& padding,
                  const std::string& signature);
   private:
      RSA_PublicKey* rsa_key;
   };

Py_RSA_PublicKey::Py_RSA_PublicKey(const Py_RSA_PrivateKey& priv)
   {
   rsa_key = new RSA_PublicKey(priv.get_bigint_N(), priv.get_bigint_E());
   }

Py_RSA_PublicKey::Py_RSA_PublicKey(std::string pem_str)
   {
   DataSource_Memory in(pem_str);
   Public_Key* x509_key = X509::load_key(in);

   rsa_key = dynamic_cast<RSA_PublicKey*>(x509_key);

   if(!rsa_key)
      throw std::invalid_argument("Key is not an RSA key");
   }

std::string Py_RSA_PublicKey::encrypt(const std::string& in,
                                      const std::string& padding,
                                      Python_RandomNumberGenerator& rng)
   {
   std::auto_ptr<PK_Encryptor> enc(get_pk_encryptor(*rsa_key, padding));

   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());

   return secvec2str(enc->encrypt(in_bytes, in.size(),
                                  rng.get_underlying_rng()));
   }

bool Py_RSA_PublicKey::verify(const std::string& in,
                              const std::string& signature,
                              const std::string& padding)
   {
   std::auto_ptr<PK_Verifier> ver(get_pk_verifier(*rsa_key, padding));

   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
   const byte* sig_bytes = reinterpret_cast<const byte*>(signature.data());

   ver->update(in_bytes, in.size());
   return ver->check_signature(sig_bytes, signature.size());
   }

void export_rsa()
   {
   python::class_<Py_RSA_PublicKey>
      ("RSA_PublicKey", python::init<std::string>())
      .def(python::init<const Py_RSA_PrivateKey&>())
      .def("to_string", &Py_RSA_PublicKey::to_string)
      .def("encrypt", &Py_RSA_PublicKey::encrypt)
      .def("verify", &Py_RSA_PublicKey::verify)
      .def("get_N", &Py_RSA_PublicKey::get_N)
      .def("get_E", &Py_RSA_PublicKey::get_E);

   python::class_<Py_RSA_PrivateKey>
      ("RSA_PrivateKey", python::init<std::string, Python_RandomNumberGenerator&, std::string>())
       .def(python::init<u32bit, Python_RandomNumberGenerator&>())
       .def("to_string", &Py_RSA_PrivateKey::to_string)
       .def("decrypt", &Py_RSA_PrivateKey::decrypt)
       .def("sign", &Py_RSA_PrivateKey::sign)
       .def("get_N", &Py_RSA_PrivateKey::get_N)
       .def("get_E", &Py_RSA_PrivateKey::get_E);
   }
<commit_msg>Remove redundant function<commit_after>/*
* Boost.Python module definition
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/rsa.h>
#include <botan/look_pk.h>
#include <botan/pubkey.h>
#include <botan/x509_key.h>
using namespace Botan;

#include "python_botan.h"
#include <sstream>

std::string bigint2str(const BigInt& n)
   {
   std::ostringstream out;
   out << n;
   return out.str();
   }

class Py_RSA_PrivateKey
   {
   public:
      Py_RSA_PrivateKey(std::string pem_str,
                        Python_RandomNumberGenerator& rng,
                        std::string pass);

      Py_RSA_PrivateKey(u32bit bits, Python_RandomNumberGenerator& rng);
      ~Py_RSA_PrivateKey() { delete rsa_key; }

      std::string to_string() const
         {
         return PKCS8::PEM_encode(*rsa_key);
         }

      std::string get_N() const { return bigint2str(get_bigint_N()); }
      std::string get_E() const { return bigint2str(get_bigint_E()); }

      const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
      const BigInt& get_bigint_E() const { return rsa_key->get_e(); }

      std::string decrypt(const std::string& in,
                          const std::string& padding);

      std::string sign(const std::string& in,
                       const std::string& padding,
                       Python_RandomNumberGenerator& rng);
   private:
      RSA_PrivateKey* rsa_key;
   };

std::string Py_RSA_PrivateKey::decrypt(const std::string& in,
                                       const std::string& padding)
   {
   std::auto_ptr<PK_Decryptor> enc(get_pk_decryptor(*rsa_key, padding));

   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());

   return make_string(enc->decrypt(in_bytes, in.size()));
   }

std::string Py_RSA_PrivateKey::sign(const std::string& in,
                                    const std::string& padding,
                                    Python_RandomNumberGenerator& rng)
   {
   std::auto_ptr<PK_Signer> sign(get_pk_signer(*rsa_key, padding));
   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
   sign->update(in_bytes, in.size());
   return make_string(sign->signature(rng.get_underlying_rng()));
   }

Py_RSA_PrivateKey::Py_RSA_PrivateKey(u32bit bits,
                                     Python_RandomNumberGenerator& rng)
   {
   rsa_key = new RSA_PrivateKey(rng.get_underlying_rng(), bits);
   }

Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str,
                                     Python_RandomNumberGenerator& rng,
                                     std::string passphrase)
   {
   DataSource_Memory in(pem_str);

   Private_Key* pkcs8_key =
      PKCS8::load_key(in,
                      rng.get_underlying_rng(),
                      passphrase);

   rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key);

   if(!rsa_key)
      throw std::invalid_argument("Key is not an RSA key");
   }

class Py_RSA_PublicKey
   {
   public:
      Py_RSA_PublicKey(std::string pem_str);
      Py_RSA_PublicKey(const Py_RSA_PrivateKey&);
      ~Py_RSA_PublicKey() { delete rsa_key; }

      std::string get_N() const { return bigint2str(get_bigint_N()); }
      std::string get_E() const { return bigint2str(get_bigint_E()); }

      const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
      const BigInt& get_bigint_E() const { return rsa_key->get_e(); }

      std::string to_string() const
         {
         return X509::PEM_encode(*rsa_key);
         }

      std::string encrypt(const std::string& in,
                          const std::string& padding,
                          Python_RandomNumberGenerator& rng);

      bool verify(const std::string& in,
                  const std::string& padding,
                  const std::string& signature);
   private:
      RSA_PublicKey* rsa_key;
   };

Py_RSA_PublicKey::Py_RSA_PublicKey(const Py_RSA_PrivateKey& priv)
   {
   rsa_key = new RSA_PublicKey(priv.get_bigint_N(), priv.get_bigint_E());
   }

Py_RSA_PublicKey::Py_RSA_PublicKey(std::string pem_str)
   {
   DataSource_Memory in(pem_str);
   Public_Key* x509_key = X509::load_key(in);

   rsa_key = dynamic_cast<RSA_PublicKey*>(x509_key);

   if(!rsa_key)
      throw std::invalid_argument("Key is not an RSA key");
   }

std::string Py_RSA_PublicKey::encrypt(const std::string& in,
                                      const std::string& padding,
                                      Python_RandomNumberGenerator& rng)
   {
   std::auto_ptr<PK_Encryptor> enc(get_pk_encryptor(*rsa_key, padding));

   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());

   return make_string(enc->encrypt(in_bytes, in.size(),
                                  rng.get_underlying_rng()));
   }

bool Py_RSA_PublicKey::verify(const std::string& in,
                              const std::string& signature,
                              const std::string& padding)
   {
   std::auto_ptr<PK_Verifier> ver(get_pk_verifier(*rsa_key, padding));

   const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
   const byte* sig_bytes = reinterpret_cast<const byte*>(signature.data());

   ver->update(in_bytes, in.size());
   return ver->check_signature(sig_bytes, signature.size());
   }

void export_rsa()
   {
   python::class_<Py_RSA_PublicKey>
      ("RSA_PublicKey", python::init<std::string>())
      .def(python::init<const Py_RSA_PrivateKey&>())
      .def("to_string", &Py_RSA_PublicKey::to_string)
      .def("encrypt", &Py_RSA_PublicKey::encrypt)
      .def("verify", &Py_RSA_PublicKey::verify)
      .def("get_N", &Py_RSA_PublicKey::get_N)
      .def("get_E", &Py_RSA_PublicKey::get_E);

   python::class_<Py_RSA_PrivateKey>
      ("RSA_PrivateKey", python::init<std::string, Python_RandomNumberGenerator&, std::string>())
       .def(python::init<u32bit, Python_RandomNumberGenerator&>())
       .def("to_string", &Py_RSA_PrivateKey::to_string)
       .def("decrypt", &Py_RSA_PrivateKey::decrypt)
       .def("sign", &Py_RSA_PrivateKey::sign)
       .def("get_N", &Py_RSA_PrivateKey::get_N)
       .def("get_E", &Py_RSA_PrivateKey::get_E);
   }
<|endoftext|>


<commit_before>#include <iostream>
#include <queue>
#include <string>

#include <boost/random.hpp>
#include <boost/generator_iterator.hpp>

#include <glog/logging.h>

using boost::variate_generator;
using boost::mt19937;
using boost::exponential_distribution;

#define ONLY_EVENT_TYPE     0
#define NUMBER_EVENT_TYPES  3   //NEED TO MAKE SURE THIS IS 1 MORE THAN THE LAST DEFINED EVENT

const std::string event_names[NUMBER_EVENT_TYPES] = {
    "ARRIVE",
    "DEPART",
    "CLOSE"
};

bool closed = false;

std::vector<bool> servers_idle;
std::vector< std::queue<double>* > servers_queue;

/**
 *  A class for an event, which holds an int for the event type, a double for simulation time and possibly other data.
 *  We may want to subclass this with our own events
 */
class Event {
    public:
        const double time;
        const double server_start_time;
        const int server_index;
        const int type;

        Event(double time, int type) : time(time), server_start_time(0), server_index(-1), type(type) {
            //cout << "created an event with simulation time: " << this->time << endl;
            //cout << "created an event with event type: " << this->type << endl;
        }

        Event(double time, double server_start_time, int server_index, int type) : time(time), server_start_time(server_start_time), server_index(server_index), type(type) {
            //cout << "created an event with simulation time: " << this->time << endl;
            //cout << "created an event with event type: " << this->type << endl;
        }

        bool operator<( const Event& e ) const {
            return time < e.time;
        }

        bool operator>( const Event& e ) const {
            return time > e.time;
        }

        bool less( const Event& e) const {
            return time < e.time;
        }

        friend std::ostream& operator<< (std::ostream& out, Event& event);
};

class CompareEvent {
    public:
        bool operator()(Event* &e1, Event* &e2) {
            return e1->time > e2->time;
            //return false;
        }
};

// Print event
std::ostream& operator<< ( std::ostream& out, Event& event) {
    out << "[sim_time: " << std::setw(10) << std::setprecision(3) << std::fixed << event.time << ", type: " << std::setw(4) << event.type;
    if (event.type < NUMBER_EVENT_TYPES) {
        out << " - " << std::left << std::setw(50) << event_names[event.type];
    } else {
        out << std::left << std::setw(50) << " - UNKNOWN";
    }
    out << std::right << "]";
    return out;
}

bool server_idle(int &idle_index) {
    for (int i = 0; i < servers_idle.size(); i++) {
        if (servers_idle[i] == true) {
            idle_index = i;
            return true;
        }
    }
    return false;
}

void addToQueue(double enqueue_time) {
    std::queue<double> *shortest = NULL;
    for (int i = 0; i < servers_queue.size(); i++) {
        if (shortest == NULL || servers_queue[i]->size() < shortest->size()) {
            shortest = servers_queue[i];
        }
    }
    shortest->push(enqueue_time);
}

void run_simulation(const double close_time, variate_generator< mt19937, exponential_distribution<> > rand_generator) {
    double simulation_time_s = 0;
    double previous_time_s;

    double server_work_time = 0;

    double total_queue_time = 0;
    double total_departures = 0;

    double sum_of_time_queue_length = 0;

    std::priority_queue<Event*, std::vector<Event*>, CompareEvent> heap;
    //std::queue<double> queue;

    // Put initial event in the heap
    heap.push(new Event(simulation_time_s + rand_generator(), 0));
    heap.push(new Event(close_time, 2));

    VLOG(2) << "Start Simulation...";

    while (!heap.empty()) {
        Event *current_event = heap.top();
        heap.pop();

        if (current_event == NULL) {
            LOG(ERROR) << "Simulation not complete and there are no events in the min heap.";
            LOG(ERROR) << "\tsimulation time: " << simulation_time_s;
            exit(0);
        }

        previous_time_s = simulation_time_s;
        simulation_time_s = current_event->time;

        // Calculate average time stuff
        double time_since_last = simulation_time_s - previous_time_s;
        // Calculate sum of time queue length for all servers
        //sum_of_time_queue_length += queue.size() * time_since_last;

        int idle_index = -1;
        switch (current_event->type) {
            case 0: // ARRIVE
                // If the server is busy add new arrival to waiting queue
                // otherwise set the server as busy and add new departure time.
                VLOG(2) << "Arrival Begin";
                if (!server_idle(idle_index)) {
                    addToQueue(simulation_time_s);
                } else {
                    VLOG(2) << "Idle Index: " << idle_index;
                    servers_idle[idle_index] = false;
                    heap.push(new Event(simulation_time_s + rand_generator(), simulation_time_s, idle_index, 1));
                }
                if (!closed) {
                    // Add next arrival event
                    heap.push(new Event(simulation_time_s + rand_generator(), 0));
                }
                VLOG(2) << "Arrival End";
                break;
            case 1: // DEPART
                // Add server busy time.
                // Which server is busy?
                //server_work_time += simulation_time_s - current_event->server_start_time;
                // If the queue is empty set the server to idle otherwise
                // get the next person from the queue and set their departure
                // time.
                VLOG(2) << "Depart Begin";
                if (servers_queue[current_event->server_index]->empty()) {
                    servers_idle[current_event->server_index] = true;
                } else {
                    // Add current simulation time minus time stored in the
                    // queue to the total queue time.
                    // total_queue_time += simulation_time_s - queue.front();
                    servers_queue[current_event->server_index]->pop();
                    // Add a new depature to the heap.
                    heap.push(new Event(simulation_time_s + rand_generator(), simulation_time_s, current_event->server_index, 1));
                }
                total_departures++;
                VLOG(2) << "Depart End";
                break;
            case 2: // CLOSE
                // Set flag to stop arrivals
                VLOG(2) << "Closed";
                closed = true;
                break;
            default:
                LOG(ERROR) << "Simulation had an event with an unknown type: " << current_event->type;
                LOG(ERROR) << "\tsimulation time: " << simulation_time_s;
                exit(0);
        }

        VLOG(3) << *current_event << ", h: " << heap.size();

        delete current_event; // Event's are created with new, so we need to delete them when we're done with them
    }

    LOG(INFO) << "The simulation ended at time: " << simulation_time_s;
    VLOG(1) << "The server was busy for time: " << server_work_time;
    LOG(INFO) << "The server utilization was: " << server_work_time / simulation_time_s;
    LOG(INFO) << "The average length of the queue was: " << sum_of_time_queue_length / simulation_time_s;
    VLOG(1) << "Total time spent in the queue: " << total_queue_time;
    VLOG(1) << "Total departures: " << total_departures;
    LOG(INFO) << "The average time spent in queue: " << total_queue_time / total_departures;
}

int main(int argc, char **argv) {
    // Initialize Google Logging
    google::InitGoogleLogging(argv[0]);
    // Log to Stderr
    FLAGS_logtostderr = 1;

    int seed = time(0);
    double distribution_mean = 3.0;
    variate_generator< mt19937, exponential_distribution<> > rand_generator(mt19937(seed), exponential_distribution<>(1/distribution_mean));

    // Init number of servers
    int num_servers = 2;
    for (int i = 0; i < num_servers; i++) {
        servers_idle.push_back(true);
        servers_queue.push_back(new std::queue<double>());
    }

    run_simulation(atoi(argv[1]), rand_generator);
}

<commit_msg>Add server utilization, average queue length, and average time in queue.<commit_after>#include <iostream>
#include <queue>
#include <string>

#include <boost/random.hpp>
#include <boost/generator_iterator.hpp>

#include <glog/logging.h>

using boost::variate_generator;
using boost::mt19937;
using boost::exponential_distribution;

#define ONLY_EVENT_TYPE     0
#define NUMBER_EVENT_TYPES  3   //NEED TO MAKE SURE THIS IS 1 MORE THAN THE LAST DEFINED EVENT

const std::string event_names[NUMBER_EVENT_TYPES] = {
    "ARRIVE",
    "DEPART",
    "CLOSE"
};

bool closed = false;

std::vector<bool> servers_idle;
std::vector< std::queue<double>* > servers_queue;

/**
 *  A class for an event, which holds an int for the event type, a double for simulation time and possibly other data.
 *  We may want to subclass this with our own events
 */
class Event {
    public:
        const double time;
        const double server_start_time;
        const int server_index;
        const int type;

        Event(double time, int type) : time(time), server_start_time(0), server_index(-1), type(type) {
            //cout << "created an event with simulation time: " << this->time << endl;
            //cout << "created an event with event type: " << this->type << endl;
        }

        Event(double time, double server_start_time, int server_index, int type) : time(time), server_start_time(server_start_time), server_index(server_index), type(type) {
            //cout << "created an event with simulation time: " << this->time << endl;
            //cout << "created an event with event type: " << this->type << endl;
        }

        bool operator<( const Event& e ) const {
            return time < e.time;
        }

        bool operator>( const Event& e ) const {
            return time > e.time;
        }

        bool less( const Event& e) const {
            return time < e.time;
        }

        friend std::ostream& operator<< (std::ostream& out, Event& event);
};

class CompareEvent {
    public:
        bool operator()(Event* &e1, Event* &e2) {
            return e1->time > e2->time;
            //return false;
        }
};

// Print event
std::ostream& operator<< ( std::ostream& out, Event& event) {
    out << "[sim_time: " << std::setw(10) << std::setprecision(3) << std::fixed << event.time << ", type: " << std::setw(4) << event.type;
    if (event.type < NUMBER_EVENT_TYPES) {
        out << " - " << std::left << std::setw(50) << event_names[event.type];
    } else {
        out << std::left << std::setw(50) << " - UNKNOWN";
    }
    out << std::right << "]";
    return out;
}

bool server_idle(int &idle_index) {
    for (int i = 0; i < servers_idle.size(); i++) {
        if (servers_idle[i] == true) {
            idle_index = i;
            return true;
        }
    }
    return false;
}

void addToQueue(double enqueue_time) {
    std::queue<double> *shortest = NULL;
    for (int i = 0; i < servers_queue.size(); i++) {
        if (shortest == NULL || servers_queue[i]->size() < shortest->size()) {
            shortest = servers_queue[i];
        }
    }
    shortest->push(enqueue_time);
}

void run_simulation(const double close_time, variate_generator< mt19937, exponential_distribution<> > rand_generator) {
    double simulation_time_s = 0;
    double previous_time_s;

    std::vector<double> servers_work_time;
    std::vector<double> servers_time_queue_length;
    for (int i = 0; i < servers_idle.size(); i++) {
        servers_work_time.push_back(0);
        servers_time_queue_length.push_back(0);
    }

    double total_queue_time = 0;
    double total_departures = 0;

    std::priority_queue<Event*, std::vector<Event*>, CompareEvent> heap;
    //std::queue<double> queue;

    // Put initial event in the heap
    heap.push(new Event(simulation_time_s + rand_generator(), 0));
    heap.push(new Event(close_time, 2));

    VLOG(2) << "Start Simulation...";

    while (!heap.empty()) {
        Event *current_event = heap.top();
        heap.pop();

        if (current_event == NULL) {
            LOG(ERROR) << "Simulation not complete and there are no events in the min heap.";
            LOG(ERROR) << "\tsimulation time: " << simulation_time_s;
            exit(0);
        }

        previous_time_s = simulation_time_s;
        simulation_time_s = current_event->time;

        // Calculate average time stuff
        double time_since_last = simulation_time_s - previous_time_s;
        // Calculate sum of time queue length for all servers
        for (int i = 0; i < servers_idle.size(); i++) {
            servers_time_queue_length[i] += servers_queue[i]->size() * time_since_last;
        }

        int idle_index = -1;
        switch (current_event->type) {
            case 0: // ARRIVE
                // If the server is busy add new arrival to waiting queue
                // otherwise set the server as busy and add new departure time.
                VLOG(2) << "Arrival Begin";
                if (!server_idle(idle_index)) {
                    addToQueue(simulation_time_s);
                } else {
                    VLOG(2) << "Idle Index: " << idle_index;
                    servers_idle[idle_index] = false;
                    heap.push(new Event(simulation_time_s + rand_generator(), simulation_time_s, idle_index, 1));
                }
                if (!closed) {
                    // Add next arrival event
                    heap.push(new Event(simulation_time_s + rand_generator(), 0));
                }
                VLOG(2) << "Arrival End";
                break;
            case 1: // DEPART
                // Add server busy time.
                // Which server is busy?
                servers_work_time[current_event->server_index] += simulation_time_s - current_event->server_start_time;
                // If the queue is empty set the server to idle otherwise
                // get the next person from the queue and set their departure
                // time.
                VLOG(2) << "Depart Begin";
                if (servers_queue[current_event->server_index]->empty()) {
                    servers_idle[current_event->server_index] = true;
                } else {
                    // Add current simulation time minus time stored in the
                    // queue to the total queue time.
                    total_queue_time += simulation_time_s - servers_queue[current_event->server_index]->front();
                    servers_queue[current_event->server_index]->pop();
                    // Add a new depature to the heap.
                    heap.push(new Event(simulation_time_s + rand_generator(), simulation_time_s, current_event->server_index, 1));
                }
                total_departures++;
                VLOG(2) << "Depart End";
                break;
            case 2: // CLOSE
                // Set flag to stop arrivals
                VLOG(2) << "Closed";
                closed = true;
                break;
            default:
                LOG(ERROR) << "Simulation had an event with an unknown type: " << current_event->type;
                LOG(ERROR) << "\tsimulation time: " << simulation_time_s;
                exit(0);
        }

        VLOG(3) << *current_event << ", h: " << heap.size();

        delete current_event; // Event's are created with new, so we need to delete them when we're done with them
    }

    LOG(INFO) << "The simulation ended at time: " << simulation_time_s;
    LOG(INFO) << "The simulation ended " << simulation_time_s - close_time << " after close.";
    for (int i = 0; i < servers_idle.size(); i++) {
        VLOG(1) << "The server " << i+1 << " was busy for time: " << servers_work_time[i];
        LOG(INFO) << "The server " << i+1 << " utilization was: " << servers_work_time[i] / simulation_time_s;
        LOG(INFO) << "The average length of server " << i+1 << " queue was: " << servers_time_queue_length[i] / simulation_time_s;
    }
    VLOG(1) << "Total time spent in the queue: " << total_queue_time;
    VLOG(1) << "Total departures: " << total_departures;
    LOG(INFO) << "The average time spent in queue: " << total_queue_time / total_departures;
}

int main(int argc, char **argv) {
    // Initialize Google Logging
    google::InitGoogleLogging(argv[0]);
    // Log to Stderr
    FLAGS_logtostderr = 1;

    int seed = time(0);
    double distribution_mean = 3.0;
    variate_generator< mt19937, exponential_distribution<> > rand_generator(mt19937(seed), exponential_distribution<>(1/distribution_mean));

    // Init number of servers
    int num_servers = 2;
    for (int i = 0; i < num_servers; i++) {
        servers_idle.push_back(true);
        servers_queue.push_back(new std::queue<double>());
    }

    run_simulation(atoi(argv[1]), rand_generator);

    for (int i = 0; i < num_servers; i++) {
        delete servers_queue[i];
    }
}

<|endoftext|>


<commit_before>/* RLTK (RogueLike Tool Kit) 1.00
 * Copyright (c) 2016-Present, Bracket Productions.
 * Licensed under the LGPL - see LICENSE file.
 *
 * Example 7: Advanced GUI with retained-mode GUI elements and an owner-draw background.
 */

// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
#include <sstream>
#include <iomanip>

// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;

constexpr int BACKDROP_LAYER = 1;
constexpr int LOG_LAYER = 2;
constexpr int RETAINED_TEST_LAYER = 3;

constexpr int TEST_BOUNDARY_BOX = 1;
constexpr int TEST_STATIC_TEST = 2;
constexpr int TEST_MOUSE_HOVER = 3;
constexpr int TEST_CHECKBOX = 4;
constexpr int TEST_RADIOSET = 5;

void resize_bg(layer_t * l, int w, int h) {
	// Use the whole window
	l->w = w;
	l->h = h;
}

void draw_bg(layer_t * l, sf::RenderTexture &window) {
	sf::Texture * bg = get_texture("backdrop");
	sf::Sprite backdrop(*bg);
	window.draw(backdrop);
}

void resize_log(layer_t * l, int w, int h) {
	// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)
	l->w = w - 160;
	l->h = h - 32;

	// If the log window would take up the whole screen, hide it
	if (l->w < 0) {
		l->console->visible = false;
	} else {
		l->console->visible = true;
	}
	l->x = w - 160;
}

void resize_retained(layer_t * l, int w, int h) {
	// Do nothing - we'll just keep on rendering away.
	l->x = 100;
	l->y = 100;
	l->w = 400;
	l->h = 200;
}

// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
	term(LOG_LAYER)->clear(vchar{' ', WHITE, DARKEST_GREEN});
	term(LOG_LAYER)->box(DARKEST_GREEN, BLACK);
	term(LOG_LAYER)->print(1,1, "Log Entry", LIGHT_GREEN, DARKEST_GREEN);
	term(LOG_LAYER)->print(1,2, "More text!", LIGHT_GREEN, DARKEST_GREEN);
	term(LOG_LAYER)->print(1,3, "Even more...", LIGHT_GREEN, DARKEST_GREEN);
	term(LOG_LAYER)->print(1,4, "... goes here", LIGHT_GREEN, DARKEST_GREEN);

	std::stringstream ss;
	ss << std::setiosflags(std::ios::fixed) << std::setprecision(0) << (1000.0/duration_ms) << " FPS";
	term(LOG_LAYER)->print(1,6, ss.str(), WHITE, DARKEST_GREEN);
}

// Your main function
int main()
{
	// This time, we're using a full initialization: width, height, window title, and "false" meaning we don't
	// want an automatically generated root console. This is necessary when you want to use the complex layout
	// functions.
	init(config_advanced("../assets"));

	// We're going to be using a bitmap, so we need to load it. The library makes this easy:
	register_texture("../assets/background_image.png", "backdrop");

	// Now we add an owner-draw background layer. "Owner-draw" means that it the library will ask it to
	// draw itself with a call-back function.
	gui->add_owner_layer(BACKDROP_LAYER, 0, 0, 1024, 768, resize_bg, draw_bg);
	gui->add_layer(LOG_LAYER, 864, 32, 160, 768-32, "8x16", resize_log);
	term(LOG_LAYER)->set_alpha(196); // Make the overlay translucent
	gui->add_layer(RETAINED_TEST_LAYER, 100, 100, 400, 200, "8x16", resize_retained);

	// Now we build some retained-mode controls. These don't require additional work during rendering
	// Note that we are providing a handle to the control. That lets us access it later with
	// layer(layerhandle)->control(controlhandle). It's up to you to store the handles; they can be any
	// int.
	layer(RETAINED_TEST_LAYER)->add_boundary_box(TEST_BOUNDARY_BOX, true, DARK_GREY, BLACK);
	layer(RETAINED_TEST_LAYER)->add_static_text(TEST_STATIC_TEST, 1, 1, "Retained Mode Static Text", YELLOW, BLACK);

	// For this control, we'll define an on-mouse-over. We're using a lambda, but it could be any function
	// with that takes a gui_control_t * as a parameter. We'll also use "on render start" to define a function
	// run when the control rendering starts.
	layer(RETAINED_TEST_LAYER)->add_static_text(TEST_MOUSE_HOVER, 1, 2, "Hover the mouse over me!", WHITE, BLACK);
	layer(RETAINED_TEST_LAYER)->control(TEST_MOUSE_HOVER)->on_render_start = [] (gui_control_t * control) {
		auto static_text = static_cast<gui_static_text_t *>(control);
		static_text->background = BLACK;
		static_text->text = "Hover the mouse over me!";
	};
	layer(RETAINED_TEST_LAYER)->control(TEST_MOUSE_HOVER)->on_mouse_over = [] (gui_control_t * control, int terminal_x, int terminal_y) {
		auto static_text = static_cast<gui_static_text_t *>(control);
		static_text->background = RED;
		static_text->text = "Why Hello There!        ";
	};

	// A checkbox
	layer(RETAINED_TEST_LAYER)->add_checkbox(TEST_CHECKBOX, 1, 3, "I'm a checkbox - click me!", false, LIGHT_GREEN, BLACK);

	// A radioset
	layer(RETAINED_TEST_LAYER)->add_radioset(TEST_RADIOSET, 1, 5, "Test radio buttons", CYAN, BLACK, {
		{true, "Option A", 0}, {false, "Option B", 1}, {false, "Option C", 2}
	});

	// Main loop - calls the 'tick' function you defined for each frame.
	run(tick);

    return 0;
}
<commit_msg>Show some results in the panel for the GUI selection, to demo how to read data back.<commit_after>/* RLTK (RogueLike Tool Kit) 1.00
 * Copyright (c) 2016-Present, Bracket Productions.
 * Licensed under the LGPL - see LICENSE file.
 *
 * Example 7: Advanced GUI with retained-mode GUI elements and an owner-draw background.
 */

// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
#include <sstream>
#include <iomanip>

// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;

constexpr int BACKDROP_LAYER = 1;
constexpr int LOG_LAYER = 2;
constexpr int RETAINED_TEST_LAYER = 3;

constexpr int TEST_BOUNDARY_BOX = 1;
constexpr int TEST_STATIC_TEST = 2;
constexpr int TEST_MOUSE_HOVER = 3;
constexpr int TEST_CHECKBOX = 4;
constexpr int TEST_RADIOSET = 5;

void resize_bg(layer_t * l, int w, int h) {
	// Use the whole window
	l->w = w;
	l->h = h;
}

void draw_bg(layer_t * l, sf::RenderTexture &window) {
	sf::Texture * bg = get_texture("backdrop");
	sf::Sprite backdrop(*bg);
	window.draw(backdrop);
}

void resize_log(layer_t * l, int w, int h) {
	// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)
	l->w = w - 160;
	l->h = h - 32;

	// If the log window would take up the whole screen, hide it
	if (l->w < 0) {
		l->console->visible = false;
	} else {
		l->console->visible = true;
	}
	l->x = w - 160;
}

void resize_retained(layer_t * l, int w, int h) {
	// Do nothing - we'll just keep on rendering away.
	l->x = 100;
	l->y = 100;
	l->w = 400;
	l->h = 200;
}

// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
	term(LOG_LAYER)->clear(vchar{' ', WHITE, DARKEST_GREEN});
	term(LOG_LAYER)->box(DARKEST_GREEN, BLACK);

	if (static_cast<gui_checkbox_t *>(layer(RETAINED_TEST_LAYER)->control(TEST_CHECKBOX))->checked) {
		term(LOG_LAYER)->print(1,1, "Checked", LIGHTEST_GREEN, DARKEST_GREEN);
	} else {
		term(LOG_LAYER)->print(1,1, "Not Checked", DARK_GREEN, DARKEST_GREEN);
	}

	std::stringstream radio_ss;
	radio_ss << "Option: " << static_cast<gui_radiobuttons_t *>(layer(RETAINED_TEST_LAYER)->control(TEST_RADIOSET))->selected_value;
	term(LOG_LAYER)->print(1,2, radio_ss.str(), LIGHT_GREEN, DARKEST_GREEN);
	term(LOG_LAYER)->print(1,3, "Even more...", LIGHT_GREEN, DARKEST_GREEN);
	term(LOG_LAYER)->print(1,4, "... goes here", LIGHT_GREEN, DARKEST_GREEN);

	std::stringstream ss;
	ss << std::setiosflags(std::ios::fixed) << std::setprecision(0) << (1000.0/duration_ms) << " FPS";
	term(LOG_LAYER)->print(1,6, ss.str(), WHITE, DARKEST_GREEN);
}

// Your main function
int main()
{
	// This time, we're using a full initialization: width, height, window title, and "false" meaning we don't
	// want an automatically generated root console. This is necessary when you want to use the complex layout
	// functions.
	init(config_advanced("../assets"));

	// We're going to be using a bitmap, so we need to load it. The library makes this easy:
	register_texture("../assets/background_image.png", "backdrop");

	// Now we add an owner-draw background layer. "Owner-draw" means that it the library will ask it to
	// draw itself with a call-back function.
	gui->add_owner_layer(BACKDROP_LAYER, 0, 0, 1024, 768, resize_bg, draw_bg);
	gui->add_layer(LOG_LAYER, 864, 32, 160, 768-32, "8x16", resize_log);
	term(LOG_LAYER)->set_alpha(196); // Make the overlay translucent
	gui->add_layer(RETAINED_TEST_LAYER, 100, 100, 400, 200, "8x16", resize_retained);

	// Now we build some retained-mode controls. These don't require additional work during rendering
	// Note that we are providing a handle to the control. That lets us access it later with
	// layer(layerhandle)->control(controlhandle). It's up to you to store the handles; they can be any
	// int.
	layer(RETAINED_TEST_LAYER)->add_boundary_box(TEST_BOUNDARY_BOX, true, DARK_GREY, BLACK);
	layer(RETAINED_TEST_LAYER)->add_static_text(TEST_STATIC_TEST, 1, 1, "Retained Mode Static Text", YELLOW, BLACK);

	// For this control, we'll define an on-mouse-over. We're using a lambda, but it could be any function
	// with that takes a gui_control_t * as a parameter. We'll also use "on render start" to define a function
	// run when the control rendering starts.
	layer(RETAINED_TEST_LAYER)->add_static_text(TEST_MOUSE_HOVER, 1, 2, "Hover the mouse over me!", WHITE, BLACK);
	layer(RETAINED_TEST_LAYER)->control(TEST_MOUSE_HOVER)->on_render_start = [] (gui_control_t * control) {
		auto static_text = static_cast<gui_static_text_t *>(control);
		static_text->background = BLACK;
		static_text->text = "Hover the mouse over me!";
	};
	layer(RETAINED_TEST_LAYER)->control(TEST_MOUSE_HOVER)->on_mouse_over = [] (gui_control_t * control, int terminal_x, int terminal_y) {
		auto static_text = static_cast<gui_static_text_t *>(control);
		static_text->background = RED;
		static_text->text = "Why Hello There!        ";
	};

	// A checkbox
	layer(RETAINED_TEST_LAYER)->add_checkbox(TEST_CHECKBOX, 1, 3, "I'm a checkbox - click me!", false, LIGHT_GREEN, BLACK);

	// A radioset
	layer(RETAINED_TEST_LAYER)->add_radioset(TEST_RADIOSET, 1, 5, "Test radio buttons", CYAN, BLACK, {
		{true, "Option A", 0}, {false, "Option B", 1}, {false, "Option C", 2}
	});

	// Main loop - calls the 'tick' function you defined for each frame.
	run(tick);

    return 0;
}
<|endoftext|>


<commit_before>/// This example demonstrates a bot that accepts photos, analyses them and
/// presents information to the user, then downloads those photos to disk.
/// It also demonstrates how to use optional types safely to deal with
/// unexpected errors, and how to send chat actions.
/// It also shows how to switch to single-threaded mode.

#include <libtelegram/libtelegram.h>

auto main()->int {
  std::string const token("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11");
  telegram::sender sender(token);
  telegram::listener::poll listener(sender);

  auto to_kb = [](auto value){                                                  // helper lambda to convert values in bytes to kylobytes
    std::stringstream ss;
    ss << static_cast<float>(value) / 1024 << "KB";
    return ss.str();
  };

  listener.set_callback_message([&](telegram::types::message const &message){
    auto message_chat_id = message.chat.id;
    if(!message.photo) {                                                        // check if this message contains a list of photo sizes
      if(message.text && *message.text == "/start") {                           // if it doesn't, and they've asked to /start, give them help
        sender.send_message(message_chat_id, "Send me a photo.");
      }
      return;
    }
    auto const &photo_sizes(*message.photo);                                    // if it does, dereference the optional for later use
    sender.send_message(message_chat_id, std::string("I received a photo in the ") + std::to_string(photo_sizes.size()) + " following sizes:");
    unsigned int counter = 0;
    for(auto const &photo : photo_sizes) {                                      // iterate through the vector we've received
      ++counter;
      std::stringstream ss;
      ss << "Photo " << counter << " of " << photo_sizes.size()
         << ": size: " << photo.width << "x" << photo.height;                   // tell the user what we know about the photos
      if(photo.file_size) {
        ss << ", " << to_kb(*photo.file_size) << '\n';                          // use the kilobyte conversion lambda we made earlier
      } else {
        ss << ", size unknown" << '\n';
      }
      ss << "file_id: " << photo.file_id;
      sender.send_message(message_chat_id, ss.str());

      sender.send_chat_action(message_chat_id, telegram::sender::chat_action_type::TYPING); // show the user they should wait, we're typing
      auto const &file_optional(sender.get_file(photo.file_id));                // pass the photo's file_id to the get_file method
      if(!file_optional) {                                                      // we might not get a file back, so handle this gracefully
        sender.send_message(message_chat_id, "Something went wrong and I couldn't download the file.");
        return;
      }
      auto const &file(*file_optional);
      ss.str({});                                                               // clear and reuse the stringstream
      if(file.file_path) {
        ss << "file_path: " << *file.file_path << '\n';                         // this is the file path on the Telegram servers
      } else {
        ss << "file_path unknown" << '\n';                                      // file path is optional, so we need to handle the case where it's missing
      }
      if(file.file_size) {
        ss << "file_size: " << to_kb(*file.file_size) << '\n';                  // use the kilobyte conversion lambda we made earlier
      } else {
        ss << "file_size unknown" << '\n';                                      // file size is optional, so we need to handle the case where it's missing
      }
      //ss << "URL: " << file.get_url(token).to_string() << '\n';                 // NOTE: this contains your bot's token, so be careful!  Uncomment it for testing only.
      ss << "Downloading now...";
      sender.send_message(message_chat_id, ss.str());

      sender.send_chat_action(message_chat_id, telegram::sender::chat_action_type::RECORD_VIDEO); // show the user they should wait with a different action for a change
      auto file_blob(file.download(token));                                     // grab the file into a vector<char> in memory, with which we can do whatever we want
      ss.str({});
      ss << "Downloaded, file actual size: " << to_kb(file_blob.size());
      sender.send_message(message_chat_id, ss.str());
      std::string const filename(std::string("photo_" + file.file_id + ".jpg")); // give it a unique filename
      std::ofstream filestream(std::string("photo_" + file.file_id + ".jpg"), std::ios::binary); // make sure we write in binary mode
      ss.str({});
      filestream.write(file_blob.data(), file_blob.size());                     // write the binary blob to disk
      if(filestream.fail()) {                                                   // check if the write failed
        ss << "Failed to write to \"" << filename << "\"";
        std::cerr << "Error: could not write to \"" << filename << "\"" << std::endl; // also report the failure in the webserver log - it's probably a directory permissions issue
      } else {
        ss << "Wrote " << to_kb(filestream.tellp()) << " to \"" << filename << "\""; // if successful, report how much we wrote
      }
      sender.send_message(message_chat_id, ss.str());
    }
  });
  listener.set_num_threads(1);                                                  // run single-threaded to avoid thrashing the filesystem under heavy use
  listener.run();                                                               // launch the listener - this call blocks until the fastcgi server drops us
  return EXIT_SUCCESS;
};
<commit_msg>Fixed typo<commit_after>/// This example demonstrates a bot that accepts photos, analyses them and
/// presents information to the user, then downloads those photos to disk.
/// It also demonstrates how to use optional types safely to deal with
/// unexpected errors, and how to send chat actions.
/// It also shows how to switch to single-threaded mode.

#include <libtelegram/libtelegram.h>

auto main()->int {
  std::string const token("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11");
  telegram::sender sender(token);
  telegram::listener::poll listener(sender);

  auto to_kb = [](auto value){                                                  // helper lambda to convert values in bytes to kilobytes
    std::stringstream ss;
    ss << static_cast<float>(value) / 1024 << "KB";
    return ss.str();
  };

  listener.set_callback_message([&](telegram::types::message const &message){
    auto message_chat_id = message.chat.id;
    if(!message.photo) {                                                        // check if this message contains a list of photo sizes
      if(message.text && *message.text == "/start") {                           // if it doesn't, and they've asked to /start, give them help
        sender.send_message(message_chat_id, "Send me a photo.");
      }
      return;
    }
    auto const &photo_sizes(*message.photo);                                    // if it does, dereference the optional for later use
    sender.send_message(message_chat_id, std::string("I received a photo in the ") + std::to_string(photo_sizes.size()) + " following sizes:");
    unsigned int counter = 0;
    for(auto const &photo : photo_sizes) {                                      // iterate through the vector we've received
      ++counter;
      std::stringstream ss;
      ss << "Photo " << counter << " of " << photo_sizes.size()
         << ": size: " << photo.width << "x" << photo.height;                   // tell the user what we know about the photos
      if(photo.file_size) {
        ss << ", " << to_kb(*photo.file_size) << '\n';                          // use the kilobyte conversion lambda we made earlier
      } else {
        ss << ", size unknown" << '\n';
      }
      ss << "file_id: " << photo.file_id;
      sender.send_message(message_chat_id, ss.str());

      sender.send_chat_action(message_chat_id, telegram::sender::chat_action_type::TYPING); // show the user they should wait, we're typing
      auto const &file_optional(sender.get_file(photo.file_id));                // pass the photo's file_id to the get_file method
      if(!file_optional) {                                                      // we might not get a file back, so handle this gracefully
        sender.send_message(message_chat_id, "Something went wrong and I couldn't download the file.");
        return;
      }
      auto const &file(*file_optional);
      ss.str({});                                                               // clear and reuse the stringstream
      if(file.file_path) {
        ss << "file_path: " << *file.file_path << '\n';                         // this is the file path on the Telegram servers
      } else {
        ss << "file_path unknown" << '\n';                                      // file path is optional, so we need to handle the case where it's missing
      }
      if(file.file_size) {
        ss << "file_size: " << to_kb(*file.file_size) << '\n';                  // use the kilobyte conversion lambda we made earlier
      } else {
        ss << "file_size unknown" << '\n';                                      // file size is optional, so we need to handle the case where it's missing
      }
      //ss << "URL: " << file.get_url(token).to_string() << '\n';                 // NOTE: this contains your bot's token, so be careful!  Uncomment it for testing only.
      ss << "Downloading now...";
      sender.send_message(message_chat_id, ss.str());

      sender.send_chat_action(message_chat_id, telegram::sender::chat_action_type::RECORD_VIDEO); // show the user they should wait with a different action for a change
      auto file_blob(file.download(token));                                     // grab the file into a vector<char> in memory, with which we can do whatever we want
      ss.str({});
      ss << "Downloaded, file actual size: " << to_kb(file_blob.size());
      sender.send_message(message_chat_id, ss.str());
      std::string const filename(std::string("photo_" + file.file_id + ".jpg")); // give it a unique filename
      std::ofstream filestream(std::string("photo_" + file.file_id + ".jpg"), std::ios::binary); // make sure we write in binary mode
      ss.str({});
      filestream.write(file_blob.data(), file_blob.size());                     // write the binary blob to disk
      if(filestream.fail()) {                                                   // check if the write failed
        ss << "Failed to write to \"" << filename << "\"";
        std::cerr << "Error: could not write to \"" << filename << "\"" << std::endl; // also report the failure in the webserver log - it's probably a directory permissions issue
      } else {
        ss << "Wrote " << to_kb(filestream.tellp()) << " to \"" << filename << "\""; // if successful, report how much we wrote
      }
      sender.send_message(message_chat_id, ss.str());
    }
  });
  listener.set_num_threads(1);                                                  // run single-threaded to avoid thrashing the filesystem under heavy use
  listener.run();                                                               // launch the listener - this call blocks until the fastcgi server drops us
  return EXIT_SUCCESS;
};
<|endoftext|>