<commit_before>/********************************************************************
* Description: emctask.cc
*   Mode and state management for EMC_TASK class
*
*   Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
* $Revision$
* $Author$
* $Date$
********************************************************************/

#include <stdlib.h>
#include <string.h>		// strncpy()
#include <sys/stat.h>		// struct stat
#include <unistd.h>		// stat()

#include "rcs.hh"		// INIFILE
#include "emc.hh"		// EMC NML
#include "emcglb.h"		// EMC_INIFILE
#include "interpl.hh"		// NML_INTERP_LIST, interp_list
#include "canon.hh"		// CANON_VECTOR, GET_PROGRAM_ORIGIN()
#include "rs274ngc.hh"		// the interpreter
#include "interp_return.hh"	// INTERP_FILE_NOT_OPEN

/* flag for how we want to interpret traj coord mode, as mdi or auto */
static int mdiOrAuto = EMC_TASK_MODE_AUTO;

Interp interp;

// EMC_TASK interface

/*
  format string for user-defined programs, e.g., "programs/M1%02d" means
  user-defined programs are in the programs/ directory and are named
  M1XX, where XX is a two-digit string.
*/

static char user_defined_fmt[EMC_SYSTEM_CMD_LEN] = "nc_files/M1%02d";

static void user_defined_add_m_code(int num, double arg1, double arg2)
{
    char fmt[EMC_SYSTEM_CMD_LEN];
    EMC_SYSTEM_CMD system_cmd;

    strcpy(fmt, user_defined_fmt);
    strcat(fmt, " %f %f");
    sprintf(system_cmd.string, fmt, num, arg1, arg2);
    interp_list.append(system_cmd);
}

int emcTaskInit()
{
    int index;
    char path[EMC_SYSTEM_CMD_LEN];
    struct stat buf;
    Inifile inifile;
    const char *inistring;

    // read out directory where programs are located
    inifile.open(EMC_INIFILE);
    inistring = inifile.find("PROGRAM_PREFIX", "DISPLAY");
    inifile.close();

    // if we have a program prefix, override the default user_defined_fmt
    // string with program prefix, then "M1%02d", e.g.
    // nc_files/M101, where the %%02d means 2 digits after the M code
    // and we need two % to get the literal %
    if (NULL != inistring) {
	sprintf(user_defined_fmt, "%sM1%%02d", inistring);
    }

    /* check for programs named programs/M100 .. programs/M199 and add
       any to the user defined functions list */
    for (index = 0; index < USER_DEFINED_FUNCTION_NUM; index++) {
	sprintf(path, user_defined_fmt, index);
	if (0 == stat(path, &buf)) {
	    if (buf.st_mode & S_IXUSR) {
		USER_DEFINED_FUNCTION_ADD(user_defined_add_m_code, index);
		if (EMC_DEBUG & EMC_DEBUG_CONFIG) {
		    rcs_print
			("emcTaskInit: adding user-defined function %s\n",
			 path);
		}
	    } else {
		if (EMC_DEBUG & EMC_DEBUG_CONFIG) {
		    rcs_print
			("emcTaskInit: user-defined function %s found, but not executable, so ignoring\n",
			 path);
		}
	    }
	}
    }

    return 0;
}

int emcTaskHalt()
{
    return 0;
}

int emcTaskAbort()
{
    emcMotionAbort();
    emcIoAbort();

    return 0;
}

int emcTaskSetMode(int mode)
{
    int retval = 0;

    switch (mode) {
    case EMC_TASK_MODE_MANUAL:
	// go to manual mode
	emcTrajSetMode(EMC_TRAJ_MODE_FREE);
	mdiOrAuto = EMC_TASK_MODE_AUTO;	// we'll default back to here
	break;

    case EMC_TASK_MODE_MDI:
	// go to mdi mode
	emcTrajSetMode(EMC_TRAJ_MODE_COORD);
	emcTaskPlanSynch();
	mdiOrAuto = EMC_TASK_MODE_MDI;
	break;

    case EMC_TASK_MODE_AUTO:
	// go to auto mode
	emcTrajSetMode(EMC_TRAJ_MODE_COORD);
	emcTaskPlanSynch();
	mdiOrAuto = EMC_TASK_MODE_AUTO;
	break;

    default:
	retval = -1;
	break;
    }

    return retval;
}

int emcTaskSetState(int state)
{
    int t;
    int retval = 0;

    switch (state) {
    case EMC_TASK_STATE_OFF:
	// turn the machine servos off-- go into READY state
	for (t = 0; t < emcStatus->motion.traj.axes; t++) {
	    emcAxisDisable(t);
	}
	emcTrajDisable();
	emcLubeOff();
	break;

    case EMC_TASK_STATE_ON:
	// turn the machine servos on
	emcTrajEnable();
	for (t = 0; t < emcStatus->motion.traj.axes; t++) {
	    emcAxisEnable(t);
	}
	emcLubeOn();
	break;

    case EMC_TASK_STATE_ESTOP_RESET:
	// reset the estop
	emcAuxEstopOff();
	emcLubeOff();
	break;

    case EMC_TASK_STATE_ESTOP:
	// go into estop-- do both IO estop and machine servos off
	emcAuxEstopOn();
	for (t = 0; t < emcStatus->motion.traj.axes; t++) {
	    emcAxisDisable(t);
	}
	emcTrajDisable();
	emcLubeOff();
	break;

    default:
	retval = -1;
	break;
    }

    return retval;
}

// WM access functions

/*
  determineMode()

  Looks at mode of subsystems, and returns associated mode

  Depends on traj mode, and mdiOrAuto flag

  traj mode   mdiOrAuto     mode
  ---------   ---------     ----
  FREE        XXX           MANUAL
  COORD       MDI           MDI
  COORD       AUTO          AUTO
  */
static int determineMode()
{
    // if traj is in free mode, then we're in manual mode
    if (emcStatus->motion.traj.mode == EMC_TRAJ_MODE_FREE ||
	emcStatus->motion.traj.mode == EMC_TRAJ_MODE_TELEOP) {
	return EMC_TASK_MODE_MANUAL;
    }
    // else traj is in coord mode-- we can be in either mdi or auto
    return mdiOrAuto;
}

/*
  determineState()

  Looks at state of subsystems, and returns associated state

  Depends on traj enabled, io estop, and desired task state

  traj enabled   io estop      state
  ------------   --------      -----
  DISABLED       ESTOP         ESTOP
  ENABLED        ESTOP         ESTOP
  DISABLED       OUT OF ESTOP  ESTOP_RESET
  ENABLED        OUT OF ESTOP  ON
  */
static int determineState()
{
    if (emcStatus->io.aux.estop) {
	return EMC_TASK_STATE_ESTOP;
    }

    if (!emcStatus->motion.traj.enabled) {
	return EMC_TASK_STATE_ESTOP_RESET;
    }

    return EMC_TASK_STATE_ON;
}

static int waitFlag = 0;

static char interp_error_text_buf[LINELEN];
static char interp_stack_buf[LINELEN];

static void print_interp_error(int retval)
{
    int index = 0;
    if (retval == 0) {
	return;
    }

    if (0 != emcStatus) {
	emcStatus->task.interpreter_errcode = retval;
    }

    interp_error_text_buf[0] = 0;
    interp.error_text(retval, interp_error_text_buf, LINELEN);
    if (0 != interp_error_text_buf[0]) {
	rcs_print_error("interp_error: %s\n", interp_error_text_buf);
    }
    emcOperatorError(0, interp_error_text_buf);
    index = 0;
    if (EMC_DEBUG & EMC_DEBUG_INTERP) {
	rcs_print("Interpreter stack: \t");
	while (index < 5) {
	    interp_stack_buf[0] = 0;
	    interp.stack_name(index, interp_stack_buf, LINELEN);
	    if (0 == interp_stack_buf[0]) {
		break;
	    }
	    rcs_print(" - %s ", interp_stack_buf);
	    index++;
	}
	rcs_print("\n");
    }
}

int emcTaskPlanInit()
{
    interp.ini_load(EMC_INIFILE);
    waitFlag = 0;

    int retval = interp.init();
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    } else {
	if (0 != RS274NGC_STARTUP_CODE[0]) {
	    retval = interp.execute(RS274NGC_STARTUP_CODE);
	    if (retval > INTERP_MIN_ERROR) {
		print_interp_error(retval);
	    }
	}
    }
    return retval;
}

int emcTaskPlanSetWait()
{
    waitFlag = 1;

    return 0;
}

int emcTaskPlanIsWait()
{
    return waitFlag;
}

int emcTaskPlanClearWait()
{
    waitFlag = 0;

    return 0;
}

int emcTaskPlanSynch()
{
    return interp.synch();
}

int emcTaskPlanExit()
{
    return interp.exit();
}

int emcTaskPlanOpen(const char *file)
{
    if (emcStatus != 0) {
	emcStatus->task.motionLine = 0;
	emcStatus->task.currentLine = 0;
	emcStatus->task.readLine = 0;
    }

    int retval = interp.open(file);
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
	return retval;
    }
    taskplanopen = 1;
    return retval;
}

int emcTaskPlanRead()
{
    int retval = interp.read();
    if (retval == INTERP_FILE_NOT_OPEN) {
	if (emcStatus->task.file[0] != 0) {
	    retval = interp.open(emcStatus->task.file);
	    if (retval > INTERP_MIN_ERROR) {
		print_interp_error(retval);
	    }
	    retval = interp.read();
	}
    }
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    }
    return retval;
}

int emcTaskPlanExecute(const char *command)
{
    int inpos = emcStatus->motion.traj.inpos;	// 1 if in position, 0 if not.

    if (command != 0) {		// Command is 0 if in AUTO mode, non-null if in MDI mode.
	// Don't sync if not in position.
	if ((*command != 0) && (inpos)) {
	    interp.synch();
	}
    }
    int retval = interp.execute(command);
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    }
    return retval;
}

int emcTaskPlanClose()
{
    int retval = interp.close();
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    }

    taskplanopen = 0;
    return retval;
}

int emcTaskPlanLine()
{
    return interp.line();
}

int emcTaskPlanCommand(char *cmd)
{
    char buf[LINELEN];

    strcpy(cmd, interp.command(buf, LINELEN));
    return 0;
}

int emcTaskUpdate(EMC_TASK_STAT * stat)
{
    stat->mode = (enum EMC_TASK_MODE_ENUM) determineMode();
    stat->state = (enum EMC_TASK_STATE_ENUM) determineState();

    // execState set in main
    // interpState set in main
    if (emcStatus->motion.traj.id > 0) {
	stat->motionLine = emcStatus->motion.traj.id;
    }
    // currentLine set in main
    // readLine set in main

    char buf[LINELEN];
    strcpy(stat->file, interp.file(buf, LINELEN));
    // command set in main

    // update active G and M codes
    interp.active_g_codes(&stat->activeGCodes[0]);
    interp.active_m_codes(&stat->activeMCodes[0]);
    interp.active_settings(&stat->activeSettings[0]);

    stat->heartbeat++;

    return 0;
}

<commit_msg>make sure that M1xx programs are still found even when [DISPLAY]PROGRAM_PREFIX does not end with a slash<commit_after>/********************************************************************
* Description: emctask.cc
*   Mode and state management for EMC_TASK class
*
*   Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
* $Revision$
* $Author$
* $Date$
********************************************************************/

#include <stdlib.h>
#include <string.h>		// strncpy()
#include <sys/stat.h>		// struct stat
#include <unistd.h>		// stat()

#include "rcs.hh"		// INIFILE
#include "emc.hh"		// EMC NML
#include "emcglb.h"		// EMC_INIFILE
#include "interpl.hh"		// NML_INTERP_LIST, interp_list
#include "canon.hh"		// CANON_VECTOR, GET_PROGRAM_ORIGIN()
#include "rs274ngc.hh"		// the interpreter
#include "interp_return.hh"	// INTERP_FILE_NOT_OPEN

/* flag for how we want to interpret traj coord mode, as mdi or auto */
static int mdiOrAuto = EMC_TASK_MODE_AUTO;

Interp interp;

// EMC_TASK interface

/*
  format string for user-defined programs, e.g., "programs/M1%02d" means
  user-defined programs are in the programs/ directory and are named
  M1XX, where XX is a two-digit string.
*/

static char user_defined_fmt[EMC_SYSTEM_CMD_LEN] = "nc_files/M1%02d";

static void user_defined_add_m_code(int num, double arg1, double arg2)
{
    char fmt[EMC_SYSTEM_CMD_LEN];
    EMC_SYSTEM_CMD system_cmd;

    strcpy(fmt, user_defined_fmt);
    strcat(fmt, " %f %f");
    sprintf(system_cmd.string, fmt, num, arg1, arg2);
    interp_list.append(system_cmd);
}

int emcTaskInit()
{
    int index;
    char path[EMC_SYSTEM_CMD_LEN];
    struct stat buf;
    Inifile inifile;
    const char *inistring;

    // read out directory where programs are located
    inifile.open(EMC_INIFILE);
    inistring = inifile.find("PROGRAM_PREFIX", "DISPLAY");
    inifile.close();

    // if we have a program prefix, override the default user_defined_fmt
    // string with program prefix, then "M1%02d", e.g.
    // nc_files/M101, where the %%02d means 2 digits after the M code
    // and we need two % to get the literal %
    if (NULL != inistring) {
	sprintf(user_defined_fmt, "%s/M1%%02d", inistring);
    }

    /* check for programs named programs/M100 .. programs/M199 and add
       any to the user defined functions list */
    for (index = 0; index < USER_DEFINED_FUNCTION_NUM; index++) {
	sprintf(path, user_defined_fmt, index);
	if (0 == stat(path, &buf)) {
	    if (buf.st_mode & S_IXUSR) {
		USER_DEFINED_FUNCTION_ADD(user_defined_add_m_code, index);
		if (EMC_DEBUG & EMC_DEBUG_CONFIG) {
		    rcs_print
			("emcTaskInit: adding user-defined function %s\n",
			 path);
		}
	    } else {
		if (EMC_DEBUG & EMC_DEBUG_CONFIG) {
		    rcs_print
			("emcTaskInit: user-defined function %s found, but not executable, so ignoring\n",
			 path);
		}
	    }
	}
    }

    return 0;
}

int emcTaskHalt()
{
    return 0;
}

int emcTaskAbort()
{
    emcMotionAbort();
    emcIoAbort();

    return 0;
}

int emcTaskSetMode(int mode)
{
    int retval = 0;

    switch (mode) {
    case EMC_TASK_MODE_MANUAL:
	// go to manual mode
	emcTrajSetMode(EMC_TRAJ_MODE_FREE);
	mdiOrAuto = EMC_TASK_MODE_AUTO;	// we'll default back to here
	break;

    case EMC_TASK_MODE_MDI:
	// go to mdi mode
	emcTrajSetMode(EMC_TRAJ_MODE_COORD);
	emcTaskPlanSynch();
	mdiOrAuto = EMC_TASK_MODE_MDI;
	break;

    case EMC_TASK_MODE_AUTO:
	// go to auto mode
	emcTrajSetMode(EMC_TRAJ_MODE_COORD);
	emcTaskPlanSynch();
	mdiOrAuto = EMC_TASK_MODE_AUTO;
	break;

    default:
	retval = -1;
	break;
    }

    return retval;
}

int emcTaskSetState(int state)
{
    int t;
    int retval = 0;

    switch (state) {
    case EMC_TASK_STATE_OFF:
	// turn the machine servos off-- go into READY state
	for (t = 0; t < emcStatus->motion.traj.axes; t++) {
	    emcAxisDisable(t);
	}
	emcTrajDisable();
	emcLubeOff();
	break;

    case EMC_TASK_STATE_ON:
	// turn the machine servos on
	emcTrajEnable();
	for (t = 0; t < emcStatus->motion.traj.axes; t++) {
	    emcAxisEnable(t);
	}
	emcLubeOn();
	break;

    case EMC_TASK_STATE_ESTOP_RESET:
	// reset the estop
	emcAuxEstopOff();
	emcLubeOff();
	break;

    case EMC_TASK_STATE_ESTOP:
	// go into estop-- do both IO estop and machine servos off
	emcAuxEstopOn();
	for (t = 0; t < emcStatus->motion.traj.axes; t++) {
	    emcAxisDisable(t);
	}
	emcTrajDisable();
	emcLubeOff();
	break;

    default:
	retval = -1;
	break;
    }

    return retval;
}

// WM access functions

/*
  determineMode()

  Looks at mode of subsystems, and returns associated mode

  Depends on traj mode, and mdiOrAuto flag

  traj mode   mdiOrAuto     mode
  ---------   ---------     ----
  FREE        XXX           MANUAL
  COORD       MDI           MDI
  COORD       AUTO          AUTO
  */
static int determineMode()
{
    // if traj is in free mode, then we're in manual mode
    if (emcStatus->motion.traj.mode == EMC_TRAJ_MODE_FREE ||
	emcStatus->motion.traj.mode == EMC_TRAJ_MODE_TELEOP) {
	return EMC_TASK_MODE_MANUAL;
    }
    // else traj is in coord mode-- we can be in either mdi or auto
    return mdiOrAuto;
}

/*
  determineState()

  Looks at state of subsystems, and returns associated state

  Depends on traj enabled, io estop, and desired task state

  traj enabled   io estop      state
  ------------   --------      -----
  DISABLED       ESTOP         ESTOP
  ENABLED        ESTOP         ESTOP
  DISABLED       OUT OF ESTOP  ESTOP_RESET
  ENABLED        OUT OF ESTOP  ON
  */
static int determineState()
{
    if (emcStatus->io.aux.estop) {
	return EMC_TASK_STATE_ESTOP;
    }

    if (!emcStatus->motion.traj.enabled) {
	return EMC_TASK_STATE_ESTOP_RESET;
    }

    return EMC_TASK_STATE_ON;
}

static int waitFlag = 0;

static char interp_error_text_buf[LINELEN];
static char interp_stack_buf[LINELEN];

static void print_interp_error(int retval)
{
    int index = 0;
    if (retval == 0) {
	return;
    }

    if (0 != emcStatus) {
	emcStatus->task.interpreter_errcode = retval;
    }

    interp_error_text_buf[0] = 0;
    interp.error_text(retval, interp_error_text_buf, LINELEN);
    if (0 != interp_error_text_buf[0]) {
	rcs_print_error("interp_error: %s\n", interp_error_text_buf);
    }
    emcOperatorError(0, interp_error_text_buf);
    index = 0;
    if (EMC_DEBUG & EMC_DEBUG_INTERP) {
	rcs_print("Interpreter stack: \t");
	while (index < 5) {
	    interp_stack_buf[0] = 0;
	    interp.stack_name(index, interp_stack_buf, LINELEN);
	    if (0 == interp_stack_buf[0]) {
		break;
	    }
	    rcs_print(" - %s ", interp_stack_buf);
	    index++;
	}
	rcs_print("\n");
    }
}

int emcTaskPlanInit()
{
    interp.ini_load(EMC_INIFILE);
    waitFlag = 0;

    int retval = interp.init();
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    } else {
	if (0 != RS274NGC_STARTUP_CODE[0]) {
	    retval = interp.execute(RS274NGC_STARTUP_CODE);
	    if (retval > INTERP_MIN_ERROR) {
		print_interp_error(retval);
	    }
	}
    }
    return retval;
}

int emcTaskPlanSetWait()
{
    waitFlag = 1;

    return 0;
}

int emcTaskPlanIsWait()
{
    return waitFlag;
}

int emcTaskPlanClearWait()
{
    waitFlag = 0;

    return 0;
}

int emcTaskPlanSynch()
{
    return interp.synch();
}

int emcTaskPlanExit()
{
    return interp.exit();
}

int emcTaskPlanOpen(const char *file)
{
    if (emcStatus != 0) {
	emcStatus->task.motionLine = 0;
	emcStatus->task.currentLine = 0;
	emcStatus->task.readLine = 0;
    }

    int retval = interp.open(file);
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
	return retval;
    }
    taskplanopen = 1;
    return retval;
}

int emcTaskPlanRead()
{
    int retval = interp.read();
    if (retval == INTERP_FILE_NOT_OPEN) {
	if (emcStatus->task.file[0] != 0) {
	    retval = interp.open(emcStatus->task.file);
	    if (retval > INTERP_MIN_ERROR) {
		print_interp_error(retval);
	    }
	    retval = interp.read();
	}
    }
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    }
    return retval;
}

int emcTaskPlanExecute(const char *command)
{
    int inpos = emcStatus->motion.traj.inpos;	// 1 if in position, 0 if not.

    if (command != 0) {		// Command is 0 if in AUTO mode, non-null if in MDI mode.
	// Don't sync if not in position.
	if ((*command != 0) && (inpos)) {
	    interp.synch();
	}
    }
    int retval = interp.execute(command);
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    }
    return retval;
}

int emcTaskPlanClose()
{
    int retval = interp.close();
    if (retval > INTERP_MIN_ERROR) {
	print_interp_error(retval);
    }

    taskplanopen = 0;
    return retval;
}

int emcTaskPlanLine()
{
    return interp.line();
}

int emcTaskPlanCommand(char *cmd)
{
    char buf[LINELEN];

    strcpy(cmd, interp.command(buf, LINELEN));
    return 0;
}

int emcTaskUpdate(EMC_TASK_STAT * stat)
{
    stat->mode = (enum EMC_TASK_MODE_ENUM) determineMode();
    stat->state = (enum EMC_TASK_STATE_ENUM) determineState();

    // execState set in main
    // interpState set in main
    if (emcStatus->motion.traj.id > 0) {
	stat->motionLine = emcStatus->motion.traj.id;
    }
    // currentLine set in main
    // readLine set in main

    char buf[LINELEN];
    strcpy(stat->file, interp.file(buf, LINELEN));
    // command set in main

    // update active G and M codes
    interp.active_g_codes(&stat->activeGCodes[0]);
    interp.active_m_codes(&stat->activeMCodes[0]);
    interp.active_settings(&stat->activeSettings[0]);

    stat->heartbeat++;

    return 0;
}

<|endoftext|>


<commit_before>/* OpenHoW
 * Copyright (C) 2017-2020 Mark Sowden <markelswo@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <PL/platform_graphics.h>
#include <PL/platform_graphics_camera.h>
#include <PL/platform_filesystem.h>

#include "engine.h"
#include "input.h"
#include "frontend.h"
#include "Map.h"
#include "game/TempGame.h"
#include "graphics/font.h"
#include "graphics/display.h"
#include "graphics/video.h"

using namespace openhow;

static unsigned int frontend_state = FE_MODE_INIT;
static unsigned int old_frontend_state = (unsigned int) -1;

/* for now we're going to hard-code most of this but eventually
 * we will start freeing most of this up... either through JS
 * or some other way, so y'know. Wheeee.
 */

static const char* papers_teams_paths[MAX_TEAMS] = {
    "frontend/papers/british.bmp",
    "frontend/papers/american.bmp",
    "frontend/papers/french.bmp",
    "frontend/papers/german.bmp",
    "frontend/papers/russian.bmp",
    "frontend/papers/japan.bmp",
    "frontend/papers/teamlard.bmp"
};

/* texture assets, these are loaded and free'd at runtime */
static PLTexture* fe_background = nullptr;
static PLTexture* fe_papers_teams[MAX_TEAMS] = {
    nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};

enum {
  FE_TEXTURE_ANG,
  FE_TEXTURE_ANGPOINT,

  FE_TEXTURE_CLOCK,
  FE_TEXTURE_TIMER,
  FE_TEXTURE_CLIGHT,

  FE_TEXTURE_CROSSHAIR,
  FE_TEXTURE_TARGET,

  FE_TEXTURE_ARROW,
  FE_TEXTURE_CROSS,

  FE_TEXTURE_PAUSE,

  MAX_FE_GAME_TEXTURES
};
static PLTexture* fe_tx_game_textures[MAX_FE_GAME_TEXTURES];  /* textures that we'll be using in-game */
//static PLTexture *fe_tx_game_icons[MAX_ITEM_TYPES];

static int frontend_width = 0;
static int frontend_height = 0;

/************************************************************/

static void FrontendInputCallback(int key, bool is_pressed) {
  if (frontend_state == FE_MODE_START && is_pressed) {
    /* todo, play 'ting' sound! */

    /* we've hit our key, we can take away this
     * callback now and carry on to whatever */
    Input_SetKeyboardFocusCallback(nullptr);
    FrontEnd_SetState(FE_MODE_MAIN_MENU);
    return;
  }
}

static void CacheFEGameData() {
  fe_tx_game_textures[FE_TEXTURE_ANG] =
      Engine::Resource()->LoadTexture("frontend/dash/ang", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_ANGPOINT] =
      Engine::Resource()->LoadTexture("frontend/dash/angpoint", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_CLOCK] =
      Engine::Resource()->LoadTexture("frontend/dash/clock", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_CLIGHT] =
      Engine::Resource()->LoadTexture("frontend/dash/timlit.png", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_TIMER] =
      Engine::Resource()->LoadTexture("frontend/dash/timer", PL_TEXTURE_FILTER_LINEAR, true);
}

static void CacheFEMenuData() {
  fe_background = Engine::Resource()->LoadTexture("frontend/pigbkpc1", PL_TEXTURE_FILTER_LINEAR, true);
  for (unsigned int i = 0; i < MAX_TEAMS; ++i) {
    fe_papers_teams[i] = Engine::Resource()->LoadTexture(papers_teams_paths[i], PL_TEXTURE_FILTER_LINEAR, true);
  }
}

/************************************************************/

void FE_Initialize(void) {
  CacheFontData();
  CacheFEMenuData();
  CacheFEGameData();
}

void FE_Shutdown(void) {
  ClearFontData();
}

void FE_ProcessInput(void) {
  switch (frontend_state) {
    default:break;

    case FE_MODE_START: {
      /* this is... kind of a hack... but ensures that
       * nothing will take away our check for a key during
       * the 'start' screen, e.g. bringing the console up */
      Input_SetKeyboardFocusCallback(FrontendInputCallback);
    }
      break;

    case FE_MODE_VIDEO: {
      if (Input_GetKeyState(INPUT_KEY_SPACE) || Input_GetKeyState(INPUT_KEY_ESCAPE)) {
        Video_SkipCurrent();
      }
    }
      break;
  }
}

void FrontEnd_Tick(void) {}

/************************************************************/

char loading_description[256];
uint8_t loading_progress = 0;

#define Redraw()   Display_DrawInterface();

void FE_SetLoadingBackground(const char* name) {
  char screen_path[PL_SYSTEM_MAX_PATH];
  snprintf(screen_path, sizeof(screen_path), "frontend/briefing/%s", name);
  if (!plFileExists(screen_path)) {
    snprintf(screen_path, sizeof(screen_path), "frontend/briefing/loadmult");
  }

  fe_background = Engine::Resource()->LoadTexture(screen_path, PL_TEXTURE_FILTER_LINEAR);
  Redraw();
}

void FE_SetLoadingDescription(const char* description) {
  snprintf(loading_description, sizeof(loading_description), "%s ...", description);
  Redraw();
}

void FE_SetLoadingProgress(uint8_t progress) {
  if (progress > 100) progress = 100;
  loading_progress = progress;
  Redraw();
}

uint8_t FE_GetLoadingProgress(void) {
  return loading_progress;
}

/************************************************************/

/**
 * Draw the timer in the bottom corner of the screen.
 */
static void DrawTimer() {
  if (FrontEnd_GetState() != FE_MODE_GAME) {
    return;
  }

  IGameMode* mode = Engine::Game()->GetMode();
  if(!mode->HasRoundStarted()) {
    return;
  }

  char str[64];
  snprintf(str, sizeof(str), "%0d / %0d", mode->GetTurnTimeSeconds(), mode->GetMaxTurnTimeSeconds());
  Font_DrawBitmapString(g_fonts[FONT_BIG], frontend_width - 256, frontend_height - 100, 4, 1.0f, PL_COLOUR_WHITE, str);
}

/**
 * Draw the minimap on the button left corner of the screen.
 */
static void DrawMinimap() {
  if (FrontEnd_GetState() != FE_MODE_GAME) {
    return;
  }

  Map* map = openhow::Engine::Game()->GetCurrentMap();
  if (map == nullptr) {
    return;
  }

#if 0
  static PLMesh* pane = nullptr;
  if(pane == nullptr) {
      pane = plNewMeshRectangle(0, 0, 256, 256, PL_COLOUR_WHITE);
      if(pane == nullptr) {
          Error("Failed to create pane mesh!\n");
      }
  }

  plSetTexture(map->GetOverviewTexture(), 0);

  PLMatrix4x4 mat = plMatrix4x4Identity();
  plSetNamedShaderUniformMatrix4x4(NULL, "pl_model", mat, false);

  plUploadMesh(pane);
  plDrawMesh(pane);

  plSetTexture(nullptr, 0);
#else
  /* for debugging... */
  unsigned int scr_h = Display_GetViewportHeight(&g_state.ui_camera->viewport);
  plDrawTexturedRectangle(0, scr_h - 128, 128, 128, map->GetTerrain()->GetOverview());
#endif
}

/* Hogs of War's menu was designed
 * with a fixed resolution in mind
 * and scales poorly with anything
 * else. For now we'll just keep
 * things fixed and worry about this
 * later. */

static void DrawLoadingScreen() {
  plDrawTexturedRectangle(0, 0, frontend_width, frontend_height, fe_background);

  /* originally I wrote some code ensuring the menu bar
   * was centered... that was until I found out that on
   * the background, the slot for the bar ISN'T centered
   * at all. JOY... */
  static const int bar_w = 330;
  int bar_x = 151; //c_x + (FRONTEND_MENU_WIDTH / 2) - bar_w / 2;
  int bar_y = 450;
  if (loading_progress > 0) {
    plDrawFilledRectangle(plCreateRectangle(
        PLVector2(bar_x, bar_y),
        PLVector2(((float) (bar_w) / 100) * loading_progress, 18),
        PL_COLOUR_INDIAN_RED,
        PL_COLOUR_INDIAN_RED,
        PL_COLOUR_RED,
        PL_COLOUR_RED
    ));
  }

  if (loading_description[0] != ' ' && loading_description[0] != '\0') {
    Font_DrawBitmapString(g_fonts[FONT_CHARS2], bar_x + 2, bar_y + 1, 4, 1.f, PL_COLOUR_WHITE, loading_description);
  }
}

void FE_Draw(void) {
  frontend_width = Display_GetViewportWidth(&g_state.ui_camera->viewport);
  frontend_height = Display_GetViewportHeight(&g_state.ui_camera->viewport);

  /* render and handle the main menu */
  if (frontend_state != FE_MODE_GAME) { // todo: what's going on here... ?
    switch (frontend_state) {
      default:break;

      case FE_MODE_INIT:
      case FE_MODE_START:
      case FE_MODE_MAIN_MENU:
        plDrawTexturedRectangle(0, 0, frontend_width, frontend_height, fe_background);
        break;

      case FE_MODE_LOADING:
        DrawLoadingScreen();
        break;

      case FE_MODE_VIDEO:
        Video_Draw();
        break;
    }

    return;
  }

  DrawMinimap();
  DrawTimer();
}

/* * * * * * * * * * * * * * * * * * * * * * */

void FE_RestoreLastState(void) {
  FrontEnd_SetState(old_frontend_state);
}

unsigned int FrontEnd_GetState(void) {
  return frontend_state;
}

void FrontEnd_SetState(unsigned int state) {
  if (state == frontend_state) {
    LogDebug("attempted to set debug state to an already existing state!\n");
    return;
  }

  LogDebug("changing frontend state to %u...\n", state);
  switch (state) {
    default: {
      LogWarn("invalid frontend state, %u, aborting\n", state);
      return;
    }

    case FE_MODE_MAIN_MENU:
      // start playing the default theme
      Engine::Audio()->PlayMusic(AUDIO_MUSIC_MENU);
      break;

    case FE_MODE_START: break;

    case FE_MODE_GAME: {
      // game mode handles music from here?
    }
      break;

    case FE_MODE_LOADING: {
      // stop the music as soon as we switch to a loading screen...
      Engine::Audio()->StopMusic();

      loading_description[0] = '\0';
      loading_progress = 0;
      break;
    }

    case FE_MODE_EDITOR: break;
  }
  old_frontend_state = frontend_state;
  frontend_state = state;

  /* !!hacky!! force the display to update due to aspect change, yeah this is gross... */
  Display_UpdateViewport(0, 0, cv_display_width->i_value, cv_display_height->i_value);
}

<commit_msg>stub out redraw for frontend until this is rewritten<commit_after>/* OpenHoW
 * Copyright (C) 2017-2020 Mark Sowden <markelswo@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <PL/platform_graphics.h>
#include <PL/platform_graphics_camera.h>
#include <PL/platform_filesystem.h>

#include "engine.h"
#include "input.h"
#include "frontend.h"
#include "Map.h"
#include "game/TempGame.h"
#include "graphics/font.h"
#include "graphics/display.h"
#include "graphics/video.h"

using namespace openhow;

static unsigned int frontend_state = FE_MODE_INIT;
static unsigned int old_frontend_state = (unsigned int) -1;

/* for now we're going to hard-code most of this but eventually
 * we will start freeing most of this up... either through JS
 * or some other way, so y'know. Wheeee.
 */

static const char* papers_teams_paths[MAX_TEAMS] = {
    "frontend/papers/british.bmp",
    "frontend/papers/american.bmp",
    "frontend/papers/french.bmp",
    "frontend/papers/german.bmp",
    "frontend/papers/russian.bmp",
    "frontend/papers/japan.bmp",
    "frontend/papers/teamlard.bmp"
};

/* texture assets, these are loaded and free'd at runtime */
static PLTexture* fe_background = nullptr;
static PLTexture* fe_papers_teams[MAX_TEAMS] = {
    nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};

enum {
  FE_TEXTURE_ANG,
  FE_TEXTURE_ANGPOINT,

  FE_TEXTURE_CLOCK,
  FE_TEXTURE_TIMER,
  FE_TEXTURE_CLIGHT,

  FE_TEXTURE_CROSSHAIR,
  FE_TEXTURE_TARGET,

  FE_TEXTURE_ARROW,
  FE_TEXTURE_CROSS,

  FE_TEXTURE_PAUSE,

  MAX_FE_GAME_TEXTURES
};
static PLTexture* fe_tx_game_textures[MAX_FE_GAME_TEXTURES];  /* textures that we'll be using in-game */
//static PLTexture *fe_tx_game_icons[MAX_ITEM_TYPES];

static int frontend_width = 0;
static int frontend_height = 0;

/************************************************************/

static void FrontendInputCallback(int key, bool is_pressed) {
  if (frontend_state == FE_MODE_START && is_pressed) {
    /* todo, play 'ting' sound! */

    /* we've hit our key, we can take away this
     * callback now and carry on to whatever */
    Input_SetKeyboardFocusCallback(nullptr);
    FrontEnd_SetState(FE_MODE_MAIN_MENU);
    return;
  }
}

static void CacheFEGameData() {
  fe_tx_game_textures[FE_TEXTURE_ANG] =
      Engine::Resource()->LoadTexture("frontend/dash/ang", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_ANGPOINT] =
      Engine::Resource()->LoadTexture("frontend/dash/angpoint", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_CLOCK] =
      Engine::Resource()->LoadTexture("frontend/dash/clock", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_CLIGHT] =
      Engine::Resource()->LoadTexture("frontend/dash/timlit.png", PL_TEXTURE_FILTER_LINEAR, true);
  fe_tx_game_textures[FE_TEXTURE_TIMER] =
      Engine::Resource()->LoadTexture("frontend/dash/timer", PL_TEXTURE_FILTER_LINEAR, true);
}

static void CacheFEMenuData() {
  fe_background = Engine::Resource()->LoadTexture("frontend/pigbkpc1", PL_TEXTURE_FILTER_LINEAR, true);
  for (unsigned int i = 0; i < MAX_TEAMS; ++i) {
    fe_papers_teams[i] = Engine::Resource()->LoadTexture(papers_teams_paths[i], PL_TEXTURE_FILTER_LINEAR, true);
  }
}

/************************************************************/

void FE_Initialize(void) {
  CacheFontData();
  CacheFEMenuData();
  CacheFEGameData();
}

void FE_Shutdown(void) {
  ClearFontData();
}

void FE_ProcessInput(void) {
  switch (frontend_state) {
    default:break;

    case FE_MODE_START: {
      /* this is... kind of a hack... but ensures that
       * nothing will take away our check for a key during
       * the 'start' screen, e.g. bringing the console up */
      Input_SetKeyboardFocusCallback(FrontendInputCallback);
    }
      break;

    case FE_MODE_VIDEO: {
      if (Input_GetKeyState(INPUT_KEY_SPACE) || Input_GetKeyState(INPUT_KEY_ESCAPE)) {
        Video_SkipCurrent();
      }
    }
      break;
  }
}

void FrontEnd_Tick(void) {}

/************************************************************/

char loading_description[256];
uint8_t loading_progress = 0;

#if 0
#	define Redraw()   Display_DrawInterface();
#else
#	define Redraw()
#endif

void FE_SetLoadingBackground(const char* name) {
  char screen_path[PL_SYSTEM_MAX_PATH];
  snprintf(screen_path, sizeof(screen_path), "frontend/briefing/%s", name);
  if (!plFileExists(screen_path)) {
    snprintf(screen_path, sizeof(screen_path), "frontend/briefing/loadmult");
  }

  fe_background = Engine::Resource()->LoadTexture(screen_path, PL_TEXTURE_FILTER_LINEAR);
  Redraw();
}

void FE_SetLoadingDescription(const char* description) {
  snprintf(loading_description, sizeof(loading_description), "%s ...", description);
  Redraw();
}

void FE_SetLoadingProgress(uint8_t progress) {
  if (progress > 100) progress = 100;
  loading_progress = progress;
  Redraw();
}

uint8_t FE_GetLoadingProgress(void) {
  return loading_progress;
}

/************************************************************/

/**
 * Draw the timer in the bottom corner of the screen.
 */
static void DrawTimer() {
  if (FrontEnd_GetState() != FE_MODE_GAME) {
    return;
  }

  IGameMode* mode = Engine::Game()->GetMode();
  if(!mode->HasRoundStarted()) {
    return;
  }

  char str[64];
  snprintf(str, sizeof(str), "%0d / %0d", mode->GetTurnTimeSeconds(), mode->GetMaxTurnTimeSeconds());
  Font_DrawBitmapString(g_fonts[FONT_BIG], frontend_width - 256, frontend_height - 100, 4, 1.0f, PL_COLOUR_WHITE, str);
}

/**
 * Draw the minimap on the button left corner of the screen.
 */
static void DrawMinimap() {
  if (FrontEnd_GetState() != FE_MODE_GAME) {
    return;
  }

  Map* map = openhow::Engine::Game()->GetCurrentMap();
  if (map == nullptr) {
    return;
  }

#if 0
  static PLMesh* pane = nullptr;
  if(pane == nullptr) {
      pane = plNewMeshRectangle(0, 0, 256, 256, PL_COLOUR_WHITE);
      if(pane == nullptr) {
          Error("Failed to create pane mesh!\n");
      }
  }

  plSetTexture(map->GetOverviewTexture(), 0);

  PLMatrix4x4 mat = plMatrix4x4Identity();
  plSetNamedShaderUniformMatrix4x4(NULL, "pl_model", mat, false);

  plUploadMesh(pane);
  plDrawMesh(pane);

  plSetTexture(nullptr, 0);
#else
  /* for debugging... */
  unsigned int scr_h = Display_GetViewportHeight(&g_state.ui_camera->viewport);
  plDrawTexturedRectangle(0, scr_h - 128, 128, 128, map->GetTerrain()->GetOverview());
#endif
}

/* Hogs of War's menu was designed
 * with a fixed resolution in mind
 * and scales poorly with anything
 * else. For now we'll just keep
 * things fixed and worry about this
 * later. */

static void DrawLoadingScreen() {
  plDrawTexturedRectangle(0, 0, frontend_width, frontend_height, fe_background);

  /* originally I wrote some code ensuring the menu bar
   * was centered... that was until I found out that on
   * the background, the slot for the bar ISN'T centered
   * at all. JOY... */
  static const int bar_w = 330;
  int bar_x = 151; //c_x + (FRONTEND_MENU_WIDTH / 2) - bar_w / 2;
  int bar_y = 450;
  if (loading_progress > 0) {
    plDrawFilledRectangle(plCreateRectangle(
        PLVector2(bar_x, bar_y),
        PLVector2(((float) (bar_w) / 100) * loading_progress, 18),
        PL_COLOUR_INDIAN_RED,
        PL_COLOUR_INDIAN_RED,
        PL_COLOUR_RED,
        PL_COLOUR_RED
    ));
  }

  if (loading_description[0] != ' ' && loading_description[0] != '\0') {
    Font_DrawBitmapString(g_fonts[FONT_CHARS2], bar_x + 2, bar_y + 1, 4, 1.f, PL_COLOUR_WHITE, loading_description);
  }
}

void FE_Draw(void) {
  frontend_width = Display_GetViewportWidth(&g_state.ui_camera->viewport);
  frontend_height = Display_GetViewportHeight(&g_state.ui_camera->viewport);

  /* render and handle the main menu */
  if (frontend_state != FE_MODE_GAME) { // todo: what's going on here... ?
    switch (frontend_state) {
      default:break;

      case FE_MODE_INIT:
      case FE_MODE_START:
      case FE_MODE_MAIN_MENU:
        plDrawTexturedRectangle(0, 0, frontend_width, frontend_height, fe_background);
        break;

      case FE_MODE_LOADING:
        DrawLoadingScreen();
        break;

      case FE_MODE_VIDEO:
        Video_Draw();
        break;
    }

    return;
  }

  DrawMinimap();
  DrawTimer();
}

/* * * * * * * * * * * * * * * * * * * * * * */

void FE_RestoreLastState(void) {
  FrontEnd_SetState(old_frontend_state);
}

unsigned int FrontEnd_GetState(void) {
  return frontend_state;
}

void FrontEnd_SetState(unsigned int state) {
  if (state == frontend_state) {
    LogDebug("attempted to set debug state to an already existing state!\n");
    return;
  }

  LogDebug("changing frontend state to %u...\n", state);
  switch (state) {
    default: {
      LogWarn("invalid frontend state, %u, aborting\n", state);
      return;
    }

    case FE_MODE_MAIN_MENU:
      // start playing the default theme
      Engine::Audio()->PlayMusic(AUDIO_MUSIC_MENU);
      break;

    case FE_MODE_START: break;

    case FE_MODE_GAME: {
      // game mode handles music from here?
    }
      break;

    case FE_MODE_LOADING: {
      // stop the music as soon as we switch to a loading screen...
      Engine::Audio()->StopMusic();

      loading_description[0] = '\0';
      loading_progress = 0;
      break;
    }

    case FE_MODE_EDITOR: break;
  }
  old_frontend_state = frontend_state;
  frontend_state = state;

  /* !!hacky!! force the display to update due to aspect change, yeah this is gross... */
  Display_UpdateViewport(0, 0, cv_display_width->i_value, cv_display_height->i_value);
}

<|endoftext|>


<commit_before>/************************************************************************/
/*                                                                      */
/*               Copyright 1998-2002 by Ullrich Koethe                  */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#include <iostream>
#include "vigra/stdimage.hxx"
#include "vigra/resizeimage.hxx"
#include "vigra/impex.hxx"

using namespace vigra;

int main(int argc, char ** argv)
{
    if(argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " infile outfile" << std::endl;
        std::cout << "(supported formats: " << vigra::impexListFormats() << ")" << std::endl;

        return 1;
    }

    try
    {
        // read image given as first argument
        // file type is determined automatically
        vigra::ImageImportInfo info(argv[1]);

        double sizefactor;
        std::cerr << "Resize factor ? ";
        std::cin >> sizefactor;
        int method;
        std::cerr << "Method (0 - pixel repetition, 1 - linear, 2 - spline ? ";
        std::cin >> method;

        // calculate new image size
        int nw = (int)(sizefactor*(info.width()-1) + 1.5);
        int nh = (int)(sizefactor*(info.height()-1) + 1.5);

        if(info.isGrayscale())
        {
            // create a gray scale image of appropriate size
            vigra::BImage in(info.width(), info.height());
            vigra::BImage out(nw, nh);

            // import the image just read
            importImage(info, destImage(in));

            switch(method)
            {
              case 0:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageNoInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              case 1:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageLinearInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              default:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageSplineInterpolation(srcImageRange(in),
                    destImageRange(out));
            }

            // write the image to the file given as second argument
            // the file type will be determined from the file name's extension
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));
        }
        else
        {
            // create a RGB image of appropriate size
            vigra::BRGBImage in(info.width(), info.height());
            vigra::BRGBImage out(nw, nh);

            // import the image just read
            importImage(info, destImage(in));

            switch(method)
            {
              case 0:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageNoInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              case 1:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageLinearInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              default:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageSplineInterpolation(srcImageRange(in),
                    destImageRange(out));
            }

            // write the image to the file given as second argument
            // the file type will be determined from the file name's extension
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));
        }
    }
    catch (vigra::StdException & e)
    {
        // catch any errors that might have occurred and print their reason
        std::cout << e.what() << std::endl;
        return 1;
    }

    return 0;
}
<commit_msg>resize example: whitespace cleanups<commit_after>/************************************************************************/
/*                                                                      */
/*               Copyright 1998-2002 by Ullrich Koethe                  */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#include <iostream>
#include "vigra/stdimage.hxx"
#include "vigra/resizeimage.hxx"
#include "vigra/impex.hxx"

using namespace vigra;

int main(int argc, char ** argv)
{
    if(argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " infile outfile" << std::endl;
        std::cout << "(supported formats: " << vigra::impexListFormats() << ")" << std::endl;

        return 1;
    }

    try
    {
        // read image given as first argument
        // file type is determined automatically
        vigra::ImageImportInfo info(argv[1]);

        double sizefactor;
        std::cerr << "Resize factor ? ";
        std::cin >> sizefactor;
        int method;
        std::cerr << "Method (0 - pixel repetition, 1 - linear, 2 - spline ? ";
        std::cin >> method;

        // calculate new image size
        int nw = (int)(sizefactor*(info.width()-1) + 1.5);
        int nh = (int)(sizefactor*(info.height()-1) + 1.5);

        if(info.isGrayscale())
        {
            // create a gray scale image of appropriate size
            vigra::BImage in(info.width(), info.height());
            vigra::BImage out(nw, nh);

            // import the image just read
            importImage(info, destImage(in));

            switch(method)
            {
              case 0:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageNoInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              case 1:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageLinearInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              default:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageSplineInterpolation(srcImageRange(in),
                    destImageRange(out));
            }

            // write the image to the file given as second argument
            // the file type will be determined from the file name's extension
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));
        }
        else
        {
            // create a RGB image of appropriate size
            vigra::BRGBImage in(info.width(), info.height());
            vigra::BRGBImage out(nw, nh);

            // import the image just read
            importImage(info, destImage(in));

            switch(method)
            {
              case 0:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageNoInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              case 1:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageLinearInterpolation(srcImageRange(in),
                    destImageRange(out));
                break;
              default:
                // resize the image, using a bi-cubic spline algorithms
                resizeImageSplineInterpolation(srcImageRange(in),
                    destImageRange(out));
            }

            // write the image to the file given as second argument
            // the file type will be determined from the file name's extension
            exportImage(srcImageRange(out), vigra::ImageExportInfo(argv[2]));
        }
    }
    catch (vigra::StdException & e)
    {
        // catch any errors that might have occurred and print their reason
        std::cout << e.what() << std::endl;
        return 1;
    }

    return 0;
}
<|endoftext|>


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

#include "flutter/flow/layers/physical_model_layer.h"

#include "third_party/skia/include/utils/SkShadowUtils.h"

#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h"
#include "apps/mozart/services/composition/nodes.fidl.h"
#endif  // defined(OS_FUCHSIA)

namespace flow {

PhysicalModelLayer::PhysicalModelLayer()
    : rrect_(SkRRect::MakeEmpty()) {}

PhysicalModelLayer::~PhysicalModelLayer() {}

void PhysicalModelLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
  PrerollChildren(context, matrix);

  // Add some margin to the paint bounds to leave space for the shadow.
  // The margin is hardcoded to an arbitrary maximum for now because Skia
  // doesn't provide a way to calculate it.
  SkRect bounds(rrect_.getBounds());
  bounds.outset(50.0, 50.0);
  set_paint_bounds(bounds);

  context->child_paint_bounds = bounds;
}

#if defined(OS_FUCHSIA)

void PhysicalModelLayer::UpdateScene(SceneUpdateContext& context,
                                     mozart::Node* container) {
  context.AddLayerToCurrentPaintTask(this);
  auto node = mozart::Node::New();
  node->content_clip = mozart::RectF::From(rrect_.getBounds());
  UpdateSceneChildrenInsideNode(context, container, std::move(node));
}

#endif  // defined(OS_FUCHSIA)

void PhysicalModelLayer::Paint(PaintContext& context) {
  TRACE_EVENT0("flutter", "PhysicalModelLayer::Paint");

  SkPath path;
  path.addRRect(rrect_);

  if (elevation_ != 0) {
    DrawShadow(&context.canvas, path, SK_ColorBLACK, elevation_,
               SkColorGetA(color_) != 0xff);
  }

  if (needs_system_composite())
    return;

  SkPaint paint;
  paint.setColor(color_);
  context.canvas.drawPath(path, paint);

  SkAutoCanvasRestore save(&context.canvas, false);
  if (rrect_.isRect()) {
    context.canvas.save();
  } else {
    context.canvas.saveLayer(&rrect_.getBounds(), nullptr);
  }
  context.canvas.clipRRect(rrect_, true);
  PaintChildren(context);
}

void PhysicalModelLayer::DrawShadow(SkCanvas* canvas, const SkPath& path,
                                    SkColor color, int elevation,
                                    bool transparentOccluder) {
    SkShadowFlags flags = transparentOccluder ?
        SkShadowFlags::kTransparentOccluder_ShadowFlag :
        SkShadowFlags::kNone_ShadowFlag;
    SkShadowUtils::DrawShadow(canvas, path,
                              elevation * 4,
                              SkPoint3::Make(0.0f, -700.0f, 2800.0f),
                              2800.0f,
                              0.25f, 0.25f,
                              color,
                              flags);
}

}  // namespace flow
<commit_msg>Improve the shadow drawing parameters (#3499)<commit_after>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/physical_model_layer.h"

#include "third_party/skia/include/utils/SkShadowUtils.h"

#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h"
#include "apps/mozart/services/composition/nodes.fidl.h"
#endif  // defined(OS_FUCHSIA)

namespace flow {

PhysicalModelLayer::PhysicalModelLayer()
    : rrect_(SkRRect::MakeEmpty()) {}

PhysicalModelLayer::~PhysicalModelLayer() {}

void PhysicalModelLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
  PrerollChildren(context, matrix);

  // Add some margin to the paint bounds to leave space for the shadow.
  // The margin is hardcoded to an arbitrary maximum for now because Skia
  // doesn't provide a way to calculate it.
  SkRect bounds(rrect_.getBounds());
  bounds.outset(50.0, 50.0);
  set_paint_bounds(bounds);

  context->child_paint_bounds = bounds;
}

#if defined(OS_FUCHSIA)

void PhysicalModelLayer::UpdateScene(SceneUpdateContext& context,
                                     mozart::Node* container) {
  context.AddLayerToCurrentPaintTask(this);
  auto node = mozart::Node::New();
  node->content_clip = mozart::RectF::From(rrect_.getBounds());
  UpdateSceneChildrenInsideNode(context, container, std::move(node));
}

#endif  // defined(OS_FUCHSIA)

void PhysicalModelLayer::Paint(PaintContext& context) {
  TRACE_EVENT0("flutter", "PhysicalModelLayer::Paint");

  SkPath path;
  path.addRRect(rrect_);

  if (elevation_ != 0) {
    DrawShadow(&context.canvas, path, SK_ColorBLACK, elevation_,
               SkColorGetA(color_) != 0xff);
  }

  if (needs_system_composite())
    return;

  SkPaint paint;
  paint.setColor(color_);
  context.canvas.drawPath(path, paint);

  SkAutoCanvasRestore save(&context.canvas, false);
  if (rrect_.isRect()) {
    context.canvas.save();
  } else {
    context.canvas.saveLayer(&rrect_.getBounds(), nullptr);
  }
  context.canvas.clipRRect(rrect_, true);
  PaintChildren(context);
}

void PhysicalModelLayer::DrawShadow(SkCanvas* canvas, const SkPath& path,
                                    SkColor color, int elevation,
                                    bool transparentOccluder) {
    SkShadowFlags flags = transparentOccluder ?
        SkShadowFlags::kTransparentOccluder_ShadowFlag :
        SkShadowFlags::kNone_ShadowFlag;
    SkShadowUtils::DrawShadow(canvas, path,
                              elevation * 2,
                              SkPoint3::Make(0.0f, 0.0f, 600.0f),
                              800.0f,
                              0.2f, 0.2f,
                              color,
                              flags);
}

}  // namespace flow
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/lexical_cast.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include <map>
#include <utility>
#include <numeric>
#include <cstdio>

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/smart_ban.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/aux_/session_impl.hpp"

namespace libtorrent { namespace
{

	struct smart_ban_plugin : torrent_plugin, boost::enable_shared_from_this<smart_ban_plugin>
	{
		smart_ban_plugin(torrent& t)
			: m_torrent(t)
			, m_salt(rand())
		{
		}

		void on_piece_pass(int p)
		{
#ifdef TORRENT_LOGGING
			(*m_torrent.session().m_logger) << time_now_string() << " PIECE PASS [ p: " << p
				<< " | block_crc_size: " << m_block_crc.size() << " ]\n";
#endif
			// has this piece failed earlier? If it has, go through the
			// CRCs from the time it failed and ban the peers that
			// sent bad blocks
			std::map<piece_block, block_entry>::iterator i = m_block_crc.lower_bound(piece_block(p, 0));
			if (i == m_block_crc.end() || i->first.piece_index != p) return;

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			while (size > 0)
			{
				if (i->first.block_index == pb.block_index)
				{
					m_torrent.filesystem().async_read(r, bind(&smart_ban_plugin::on_read_ok_block
						, shared_from_this(), *i, _1, _2));
					m_block_crc.erase(i++);
				}
				else
				{
					TORRENT_ASSERT(i->first.block_index > pb.block_index);
				}

				if (i == m_block_crc.end() || i->first.piece_index != p)
					break;

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}

#ifndef NDEBUG
			// make sure we actually removed all the entries for piece 'p'
			i = m_block_crc.lower_bound(piece_block(p, 0));
			TORRENT_ASSERT(i == m_block_crc.end() || i->first.piece_index != p);
#endif

			if (m_torrent.is_seed())
			{
				std::map<piece_block, block_entry>().swap(m_block_crc);
				return;
			}
		}

		void on_piece_failed(int p)
		{
			// The piece failed the hash check. Record
			// the CRC and origin peer of every block

			std::vector<void*> downloaders;
			m_torrent.picker().get_downloaders(downloaders, p);

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			for (std::vector<void*>::iterator i = downloaders.begin()
				, end(downloaders.end()); i != end; ++i)
			{
				if (*i != 0)
				{
					m_torrent.filesystem().async_read(r, bind(&smart_ban_plugin::on_read_failed_block
						, shared_from_this(), pb, (policy::peer*)*i, _1, _2));
				}

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}
			TORRENT_ASSERT(size <= 0);
		}

	private:

		// this entry ties a specific block CRC to
		// a peer.
		struct block_entry
		{
			policy::peer* peer;
			unsigned long crc;
		};

		void on_read_failed_block(piece_block b, policy::peer* p, int ret, disk_io_job const& j)
		{
			TORRENT_ASSERT(p);
			// ignore read errors
			if (ret != j.buffer_size) return;

			adler32_crc crc;
			crc.update(j.buffer, j.buffer_size);
			crc.update((char const*)&m_salt, sizeof(m_salt));

			block_entry e = {p, crc.final()};

			// since this callback is called directory from the disk io
			// thread, the session mutex is not locked when we get here
			aux::session_impl::mutex_t::scoped_lock l(m_torrent.session().m_mutex);

			std::map<piece_block, block_entry>::iterator i = m_block_crc.lower_bound(b);
			if (i != m_block_crc.end() && i->first == b && i->second.peer == p)
			{
				// this peer has sent us this block before
				if (i->second.crc != e.crc)
				{
					// this time the crc of the block is different
					// from the first time it sent it
					// at least one of them must be bad

					if (p == 0) return;
					if (!m_torrent.get_policy().has_peer(p)) return;

#ifdef TORRENT_LOGGING
					char const* client = "-";
					peer_info info;
					if (p->connection)
					{
						p->connection->get_peer_info(info);
						client = info.client.c_str();
					}
					(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.piece_index
						<< " | b: " << b.block_index
						<< " | c: " << client
						<< " | crc1: " << i->second.crc
						<< " | crc2: " << e.crc
						<< " | ip: " << p->ip << " ]\n";
#endif
					p->banned = true;
					if (p->connection) p->connection->disconnect("banning peer for sending bad data");
				}
				// we already have this exact entry in the map
				// we don't have to insert it
				return;
			}

			m_block_crc.insert(i, std::make_pair(b, e));

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " STORE BLOCK CRC [ p: " << b.piece_index
				<< " | b: " << b.block_index
				<< " | c: " << client
				<< " | crc: " << e.crc
				<< " | ip: " << p->ip << " ]\n";
#endif
		}

		void on_read_ok_block(std::pair<piece_block, block_entry> b, int ret, disk_io_job const& j)
		{
			// since this callback is called directory from the disk io
			// thread, the session mutex is not locked when we get here
			aux::session_impl::mutex_t::scoped_lock l(m_torrent.session().m_mutex);

			// ignore read errors
			if (ret != j.buffer_size) return;

			adler32_crc crc;
			crc.update(j.buffer, j.buffer_size);
			crc.update((char const*)&m_salt, sizeof(m_salt));
			unsigned long ok_crc = crc.final();

			if (b.second.crc == ok_crc) return;

			policy::peer* p = b.second.peer;

			if (p == 0) return;
			if (!m_torrent.get_policy().has_peer(p)) return;

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.first.piece_index
				<< " | b: " << b.first.block_index
				<< " | c: " << client
				<< " | ok_crc: " << ok_crc
				<< " | bad_crc: " << b.second.crc
				<< " | ip: " << p->ip << " ]\n";
#endif
			p->banned = true;
			if (p->connection) p->connection->disconnect("banning peer for sending bad data");
		}

		torrent& m_torrent;

		// This table maps a piece_block (piece and block index
		// pair) to a peer and the block CRC. The CRC is calculated
		// from the data in the block + the salt
		std::map<piece_block, block_entry> m_block_crc;

		// This salt is a random value used to calculate the block CRCs
		// Since the CRC function that is used is not a one way function
		// the salt is required to avoid attacks where bad data is sent
		// that is forged to match the CRC of the good data.
		int m_salt;
	};

} }

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_smart_ban_plugin(torrent* t, void*)
	{
		return boost::shared_ptr<torrent_plugin>(new smart_ban_plugin(*t));
	}

}

<commit_msg>fix smart ban assert when closing a torrent with a failing piece<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/lexical_cast.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include <map>
#include <utility>
#include <numeric>
#include <cstdio>

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/smart_ban.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/aux_/session_impl.hpp"

namespace libtorrent { namespace
{

	struct smart_ban_plugin : torrent_plugin, boost::enable_shared_from_this<smart_ban_plugin>
	{
		smart_ban_plugin(torrent& t)
			: m_torrent(t)
			, m_salt(rand())
		{
		}

		void on_piece_pass(int p)
		{
#ifdef TORRENT_LOGGING
			(*m_torrent.session().m_logger) << time_now_string() << " PIECE PASS [ p: " << p
				<< " | block_crc_size: " << m_block_crc.size() << " ]\n";
#endif
			// has this piece failed earlier? If it has, go through the
			// CRCs from the time it failed and ban the peers that
			// sent bad blocks
			std::map<piece_block, block_entry>::iterator i = m_block_crc.lower_bound(piece_block(p, 0));
			if (i == m_block_crc.end() || i->first.piece_index != p) return;

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			while (size > 0)
			{
				if (i->first.block_index == pb.block_index)
				{
					m_torrent.filesystem().async_read(r, bind(&smart_ban_plugin::on_read_ok_block
						, shared_from_this(), *i, _1, _2));
					m_block_crc.erase(i++);
				}
				else
				{
					TORRENT_ASSERT(i->first.block_index > pb.block_index);
				}

				if (i == m_block_crc.end() || i->first.piece_index != p)
					break;

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}

#ifndef NDEBUG
			// make sure we actually removed all the entries for piece 'p'
			i = m_block_crc.lower_bound(piece_block(p, 0));
			TORRENT_ASSERT(i == m_block_crc.end() || i->first.piece_index != p);
#endif

			if (m_torrent.is_seed())
			{
				std::map<piece_block, block_entry>().swap(m_block_crc);
				return;
			}
		}

		void on_piece_failed(int p)
		{
			// The piece failed the hash check. Record
			// the CRC and origin peer of every block

			// if the torrent is aborted, no point in starting
			// a bunch of read operations on it
			if (m_torrent.is_aborted()) return;

			std::vector<void*> downloaders;
			m_torrent.picker().get_downloaders(downloaders, p);

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			for (std::vector<void*>::iterator i = downloaders.begin()
				, end(downloaders.end()); i != end; ++i)
			{
				if (*i != 0)
				{
					m_torrent.filesystem().async_read(r, bind(&smart_ban_plugin::on_read_failed_block
						, shared_from_this(), pb, (policy::peer*)*i, _1, _2));
				}

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}
			TORRENT_ASSERT(size <= 0);
		}

	private:

		// this entry ties a specific block CRC to
		// a peer.
		struct block_entry
		{
			policy::peer* peer;
			unsigned long crc;
		};

		void on_read_failed_block(piece_block b, policy::peer* p, int ret, disk_io_job const& j)
		{
			TORRENT_ASSERT(p);
			// ignore read errors
			if (ret != j.buffer_size) return;

			adler32_crc crc;
			crc.update(j.buffer, j.buffer_size);
			crc.update((char const*)&m_salt, sizeof(m_salt));

			block_entry e = {p, crc.final()};

			// since this callback is called directory from the disk io
			// thread, the session mutex is not locked when we get here
			aux::session_impl::mutex_t::scoped_lock l(m_torrent.session().m_mutex);

			std::map<piece_block, block_entry>::iterator i = m_block_crc.lower_bound(b);
			if (i != m_block_crc.end() && i->first == b && i->second.peer == p)
			{
				// this peer has sent us this block before
				if (i->second.crc != e.crc)
				{
					// this time the crc of the block is different
					// from the first time it sent it
					// at least one of them must be bad

					if (p == 0) return;
					if (!m_torrent.get_policy().has_peer(p)) return;

#ifdef TORRENT_LOGGING
					char const* client = "-";
					peer_info info;
					if (p->connection)
					{
						p->connection->get_peer_info(info);
						client = info.client.c_str();
					}
					(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.piece_index
						<< " | b: " << b.block_index
						<< " | c: " << client
						<< " | crc1: " << i->second.crc
						<< " | crc2: " << e.crc
						<< " | ip: " << p->ip << " ]\n";
#endif
					p->banned = true;
					if (p->connection) p->connection->disconnect("banning peer for sending bad data");
				}
				// we already have this exact entry in the map
				// we don't have to insert it
				return;
			}

			m_block_crc.insert(i, std::make_pair(b, e));

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " STORE BLOCK CRC [ p: " << b.piece_index
				<< " | b: " << b.block_index
				<< " | c: " << client
				<< " | crc: " << e.crc
				<< " | ip: " << p->ip << " ]\n";
#endif
		}

		void on_read_ok_block(std::pair<piece_block, block_entry> b, int ret, disk_io_job const& j)
		{
			// since this callback is called directory from the disk io
			// thread, the session mutex is not locked when we get here
			aux::session_impl::mutex_t::scoped_lock l(m_torrent.session().m_mutex);

			// ignore read errors
			if (ret != j.buffer_size) return;

			adler32_crc crc;
			crc.update(j.buffer, j.buffer_size);
			crc.update((char const*)&m_salt, sizeof(m_salt));
			unsigned long ok_crc = crc.final();

			if (b.second.crc == ok_crc) return;

			policy::peer* p = b.second.peer;

			if (p == 0) return;
			if (!m_torrent.get_policy().has_peer(p)) return;

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.first.piece_index
				<< " | b: " << b.first.block_index
				<< " | c: " << client
				<< " | ok_crc: " << ok_crc
				<< " | bad_crc: " << b.second.crc
				<< " | ip: " << p->ip << " ]\n";
#endif
			p->banned = true;
			if (p->connection) p->connection->disconnect("banning peer for sending bad data");
		}

		torrent& m_torrent;

		// This table maps a piece_block (piece and block index
		// pair) to a peer and the block CRC. The CRC is calculated
		// from the data in the block + the salt
		std::map<piece_block, block_entry> m_block_crc;

		// This salt is a random value used to calculate the block CRCs
		// Since the CRC function that is used is not a one way function
		// the salt is required to avoid attacks where bad data is sent
		// that is forged to match the CRC of the good data.
		int m_salt;
	};

} }

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_smart_ban_plugin(torrent* t, void*)
	{
		return boost::shared_ptr<torrent_plugin>(new smart_ban_plugin(*t));
	}

}

<|endoftext|>


<commit_before>/**
  *  @copyright Copyright (c) 2014, Wojciech Krzemien
  *  @file JPetTaskIO.cpp
  *  @author Wojciech Krzemien, wojciech.krzemien@if.uj.edu.pl
  */

#include "JPetTaskIO.h"
#include <cassert>
#include "../JPetReader/JPetReader.h"
#include "../JPetTreeHeader/JPetTreeHeader.h"
#include "../JPetTask/JPetTask.h"
#include "../../framework/JPetHLDReader/JPetHLDReader.h"

#include "../../JPetLoggerInclude.h"

JPetTaskIO::JPetTaskIO():
  fWriter(0),
  fReader(0),
  fHeader(0)
{
}

void JPetTaskIO::init(const JPetOptions::Options& opts)
{
  setOptions(JPetOptions(opts));
  auto inputFilename = fOptions.getInputFile();
  auto outputFilename = fOptions.getOutputFile();
  createInputObjects(inputFilename);
  createOutputObjects(outputFilename);
}

void JPetTaskIO::exec()
{
  assert(fTask);
  assert(fReader);
  assert(fParamManager);
  fTask->setParamManager(fParamManager);
  JPetTaskInterface::Options emptyOpts;
  fTask->init(emptyOpts); //prepare current task for file
  auto firstEvent = 0ll;
  auto lastEvent = 0ll;
  setUserLimits(fOptions, firstEvent, lastEvent);
  assert(lastEvent > 0);
  for (auto i = firstEvent; i < lastEvent; i++) {
    fTask->setEvent(&(static_cast<TNamed&>(fReader->getCurrentEvent())));
    if (fOptions.isProgressBar()) {
      manageProgressBar(i, lastEvent);
    }
    fTask->exec();
    fReader->nextEvent();
  }
  fTask->terminate();
}

void JPetTaskIO::terminate()
{
  assert(fReader);
  assert(fWriter);
  assert(fHeader);

  INFO(Form("Finished processing %s.", "A"));
  fWriter->writeHeader(fHeader);

  // store the parametric objects in the ouptut ROOT file
  getParamManager().saveParametersToFile(
    fWriter);
  getParamManager().clearParameters();

  fWriter->closeFile();
  fReader->closeFile();

}

void JPetTaskIO::createInputObjects(const char* inputFilename)
{
  auto treeName = "";
  if (fOptions.getInputFileType() == JPetOptions::kHld ) {
    fReader = new JPetHLDReader;
    treeName = "T";
  } else {
    fReader = new JPetReader;
    treeName = "tree";
  }
  if ( fReader->openFileAndLoadData( inputFilename, treeName )) {
    if (fOptions.getInputFileType() == JPetOptions::kHld ) {
      // create a header to be stored along with the output tree
      fHeader = new JPetTreeHeader(26);

      // add general info to the Tree header
      //fHeader->setBaseFileName(
      //JPetManager::GetManager().getInputFileNames()[0].c_str());

      //// add info about this module to the processing stages' history in Tree header
      //fHeader->addStageInfo(this->GetName(), this->GetTitle(), MODULE_VERSION,
      //JPetManager::GetManager().GetTimeString());

    } else {
      assert(fParamManager);
      fParamManager->readParametersFromFile(dynamic_cast<JPetReader*> (fReader));
      // read the header from the previous analysis stage
      //
      fHeader = dynamic_cast<JPetReader*>(fReader)->getHeaderClone();
      //fParamManager.readParametersFromFile( fReader );
    }
  } else {
    ERROR(inputFilename + std::string(": Unable to open the input file"));
    exit(-1);
  }
}

void JPetTaskIO::createOutputObjects(const char* outputFilename)
{
  fWriter = new JPetWriter( outputFilename );
  fTask->setWriter(fWriter);
}

void JPetTaskIO::manageProgressBar(long long done, long long end)
{
  printf("\r[%6.4f%% %%]", setProgressBar(done, end));
}

float JPetTaskIO::setProgressBar(int currentEventNumber, int numberOfEvents)
{
  return ( ((float)currentEventNumber) / numberOfEvents ) * 100;
}

const JPetParamBank& JPetTaskIO::getParamBank()
{
  return fParamManager->getParamBank();
}

JPetTaskIO::~JPetTaskIO()
{
  if (fTask) delete fTask;
  if (fWriter) delete fWriter;
  if (fReader) delete fReader;
}

/// Sets values of firstEvent and lastEvent based on user options opts and total number of events from JPetReader
void JPetTaskIO::setUserLimits(const JPetOptions& opts, long long& firstEvent, long long& lastEvent) const
{
  assert(fReader);
  const auto kLastEvent = opts.getLastEvent();
  const auto kFirstEvent = opts.getFirstEvent();
  const auto kEventNum = fReader->getNbOfAllEvents();
  if (kLastEvent < 0)  {
    lastEvent = kEventNum;
  } else {
    lastEvent = kLastEvent < kEventNum ? kLastEvent : kEventNum;
  }
  if ( kFirstEvent < 0) {
    firstEvent = 0;
  } else {
    firstEvent = kFirstEvent;
  }
  assert(firstEvent>=0);
  assert(lastEvent>=0);
  assert(firstEvent <= lastEvent);
}
<commit_msg>Add some small fixes e.g. initialize all members of the JPetTaskIO<commit_after>/**
  *  @copyright Copyright (c) 2014, Wojciech Krzemien
  *  @file JPetTaskIO.cpp
  *  @author Wojciech Krzemien, wojciech.krzemien@if.uj.edu.pl
  */

#include "JPetTaskIO.h"
#include <cassert>
#include "../JPetReader/JPetReader.h"
#include "../JPetTreeHeader/JPetTreeHeader.h"
#include "../JPetTask/JPetTask.h"
#include "../../framework/JPetHLDReader/JPetHLDReader.h"

#include "../../JPetLoggerInclude.h"

JPetTaskIO::JPetTaskIO():
  fTask(0),
  fEventNb(-1),
  fWriter(0),
  fReader(0),
  fHeader(0),
  fParamManager(0)
{
}

void JPetTaskIO::init(const JPetOptions::Options& opts)
{
  setOptions(JPetOptions(opts));
  auto inputFilename = fOptions.getInputFile();
  auto outputFilename = fOptions.getOutputFile();
  createInputObjects(inputFilename);
  createOutputObjects(outputFilename);
}

void JPetTaskIO::exec()
{
  assert(fTask);
  assert(fReader);
  assert(fParamManager);
  fTask->setParamManager(fParamManager);
  JPetTaskInterface::Options emptyOpts;
  fTask->init(emptyOpts); //prepare current task for file
  auto firstEvent = 0ll;
  auto lastEvent = 0ll;
  setUserLimits(fOptions, firstEvent, lastEvent);
  assert(lastEvent > 0);
  for (auto i = firstEvent; i < lastEvent; i++) {
    fTask->setEvent(&(static_cast<TNamed&>(fReader->getCurrentEvent())));
    if (fOptions.isProgressBar()) {
      manageProgressBar(i, lastEvent);
    }
    fTask->exec();
    fReader->nextEvent();
  }
  fTask->terminate();
}

void JPetTaskIO::terminate()
{
  assert(fReader);
  assert(fWriter);
  assert(fHeader);

  INFO(Form("Finished processing %s.", "A"));
  fWriter->writeHeader(fHeader);

  // store the parametric objects in the ouptut ROOT file
  getParamManager().saveParametersToFile(
    fWriter);
  getParamManager().clearParameters();

  fWriter->closeFile();
  fReader->closeFile();

}

void JPetTaskIO::createInputObjects(const char* inputFilename)
{
  auto treeName = "";
  if (fOptions.getInputFileType() == JPetOptions::kHld ) {
    fReader = new JPetHLDReader;
    treeName = "T";
  } else {
    fReader = new JPetReader;
    treeName = "tree";
  }
  if ( fReader->openFileAndLoadData( inputFilename, treeName )) {
    if (fOptions.getInputFileType() == JPetOptions::kHld ) {
      // create a header to be stored along with the output tree
      fHeader = new JPetTreeHeader(26);

      // add general info to the Tree header
      //fHeader->setBaseFileName(
      //JPetManager::GetManager().getInputFileNames()[0].c_str());

      //// add info about this module to the processing stages' history in Tree header
      //fHeader->addStageInfo(this->GetName(), this->GetTitle(), MODULE_VERSION,
      //JPetManager::GetManager().GetTimeString());

    } else {
      assert(fParamManager);
      fParamManager->readParametersFromFile(dynamic_cast<JPetReader*> (fReader));
      // read the header from the previous analysis stage
      //
      fHeader = dynamic_cast<JPetReader*>(fReader)->getHeaderClone();
      //fParamManager.readParametersFromFile( fReader );
    }
  } else {
    ERROR(inputFilename + std::string(": Unable to open the input file or load the tree"));
    exit(-1);
  }
}

void JPetTaskIO::createOutputObjects(const char* outputFilename)
{
  fWriter = new JPetWriter( outputFilename );
  assert(fWriter);
  if (fTask) {
    fTask->setWriter(fWriter);
  } else {
    WARNING("the subTask does not exist, so Write was not passed to it");
  }
}

void JPetTaskIO::manageProgressBar(long long done, long long end)
{
  printf("\r[%6.4f%% %%]", setProgressBar(done, end));
}

float JPetTaskIO::setProgressBar(int currentEventNumber, int numberOfEvents)
{
  return ( ((float)currentEventNumber) / numberOfEvents ) * 100;
}

const JPetParamBank& JPetTaskIO::getParamBank()
{
  return fParamManager->getParamBank();
}

JPetTaskIO::~JPetTaskIO()
{
  if (fTask) delete fTask;
  if (fWriter) delete fWriter;
  if (fReader) delete fReader;
}

/// Sets values of firstEvent and lastEvent based on user options opts and total number of events from JPetReader
void JPetTaskIO::setUserLimits(const JPetOptions& opts, long long& firstEvent, long long& lastEvent) const
{
  assert(fReader);
  const auto kLastEvent = opts.getLastEvent();
  const auto kFirstEvent = opts.getFirstEvent();
  const auto kEventNum = fReader->getNbOfAllEvents();
  if (kLastEvent < 0)  {
    lastEvent = kEventNum;
  } else {
    lastEvent = kLastEvent < kEventNum ? kLastEvent : kEventNum;
  }
  if ( kFirstEvent < 0) {
    firstEvent = 0;
  } else {
    firstEvent = kFirstEvent;
  }
  assert(firstEvent>=0);
  assert(lastEvent>=0);
  assert(firstEvent <= lastEvent);
}
<|endoftext|>