<commit_before>//Jonathan's class

#include "FreeLookCamera.h"

FreeLookCamera::FreeLookCamera(GLint viewWidth, GLint viewHeight, GLfloat viewNearPlane, GLfloat viewFarPlane)
{
	Camera::initialize(viewWidth, viewHeight, viewNearPlane, viewFarPlane);

	//camera rotation
	yaw = 0.0f;
	pitch = 0.0f;
	roll = 0.0f;

	//camera location
	locX = 25.0f;
	locY = 10.0f;
	locZ = 25.0f;

	fovy = DEFAULT_FOVY;

	mouseSensitivity = DEFAULT_MOUSE_SENSITIVITY;
	movementSensitivity = DEFAULT_MOVEMENT_SENSITIVITY;

	for (int i = 0; i < 3; i++)
		directionVector[i] = 0.0;

	upVector[0] = 0.0f;
	upVector[1] = 1.0f;
	upVector[2] = 0.0f;
}

void FreeLookCamera::view()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(fovy, viewWidth / viewHeight, viewNearPlane, viewFarPlane);

	gluLookAt(locX, locY, locZ,
		locX + directionVector[0], locY + directionVector[1], locZ + directionVector[2],
		upVector[0], upVector[1], upVector[2]);
}

void FreeLookCamera::moveCameraForwards(bool negateTheValue)
{
	GLfloat multiplier = 1.0f;

	if (negateTheValue)
		multiplier *= -1.0f;

	locX += directionVector[0] * multiplier * movementSensitivity;
	locY += directionVector[1] * multiplier * movementSensitivity;
	locZ += directionVector[2] * multiplier * movementSensitivity;
}

void FreeLookCamera::moveCameraStrafe(bool negateTheValue)
{
	GLfloat multiplier = 1.0;

	if (negateTheValue)
		multiplier *= -1.0;

	locX -= directionVector[2] * multiplier * movementSensitivity;
	locZ += directionVector[0] * multiplier * movementSensitivity;

	glutPostRedisplay();
}

void FreeLookCamera::modifyYaw(bool negateTheValue, int x, int y)
{
	int diffX, diffY;

	diffX = x - centerX;
	diffY = y - centerY;

	if (diffX != 0 || diffY != 0)
	{
		glutWarpPointer(centerX, centerY);

		yaw += diffX * mouseSensitivity;
		pitch += diffY * mouseSensitivity;

		if (pitch > MAX_PITCH)
			pitch = MAX_PITCH;
		else if (pitch < MIN_PITCH)
			pitch = MIN_PITCH;

		directionVector[0] = cos(yaw);
		directionVector[1] = -sin(pitch);
		directionVector[2] = sin(yaw);
	}
}

void FreeLookCamera::incrementRoll(bool negateTheValue)
{
	if (negateTheValue)
		roll -= 0.4f;
	else
		roll += 0.4f;

	//http://www.gamedev.net/topic/546975-calculating-the-up-vector/
	upVector[0] = cos(yaw) * sin(pitch) * sin(roll) - sin(yaw) * cos(roll);
	upVector[1] = sin(yaw) * sin(pitch) * sin(roll) + cos(yaw) * cos(roll);
	upVector[2] = cos(pitch) * sin(roll);
}

void FreeLookCamera::resetPitchAndRoll()
{
	pitch = 0.0f;
	roll = 0.0f;

	directionVector[0] = cos(yaw);
	directionVector[1] = pitch;
	directionVector[2] = sin(yaw);

	upVector[0] = 0.0f;
	upVector[1] = 1.0f;
	upVector[2] = 0.0f;

}<commit_msg>Rolling is a bit smoother<commit_after>//Jonathan's class

#include "FreeLookCamera.h"

FreeLookCamera::FreeLookCamera(GLint viewWidth, GLint viewHeight, GLfloat viewNearPlane, GLfloat viewFarPlane)
{
	Camera::initialize(viewWidth, viewHeight, viewNearPlane, viewFarPlane);

	//camera rotation
	yaw = 0.0f;
	pitch = 0.0f;
	roll = 0.0f;

	//camera location
	locX = 25.0f;
	locY = 10.0f;
	locZ = 25.0f;

	fovy = DEFAULT_FOVY;

	mouseSensitivity = DEFAULT_MOUSE_SENSITIVITY;
	movementSensitivity = DEFAULT_MOVEMENT_SENSITIVITY;

	for (int i = 0; i < 3; i++)
		directionVector[i] = 0.0;

	upVector[0] = 0.0f;
	upVector[1] = 1.0f;
	upVector[2] = 0.0f;
}

void FreeLookCamera::view()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(fovy, viewWidth / viewHeight, viewNearPlane, viewFarPlane);

	gluLookAt(locX, locY, locZ,
		locX + directionVector[0], locY + directionVector[1], locZ + directionVector[2],
		upVector[0], upVector[1], upVector[2]);
}

void FreeLookCamera::moveCameraForwards(bool negateTheValue)
{
	GLfloat multiplier = 1.0f;

	if (negateTheValue)
		multiplier *= -1.0f;

	locX += directionVector[0] * multiplier * movementSensitivity;
	locY += directionVector[1] * multiplier * movementSensitivity;
	locZ += directionVector[2] * multiplier * movementSensitivity;
}

void FreeLookCamera::moveCameraStrafe(bool negateTheValue)
{
	GLfloat multiplier = 1.0;

	if (negateTheValue)
		multiplier *= -1.0;

	locX -= directionVector[2] * multiplier * movementSensitivity;
	locZ += directionVector[0] * multiplier * movementSensitivity;

	glutPostRedisplay();
}

void FreeLookCamera::modifyYaw(bool negateTheValue, int x, int y)
{
	int diffX, diffY;

	diffX = x - centerX;
	diffY = y - centerY;

	if (diffX != 0 || diffY != 0)
	{
		glutWarpPointer(centerX, centerY);

		yaw += diffX * mouseSensitivity;
		pitch += diffY * mouseSensitivity;

		if (pitch > MAX_PITCH)
			pitch = MAX_PITCH;
		else if (pitch < MIN_PITCH)
			pitch = MIN_PITCH;

		directionVector[0] = cos(yaw);
		directionVector[1] = -sin(pitch);
		directionVector[2] = sin(yaw);
	}
}

void FreeLookCamera::incrementRoll(bool negateTheValue)
{
	if (negateTheValue)
		roll -= 0.4f;
	else
		roll += 0.4f;

	//http://www.gamedev.net/topic/546975-calculating-the-up-vector/
	upVector[0] = cos(yaw) * sin(pitch) * sin(roll) - sin(yaw) * cos(roll);
	upVector[1] = sin(yaw) * sin(pitch) * sin(roll) + cos(yaw) * cos(roll);
	upVector[2] = /*cos(pitch) */ sin(roll);
}

void FreeLookCamera::resetPitchAndRoll()
{
	pitch = 0.0f;
	roll = 0.0f;

	directionVector[0] = cos(yaw);
	directionVector[1] = pitch;
	directionVector[2] = sin(yaw);

	upVector[0] = 0.0f;
	upVector[1] = 1.0f;
	upVector[2] = 0.0f;

}<|endoftext|>


<commit_before>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

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

/*****
 begin camera setup
*****/

 CvCapture* capture = 0;
 int width, height;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream config_file (".config");

 if (config_file.is_open()) {
// does not support corrupted .config

  string line;
  getline(config_file, line);
  istringstream(line)>>width;
  getline(config_file, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  config_file.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream config_file_out(".config");
  config_file_out << width;
  config_file_out << "\n";
  config_file_out << height;
  config_file_out << "\n";
  config_file_out.close();
 }

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

/*****
 end camera setup
*****/

/*****
 filter setup
*****/

 Mat acbg(256, 256, CV_8UC3, Scalar(0,0,0));
// accumulated background
 Mat acbg_m(256, 256, CV_8UC1, Scalar(0));
// accumulated background mask

 int haar_scale = width/300;
 if (haar_scale < 1)
  haar_scale = 1;
// can't use 256x256 since haar isn't stretch invariant

 Mat acfg(height, width, CV_8UC1, Scalar(0));
// accumulated foreground

 Mat img_256_p(256, 256, CV_8UC3, Scalar(0,0,0));
// previous image
 Mat delta_flows[4];
 delta_flows[0] = Mat(256, 256, CV_8UC1, Scalar(1));
 delta_flows[1] = Mat(256, 256, CV_8UC1, Scalar(1));
 delta_flows[2] = Mat(256, 256, CV_8UC1, Scalar(1));
 delta_flows[3] = Mat(256, 256, CV_8UC1, Scalar(1));
// delta of past 3 frames
 Mat haar_t_p(256, 256, CV_8UC1, Scalar(1));
// previous possible locations for mouth

/*****
 end filter setup
*****/

/*****
 misc
*****/

 unsigned long long times[100];
 for (int i=0; i<100; i++)
  times[i] = 0;

 int tracker1, tracker2, tracker3, tracker4;
 namedWindow("settings",1);
 createTrackbar("1","settings",&tracker1,100);
 createTrackbar("2","settings",&tracker2,100);
 createTrackbar("3","settings",&tracker3,100);
 createTrackbar("4","settings",&tracker4,100);

 unsigned long long timenow = getMilliseconds();

 bool keep_going = true;

 CascadeClassifier mouth_cascade;
 mouth_cascade.load("Mouth.xml");

/*****
 begin filter loop
*****/

 while (keep_going) {

  Mat image(cvQueryFrame(capture));
//  imshow("webcam", image);
// at some point preprocess by rotating according to OVR roll
// right now really annoying because of state variables

  Mat gray, img_256, gray_256;
  resize(image, img_256, Size(256, 256));
  cvtColor(image, gray, CV_RGB2GRAY);
  cvtColor(img_256, gray_256, CV_RGB2GRAY);

// this mask gets anything kind of dark (DK2) and dilates
// should work *great*
  Mat gr_m;
// gray mask
  equalizeHist(gray_256, gr_m);
  threshold(gr_m, gr_m, 215, 1, THRESH_BINARY);
  dilate(gr_m, gr_m, ellipticKernel(23));
  erode(gr_m, gr_m, ellipticKernel(45));

//  imshow("gray mask", gray_256.mul(1-gr_m));

  bitwise_or(acbg_m, gr_m, acbg_m);
//  imshow("accumulated bg mask", gray_256.mul(1-acbg_m));

// this mask watches for flow against accumulated bg
  Mat fl_m;
// flow mask
  absdiff(img_256, acbg, fl_m);
  cvtColor(fl_m, fl_m, CV_BGR2GRAY);
  fl_m = acbg_m.mul(fl_m);
  threshold(fl_m, fl_m, 45, 1, THRESH_BINARY_INV);
  erode(fl_m, fl_m, ellipticKernel(51));
//  imshow("flow mask", fl_m*255);

  Mat bg_m;
  bitwise_and(acbg_m, fl_m, bg_m);
  bitwise_or(gr_m, bg_m, bg_m);
//  imshow("bgm", bg_m*255);

// maybe do some morphological operations on bg_m?
// previously combined bg_m with its opening

// ugly way to compute:
// acbg = [acbg'.(1-bg_m)]+[((acbg'+img_256)/2).bg_m]
// find a nicer way later
// problem is masks are 1 channel while images are 3 channel

  Mat bg_m3;
  Mat tmp0[3];
  tmp0[0] = tmp0[1] = tmp0[2] = bg_m;
  merge(tmp0, 3, bg_m3);
//  imshow("bg_m3", bg_m3*255);
  acbg = acbg.mul(Scalar(1,1,1)-bg_m3) + (acbg/2+img_256/2).mul(bg_m3);
//  imshow("acbg", acbg);

//  imshow("bg mask", gray_256.mul(1-bg_m));

  Mat df_m;
// delta flow mask
  absdiff(img_256, img_256_p, df_m);
  cvtColor(df_m, df_m, CV_BGR2GRAY);
  blur(df_m, df_m, Size(10, 10));
  threshold(df_m, df_m, 5, 1, THRESH_BINARY);

  dilate(df_m, df_m, ellipticKernel(25, 25));
  erode(df_m, df_m, ellipticKernel(25, 25));

  img_256_p = img_256.clone();
  delta_flows[3] = delta_flows[2];
  delta_flows[2] = delta_flows[1];
  delta_flows[1] = delta_flows[0];
  delta_flows[0] = df_m.clone();
  bitwise_or(df_m, delta_flows[3], df_m);
  bitwise_or(df_m, delta_flows[2], df_m);
  bitwise_or(df_m, delta_flows[1], df_m);

  Mat fg_m;
  bitwise_or(haar_t_p, df_m, fg_m);

  Mat haar_m;
  bitwise_and(1 - bg_m, fg_m, haar_m);

// run haar classifier

  Mat gray_haar;
  resize(gray, gray_haar, Size(width/haar_scale, height/haar_scale));
  equalizeHist(gray_haar, gray_haar);

  vector<Rect> mouth_rects;
  resize(haar_m, haar_m, Size(width/haar_scale, height/haar_scale));

  gray_haar = gray_haar.mul(haar_m);

  mouth_cascade.detectMultiScale(gray_haar, mouth_rects, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat fg(height, width, CV_8UC1, Scalar(0));

  for (size_t i=0; i<mouth_rects.size(); i++) {
   Rect scaled(mouth_rects[i].x*haar_scale, mouth_rects[i].y*haar_scale, mouth_rects[i].width*haar_scale,mouth_rects[i].height*haar_scale);
   Mat new_rect(height, width, CV_8UC1, Scalar(0));
   rectangle(new_rect, scaled, Scalar(1), CV_FILLED);
   fg += new_rect;
  }

// or maybe equalize? this whole thing needs to be rewritten
// with the new fg and temporal coherence ideas

// very interesting idea:
// if nothing moved in some place over the past frame,
// and nothing was detected last frame, whatever is
// detected now is more likely to be bogus
  acfg = acfg*0.2 + fg;

  double min_val, max_val;
  minMaxLoc(fg, &min_val, &max_val);

  Mat rect_thresh;
  threshold(acfg, rect_thresh, max_val*0.9, 1, THRESH_BINARY);
  imshow("mouth", rect_thresh.mul(gray));

  resize(acfg, haar_t_p, Size(256, 256));
  if (max_val < 10) max_val = 10;
  threshold(haar_t_p, haar_t_p, max_val*0.1, 1, THRESH_BINARY);

/*
  Moments m = moments(rect_thresh, 1);
  circle(image, Point(m.m10/m.m00,m.m01/m.m00),20,Scalar(128),30);
  imshow("centroid", image);
*/

  keep_going = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}

<commit_msg>hacking<commit_after>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

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

/*****
 begin camera setup
*****/

 CvCapture* capture = 0;
 int width, height;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream config_file (".config");

 if (config_file.is_open()) {
// does not support corrupted .config

  string line;
  getline(config_file, line);
  istringstream(line)>>width;
  getline(config_file, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  config_file.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream config_file_out(".config");
  config_file_out << width;
  config_file_out << "\n";
  config_file_out << height;
  config_file_out << "\n";
  config_file_out.close();
 }

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

/*****
 end camera setup
*****/

/*****
 filter setup
*****/

 Mat acbg(256, 256, CV_8UC3, Scalar(0,0,0));
// accumulated background
 Mat acbg_m(256, 256, CV_8UC1, Scalar(0));
// accumulated background mask

 int haar_scale = width/300;
 if (haar_scale < 1)
  haar_scale = 1;
// can't use 256x256 since haar isn't stretch invariant

 Mat acfg(height, width, CV_8UC1, Scalar(0));
// accumulated foreground

 Mat img_256_p(256, 256, CV_8UC3, Scalar(0,0,0));
// previous image
 Mat delta_flows[4];
 delta_flows[0] = Mat(256, 256, CV_8UC1, Scalar(1));
 delta_flows[1] = Mat(256, 256, CV_8UC1, Scalar(1));
 delta_flows[2] = Mat(256, 256, CV_8UC1, Scalar(1));
 delta_flows[3] = Mat(256, 256, CV_8UC1, Scalar(1));
// delta of past 3 frames
 Mat haar_t_p(256, 256, CV_8UC1, Scalar(1));
// previous possible locations for mouth

/*****
 end filter setup
*****/

/*****
 misc
*****/

 unsigned long long times[100];
 for (int i=0; i<100; i++)
  times[i] = 0;

 int tracker1, tracker2, tracker3, tracker4;
 namedWindow("settings",1);
 createTrackbar("1","settings",&tracker1,100);
 createTrackbar("2","settings",&tracker2,100);
 createTrackbar("3","settings",&tracker3,100);
 createTrackbar("4","settings",&tracker4,100);

 unsigned long long timenow = getMilliseconds();

 bool keep_going = true;

 CascadeClassifier mouth_cascade;
 mouth_cascade.load("Mouth.xml");

/*****
 begin filter loop
*****/

 while (keep_going) {

  Mat image(cvQueryFrame(capture));
//  imshow("webcam", image);
// at some point preprocess by rotating according to OVR roll
// right now really annoying because of state variables

  Mat gray, img_256, gray_256;
  resize(image, img_256, Size(256, 256));
  cvtColor(image, gray, CV_RGB2GRAY);
  cvtColor(img_256, gray_256, CV_RGB2GRAY);

// this mask gets anything kind of dark (DK2) and dilates
// should work *great*
  Mat gr_m;
// gray mask
  equalizeHist(gray_256, gr_m);
  threshold(gr_m, gr_m, 215, 1, THRESH_BINARY);
  dilate(gr_m, gr_m, ellipticKernel(23));
  erode(gr_m, gr_m, ellipticKernel(45));

//  imshow("gray mask", gray_256.mul(1-gr_m));

  bitwise_or(acbg_m, gr_m, acbg_m);
//  imshow("accumulated bg mask", gray_256.mul(1-acbg_m));

// this mask watches for flow against accumulated bg
  Mat fl_m;
// flow mask
  absdiff(img_256, acbg, fl_m);
  cvtColor(fl_m, fl_m, CV_BGR2GRAY);
  fl_m = acbg_m.mul(fl_m);
  threshold(fl_m, fl_m, 45, 1, THRESH_BINARY_INV);
  erode(fl_m, fl_m, ellipticKernel(51));
//  imshow("flow mask", fl_m*255);

  Mat bg_m;
  bitwise_and(acbg_m, fl_m, bg_m);
  bitwise_or(gr_m, bg_m, bg_m);
//  imshow("bgm", bg_m*255);

// maybe do some morphological operations on bg_m?
// previously combined bg_m with its opening

// ugly way to compute:
// acbg = [acbg'.(1-bg_m)]+[((acbg'+img_256)/2).bg_m]
// find a nicer way later
// problem is masks are 1 channel while images are 3 channel

  Mat bg_m3;
  Mat tmp0[3];
  tmp0[0] = tmp0[1] = tmp0[2] = bg_m;
  merge(tmp0, 3, bg_m3);
//  imshow("bg_m3", bg_m3*255);
  acbg = acbg.mul(Scalar(1,1,1)-bg_m3) + (acbg/2+img_256/2).mul(bg_m3);
//  imshow("acbg", acbg);

//  imshow("bg mask", gray_256.mul(1-bg_m));

  Mat df_m;
// delta flow mask
  absdiff(img_256, img_256_p, df_m);
  cvtColor(df_m, df_m, CV_BGR2GRAY);
  blur(df_m, df_m, Size(10, 10));
  threshold(df_m, df_m, 5, 1, THRESH_BINARY);

  dilate(df_m, df_m, ellipticKernel(25, 25));
  erode(df_m, df_m, ellipticKernel(25, 25));

  img_256_p = img_256.clone();
  delta_flows[3] = delta_flows[2];
  delta_flows[2] = delta_flows[1];
  delta_flows[1] = delta_flows[0];
  delta_flows[0] = df_m.clone();
  bitwise_or(df_m, delta_flows[3], df_m);
  bitwise_or(df_m, delta_flows[2], df_m);
  bitwise_or(df_m, delta_flows[1], df_m);

  Mat fg_m;
  bitwise_or(haar_t_p, df_m, fg_m);

  Mat haar_m;
  bitwise_and(1 - bg_m, fg_m, haar_m);

// run haar classifier

  Mat gray_haar;
  resize(gray, gray_haar, Size(width/haar_scale, height/haar_scale));
  equalizeHist(gray_haar, gray_haar);

  vector<Rect> mouth_rects;
  resize(haar_m, haar_m, Size(width/haar_scale, height/haar_scale));

  gray_haar = gray_haar.mul(haar_m);

  mouth_cascade.detectMultiScale(gray_haar, mouth_rects, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat fg(height, width, CV_8UC1, Scalar(0));

  for (size_t i=0; i<mouth_rects.size(); i++) {
   Rect scaled(mouth_rects[i].x*haar_scale, mouth_rects[i].y*haar_scale, mouth_rects[i].width*haar_scale,mouth_rects[i].height*haar_scale);
   Mat new_rect(height, width, CV_8UC1, Scalar(0));
   rectangle(new_rect, scaled, Scalar(1), CV_FILLED);
   fg += new_rect;
  }

// or maybe equalize? this whole thing needs to be rewritten
// with the new fg and temporal coherence ideas

// very interesting idea:
// if nothing moved in some place over the past frame,
// and nothing was detected last frame, whatever is
// detected now is more likely to be bogus
  acfg = acfg*0.2 + fg;

  double min_val, max_val;
  minMaxLoc(fg, &min_val, &max_val);

  Mat rect_thresh;
  threshold(acfg, rect_thresh, max_val*0.9, 1, THRESH_BINARY);
//  imshow("mouth", rect_thresh.mul(gray));

  resize(acfg, haar_t_p, Size(256, 256));
  if (max_val < 10) max_val = 10;
  threshold(haar_t_p, haar_t_p, max_val*0.1, 1, THRESH_BINARY);

  Moments m = moments(rect_thresh, 1);
  circle(image, Point(m.m10/m.m00,m.m01/m.m00),20,Scalar(128),30);
  imshow("centroid", image);

  keep_going = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}

<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "settings_page.h"
#include "settings.h"

namespace App {
	bool SettingsPage::PerformOnInitDialog() {
		App::Settings* pSet = dynamic_cast<App::Settings*>(Parent());
		COND_STRICT(pSet, Err::CriticalError, TX("Settings page had an invalid parent."));

		Move(pSet->GetPagePosition());
		if (!PerformOnInitPage()) return false;
		return true;
	}
}
<commit_msg>Removed cond_strict garbage<commit_after>#include "StdAfx.h"
#include "settings_page.h"
#include "settings.h"

namespace App {
	bool SettingsPage::PerformOnInitDialog() {
		auto* pSet = dynamic_cast<App::Settings*>(Parent());
		if (pSet == nullptr) {
			DO_THROW(Err::CriticalError, TX("Settings page had an invalid parent."));
		}

		Move(pSet->GetPagePosition());
		if (!PerformOnInitPage()) return false;
		return true;
	}
}
<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));
 imshow("background", background);

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
// preprocess by rotating according to OVR roll
  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray;
  cvtColor(image, gray, CV_RGB2GRAY);

// this mask filters out areas with too many edges
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  blur(image, flow, Size(50,50));
  absdiff(flow, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
//  blur(flow, flow, Size(tracker1+1,tracker1+1));
//  equalizeHist(flow, flow);
  int factor = ((tracker1)+1)/5;
  Mat flowKernel = getStructuringElement(MORPH_ELLIPSE,
   Size(
    width/factor+(1-(width/factor)%2),
    height/factor+(1-(height/factor)%2)
   )
  );
  imshow("FLOW1", flow);
  waitKey(1);
  dilate(flow, flow, flowKernel);
  imshow("FLOW1.5", flow);
  waitKey(1);
  threshold(flow, flow, tracker2*3, 1, THRESH_BINARY);
  imshow("FLOW2", gray.mul(flow));

//  Moments lol = moments(mask, 1);
//  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
//  imshow("leimage", image);

/*
  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  Mat classifyThis;
  bilateralFilter(gray, classifyThis, 15, 10, 1);
  equalizeHist(classifyThis, classifyThis);
  classifyThis = classifyThis.mul(mask);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 2, CV_HAAR_SCALE_IMAGE);
  for (size_t i=0; i<mouths.size(); i++) {
   Point center( mouths[i].x + mouths[i].width*0.5, mouths[i].y + mouths[i].height*0.5 );
   ellipse( image, center, Size( mouths[i].width*0.5, mouths[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
  }
  imshow("MOUTH", image);
*/
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));
 imshow("background", background);

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
// preprocess by rotating according to OVR roll
  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray;
  cvtColor(image, gray, CV_RGB2GRAY);

// this mask filters out areas with too many edges
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  blur(image, flow, Size(50,50));
  absdiff(flow, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
//  blur(flow, flow, Size(tracker1+1,tracker1+1));
//  equalizeHist(flow, flow);
  int factor = (tracker1/5) + 1;
  Mat flowKernel = getStructuringElement(MORPH_ELLIPSE,
   Size(
    width/factor+(1-(width/factor)%2),
    height/factor+(1-(height/factor)%2)
   )
  );
  imshow("FLOW1", flow);
  waitKey(1);
  dilate(flow, flow, flowKernel);
  imshow("FLOW1.5", flow);
  waitKey(1);
  threshold(flow, flow, tracker2*3, 1, THRESH_BINARY);
  imshow("FLOW2", gray.mul(flow));

//  Moments lol = moments(mask, 1);
//  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
//  imshow("leimage", image);

/*
  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  Mat classifyThis;
  bilateralFilter(gray, classifyThis, 15, 10, 1);
  equalizeHist(classifyThis, classifyThis);
  classifyThis = classifyThis.mul(mask);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 2, CV_HAAR_SCALE_IMAGE);
  for (size_t i=0; i<mouths.size(); i++) {
   Point center( mouths[i].x + mouths[i].width*0.5, mouths[i].y + mouths[i].height*0.5 );
   ellipse( image, center, Size( mouths[i].width*0.5, mouths[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
  }
  imshow("MOUTH", image);
*/
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBitmap.h"
#include "SkBitmapFactory.h"
#include "SkImage.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkMovie.h"

class SkColorTable;
class SkStream;
class SkStreamRewindable;

// Empty implementations for SkImageDecoder.

SkImageDecoder::SkImageDecoder() {}

SkImageDecoder::~SkImageDecoder() {}

SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable*) {
    return NULL;
}

void SkImageDecoder::copyFieldsToOther(SkImageDecoder* ) {}

bool SkImageDecoder::DecodeFile(const char[], SkBitmap*, SkBitmap::Config,
                                SkImageDecoder::Mode, SkImageDecoder::Format*) {
    return false;
}

bool SkImageDecoder::decode(SkStream*, SkBitmap*, SkBitmap::Config, Mode) {
    return false;
}

bool SkImageDecoder::DecodeStream(SkStreamRewindable*, SkBitmap*, SkBitmap::Config,
                                  SkImageDecoder::Mode,
                                  SkImageDecoder::Format*) {
    return false;
}

bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*,
                                  SkBitmap::Config, SkImageDecoder::Mode,
                                  SkImageDecoder::Format*) {
    return false;
}

bool SkImageDecoder::buildTileIndex(SkStreamRewindable*, int *width, int *height) {
    return false;
}

bool SkImageDecoder::decodeSubset(SkBitmap*, const SkIRect&, SkBitmap::Config) {
    return false;
}

SkImageDecoder::Format SkImageDecoder::getFormat() const {
    return kUnknown_Format;
}

SkImageDecoder::Format SkImageDecoder::GetStreamFormat(SkStreamRewindable*) {
    return kUnknown_Format;
}

const char* SkImageDecoder::GetFormatName(Format) {
    return NULL;
}

SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker*) {
    return NULL;
}

SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser*) {
    return NULL;
}

SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) {
    return NULL;
}

void SkImageDecoder::setSampleSize(int) {}

bool SkImageDecoder::DecodeMemoryToTarget(const void*, size_t, SkImageInfo*,
                                          const SkBitmapFactory::Target*) {
    return false;
}

SkBitmap::Config SkImageDecoder::GetDeviceConfig() {
    return SkBitmap::kNo_Config;
}

void SkImageDecoder::SetDeviceConfig(SkBitmap::Config) {}

bool SkImageDecoder::cropBitmap(SkBitmap*, SkBitmap*, int, int, int, int, int,
                    int, int) {
    return false;
}

bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config, int, int) const {
    return false;
}

bool SkImageDecoder::allocPixelRef(SkBitmap*, SkColorTable*) const {
    return false;
}

SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth, bool) const {
    return SkBitmap::kNo_Config;
}

/////////////////////////////////////////////////////////////////////////

// Empty implementation for SkMovie.

SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
    return NULL;
}

/////////////////////////////////////////////////////////////////////////

// Empty implementations for SkImageEncoder.

SkImageEncoder* SkImageEncoder::Create(Type t) {
    return NULL;
}

bool SkImageEncoder::EncodeFile(const char file[], const SkBitmap&, Type, int quality) {
    return false;
}

bool SkImageEncoder::EncodeStream(SkWStream*, const SkBitmap&, SkImageEncoder::Type, int) {
    return false;
}

SkData* SkImageEncoder::EncodeData(const SkBitmap&, Type, int quality) {
    return NULL;
}

bool SkImageEncoder::encodeStream(SkWStream*, const SkBitmap&, int) {
    return false;
}

SkData* SkImageEncoder::encodeData(const SkBitmap&, int) {
    return NULL;
}

bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quality) {
    return false;
}
/////////////////////////////////////////////////////////////////////////

// Empty implementation for SkImages.

#include "SkImages.h"

void SkImages::InitializeFlattenables() {}
<commit_msg>Fix change src/ports/SkImageDecoder_empty.cpp missed in 103033002<commit_after>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBitmap.h"
#include "SkImage.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkMovie.h"

class SkColorTable;
class SkStream;
class SkStreamRewindable;

// Empty implementations for SkImageDecoder.

SkImageDecoder::SkImageDecoder() {}

SkImageDecoder::~SkImageDecoder() {}

SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable*) {
    return NULL;
}

void SkImageDecoder::copyFieldsToOther(SkImageDecoder* ) {}

bool SkImageDecoder::DecodeFile(const char[], SkBitmap*, SkBitmap::Config,
                                SkImageDecoder::Mode, SkImageDecoder::Format*) {
    return false;
}

bool SkImageDecoder::decode(SkStream*, SkBitmap*, SkBitmap::Config, Mode) {
    return false;
}

bool SkImageDecoder::DecodeStream(SkStreamRewindable*, SkBitmap*, SkBitmap::Config,
                                  SkImageDecoder::Mode,
                                  SkImageDecoder::Format*) {
    return false;
}

bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*,
                                  SkBitmap::Config, SkImageDecoder::Mode,
                                  SkImageDecoder::Format*) {
    return false;
}

bool SkImageDecoder::buildTileIndex(SkStreamRewindable*, int *width, int *height) {
    return false;
}

bool SkImageDecoder::decodeSubset(SkBitmap*, const SkIRect&, SkBitmap::Config) {
    return false;
}

SkImageDecoder::Format SkImageDecoder::getFormat() const {
    return kUnknown_Format;
}

SkImageDecoder::Format SkImageDecoder::GetStreamFormat(SkStreamRewindable*) {
    return kUnknown_Format;
}

const char* SkImageDecoder::GetFormatName(Format) {
    return NULL;
}

SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker*) {
    return NULL;
}

SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser*) {
    return NULL;
}

SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) {
    return NULL;
}

void SkImageDecoder::setSampleSize(int) {}

bool SkImageDecoder::DecodeMemoryToTarget(const void*, size_t, SkImageInfo*,
                                          const SkImageDecoder::Target*) {
    return false;
}

SkBitmap::Config SkImageDecoder::GetDeviceConfig() {
    return SkBitmap::kNo_Config;
}

void SkImageDecoder::SetDeviceConfig(SkBitmap::Config) {}

bool SkImageDecoder::cropBitmap(SkBitmap*, SkBitmap*, int, int, int, int, int,
                    int, int) {
    return false;
}

bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config, int, int) const {
    return false;
}

bool SkImageDecoder::allocPixelRef(SkBitmap*, SkColorTable*) const {
    return false;
}

SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth, bool) const {
    return SkBitmap::kNo_Config;
}

/////////////////////////////////////////////////////////////////////////

// Empty implementation for SkMovie.

SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
    return NULL;
}

/////////////////////////////////////////////////////////////////////////

// Empty implementations for SkImageEncoder.

SkImageEncoder* SkImageEncoder::Create(Type t) {
    return NULL;
}

bool SkImageEncoder::EncodeFile(const char file[], const SkBitmap&, Type, int quality) {
    return false;
}

bool SkImageEncoder::EncodeStream(SkWStream*, const SkBitmap&, SkImageEncoder::Type, int) {
    return false;
}

SkData* SkImageEncoder::EncodeData(const SkBitmap&, Type, int quality) {
    return NULL;
}

bool SkImageEncoder::encodeStream(SkWStream*, const SkBitmap&, int) {
    return false;
}

SkData* SkImageEncoder::encodeData(const SkBitmap&, int) {
    return NULL;
}

bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quality) {
    return false;
}
/////////////////////////////////////////////////////////////////////////

// Empty implementation for SkImages.

#include "SkImages.h"

void SkImages::InitializeFlattenables() {}
<|endoftext|>


<commit_before>#include "GPU.H"

#include "CAMERA.H"
#include "LOAD_LEV.H"
#include "PROFILE.H"
#include "SHADOWS.H"
#include "SPECIFIC.H"

#include <assert.h>
#include <LIBGPU.H>
#include <LIBETC.H>

unsigned long GnFrameCounter = 19;
unsigned long GnLastFrameCount = 19;
struct PSXTEXTSTRUCT* psxtextinfo;
struct PSXSPRITESTRUCT* psxspriteinfo;
int rgbscaleme = 256;
int gfx_debugging_mode;
struct DB_STRUCT db;
struct MMTEXTURE* RoomTextInfo;
unsigned long GadwOrderingTables_V2[512];
static int LnFlipFrame;
unsigned long GadwOrderingTables[5128];
unsigned long GadwPolygonBuffers[52260];

void GPU_UseOrderingTables(unsigned long* pBuffers, int nOTSize)//5DF68(<), 5F1C8(<)
{
#if 0
	db.order_table[0] = &pBuffers[0];
	db.order_table[1] = &pBuffers[nOTSize];
	db.nOTSize = nOTSize;
	db.pickup_order_table[0] = (unsigned long*)&db.disp[1];
	db.pickup_order_table[1] = &GadwOrderingTables_V2[256];
#else
	//Should be safe to use 32-bit ptrs tho
	db.order_table[0] = (unsigned long*)((unsigned long) pBuffers & 0xFFFFFF);
	db.order_table[1] = (unsigned long*)((unsigned long) &pBuffers[nOTSize] & 0xFFFFFF);
	db.nOTSize = nOTSize;
	db.pickup_order_table[0] = (unsigned long*)((unsigned long)&db.disp[1] & 0xFFFFFF);
	db.pickup_order_table[1] = (unsigned long*)((unsigned long)&GadwOrderingTables_V2[256] & 0xFFFFFF);
#endif
	return;
}

void GPU_UsePolygonBuffers(unsigned long* pBuffers, int nPBSize)//5DFB0(<),
{
#if 0
	db.nPBSize = nPBSize;
	db.poly_buffer[0] = &pBuffers[0];
	db.poly_buffer[1] = &pBuffers[nPBSize];
#else
	db.nPBSize = nPBSize;
	db.poly_buffer[0] = (unsigned long*)((unsigned long)pBuffers & 0xFFFFFF);
	db.poly_buffer[1] = (unsigned long*)((unsigned long)&pBuffers[nPBSize] & 0xFFFFFF);
#endif
	return;
}

void GPU_EndScene()//5DFDC(<), 5F23C(<) (F)
{
#if DEBUG_VERSION
	int nPolys;
	static int nWorstPolys;

	nPolys = ((int) &db.polyptr[0] - (int) &db.curpolybuf[0]) * 0x4EC4EC4F / 16 - (((long) &db.polyptr[0] - (long) &db.curpolybuf[0]) >> 31);

	if (psxtextinfo->u2v2pad < nPolys)
	{
		psxtextinfo->u2v2pad = nPolys;
	}

	//loc_5E020
#endif

	OptimiseOTagR(&db.ot[0], db.nOTSize);

#if DEBUG_VERSION
	ProfileRGB(255, 255, 255);
	do_gfx_debug_mode(&db.ot[db.nOTSize - 1]);
	ProfileRGB(0, 255, 255);
#endif

	return;
}

int GPU_FlipNoIdle()//5E078(<), 5F264(<) (F)
{
#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileRGB(255, 255, 255);
		ProfileAddOT(&db.ot[0]);
	}
#endif

	//loc_5E0B0
	DrawSync(0);

#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileAddDrawOT(&db.ot[0]);
	}
#endif

	LnFlipFrame = GnLastFrameCount;

	//loc_5E0D8
	if (LnFlipFrame < 2)
	{
		do
		{
			VSync(0);
			LnFlipFrame++;
		} while (LnFlipFrame < 2);
	}
	else
	{
		//loc_5E120
		VSync(0);
		LnFlipFrame++;
	}

	GnLastFrameCount = 0;
	PutDispEnv(&db.disp[db.current_buffer]);
	DrawOTagEnv(&db.ot[db.nOTSize-1], &db.draw[db.current_buffer]);

#if DEBUG_VERSION
	ProfileStartCount();
#endif

	db.current_buffer ^= 1;

	return LnFlipFrame;
}

void do_gfx_debug_mode(unsigned long* otstart)
{
	S_Warn("[do_gfx_debug_mode] - Unimplemented!\n");
}

void GPU_FlipStory(unsigned long* gfx)//5E448(<), * (F)
{
	RECT r;
	RECT* fuckmyanalpassage;

	DrawSync(0);
	VSync(0);

	PutDispEnv(&db.disp[db.current_buffer]);
	fuckmyanalpassage = (RECT*) &db.disp[db.current_buffer ^ 1].disp;
	r.x = fuckmyanalpassage->x;
	r.y = fuckmyanalpassage->y;
	r.w = fuckmyanalpassage->w;
	r.h = fuckmyanalpassage->h;
	LoadImage(&r, gfx);
	DrawOTagEnv(&db.ot[db.nOTSize - 1], &db.draw[db.current_buffer]);
	db.current_buffer ^= 1;
}<commit_msg>Add do_gfx_debug_mode()<commit_after>#include "GPU.H"

#include "CAMERA.H"
#include "FXTRIG.H"
#include "LOAD_LEV.H"
#include "PROFILE.H"
#include "PSXINPUT.H"
#include "SHADOWS.H"
#include "SPECIFIC.H"

#include <assert.h>
#include <LIBGPU.H>
#include <LIBETC.H>
#include <STDIO.H>

unsigned long GnFrameCounter = 19;
unsigned long GnLastFrameCount = 19;
struct PSXTEXTSTRUCT* psxtextinfo;
struct PSXSPRITESTRUCT* psxspriteinfo;
int rgbscaleme = 256;
int gfx_debugging_mode;
struct DB_STRUCT db;
struct MMTEXTURE* RoomTextInfo;
unsigned long GadwOrderingTables_V2[512];
static int LnFlipFrame;
unsigned long GadwOrderingTables[5128];
unsigned long GadwPolygonBuffers[52260];

void GPU_UseOrderingTables(unsigned long* pBuffers, int nOTSize)//5DF68(<), 5F1C8(<)
{
#if 0
	db.order_table[0] = &pBuffers[0];
	db.order_table[1] = &pBuffers[nOTSize];
	db.nOTSize = nOTSize;
	db.pickup_order_table[0] = (unsigned long*)&db.disp[1];
	db.pickup_order_table[1] = &GadwOrderingTables_V2[256];
#else
	//Should be safe to use 32-bit ptrs tho
	db.order_table[0] = (unsigned long*)((unsigned long) pBuffers & 0xFFFFFF);
	db.order_table[1] = (unsigned long*)((unsigned long) &pBuffers[nOTSize] & 0xFFFFFF);
	db.nOTSize = nOTSize;
	db.pickup_order_table[0] = (unsigned long*)((unsigned long)&db.disp[1] & 0xFFFFFF);
	db.pickup_order_table[1] = (unsigned long*)((unsigned long)&GadwOrderingTables_V2[256] & 0xFFFFFF);
#endif
	return;
}

void GPU_UsePolygonBuffers(unsigned long* pBuffers, int nPBSize)//5DFB0(<),
{
#if 0
	db.nPBSize = nPBSize;
	db.poly_buffer[0] = &pBuffers[0];
	db.poly_buffer[1] = &pBuffers[nPBSize];
#else
	db.nPBSize = nPBSize;
	db.poly_buffer[0] = (unsigned long*)((unsigned long)pBuffers & 0xFFFFFF);
	db.poly_buffer[1] = (unsigned long*)((unsigned long)&pBuffers[nPBSize] & 0xFFFFFF);
#endif
	return;
}

void GPU_EndScene()//5DFDC(<), 5F23C(<) (F)
{
#if DEBUG_VERSION
	int nPolys;
	static int nWorstPolys;

	nPolys = ((int) &db.polyptr[0] - (int) &db.curpolybuf[0]) * 0x4EC4EC4F / 16 - (((long) &db.polyptr[0] - (long) &db.curpolybuf[0]) >> 31);

	if (psxtextinfo->u2v2pad < nPolys)
	{
		psxtextinfo->u2v2pad = nPolys;
	}

	//loc_5E020
#endif

	OptimiseOTagR(&db.ot[0], db.nOTSize);

#if DEBUG_VERSION
	ProfileRGB(255, 255, 255);
	do_gfx_debug_mode(&db.ot[db.nOTSize - 1]);
	ProfileRGB(0, 255, 255);
#endif

	return;
}

int GPU_FlipNoIdle()//5E078(<), 5F264(<) (F)
{
#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileRGB(255, 255, 255);
		ProfileAddOT(&db.ot[0]);
	}
#endif

	//loc_5E0B0
	DrawSync(0);

#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileAddDrawOT(&db.ot[0]);
	}
#endif

	LnFlipFrame = GnLastFrameCount;

	//loc_5E0D8
	if (LnFlipFrame < 2)
	{
		do
		{
			VSync(0);
			LnFlipFrame++;
		} while (LnFlipFrame < 2);
	}
	else
	{
		//loc_5E120
		VSync(0);
		LnFlipFrame++;
	}

	GnLastFrameCount = 0;
	PutDispEnv(&db.disp[db.current_buffer]);
	DrawOTagEnv(&db.ot[db.nOTSize-1], &db.draw[db.current_buffer]);

#if DEBUG_VERSION
	ProfileStartCount();
#endif

	db.current_buffer ^= 1;

	return LnFlipFrame;
}

void do_gfx_debug_mode(unsigned long* otstart)//5E1B4(<) ? (F)
{
	unsigned long* data;
	unsigned char code;
	int ntri;
	int nquad;
	unsigned short x0;
	unsigned short y0;
	unsigned short x1;
	unsigned short y1;
	unsigned short x2;
	unsigned short y2;
	LINE_F2* line2;
	char txbuf[64];

	if (RawEdge & 8)
	{
		gfx_debugging_mode++;
	}

	//loc_5E1E0
	nquad = 0;

	if (gfx_debugging_mode > 2)
	{
		gfx_debugging_mode = 0;
	}

	//loc_5E1F8
	data = (unsigned long*)otstart[0];
	ntri = 0;

	if (((unsigned long)data & 0xFFFFFF) != 0xFFFFFF)
	{
		do
		{
			if (data[0] & 0xFF000000 != 0)
			{
				code = ((char*)data)[7];

				if (gfx_debugging_mode < 2)
				{
					if ((code & 0xFC) == 0x7C)
					{
						if (gfx_debugging_mode != 0)
						{
							((short*)data)[13] &= 0xFF9F;
						}
						else
						{
							//loc_5E27C
							((char*)data)[7] = (code & 2) | 0x3C;
						}

						nquad = 1;
					}
					else if ((code & 0xFC) == 0x74)
					{
						//loc_5E290
						if (gfx_debugging_mode != 0)
						{
							((char*)data)[7] = 0x36;
							((short*)data)[13] &= 0xFF9F;
						}
						else
						{
							//loc_5E2B4
							((char*)data)[7] = (code & 2) | 0x34;
						}

						ntri = 1;
					}//loc_5E3C4
				}
				else if (gfx_debugging_mode == 2)
				{
					//loc_5E2C8

					if ((code & 0xFC) == 0x7C)
					{
						x0 = ((unsigned short*)data)[4];
						y0 = ((unsigned short*)data)[5];
						x1 = ((unsigned short*)data)[10];
						y1 = ((unsigned short*)data)[11];
						x2 = ((unsigned short*)data)[16];
						y2 = ((unsigned short*)data)[17];

						nquad++;

						((char*)data)[7] = 0x4C;
						((char*)data)[4] = 0x0;
						((char*)data)[5] = 0x50;
						((char*)data)[6] = 0x0;
						((long*)data)[6] = 0x55555555;

						((short*)data)[8] = ((unsigned short*)data)[22];

						line2 = (struct LINE_F2*)&data[6];

						((short*)data)[9] = ((unsigned short*)data)[23];

						((short*)data)[4] = x0;
						((short*)data)[5] = y0;
						((short*)data)[6] = x1;
						((short*)data)[7] = y1;
						((short*)data)[10] = x2;
						((short*)data)[11] = y2;

						line2->code = 0x40;
						line2->x0 = x0;
						line2->y0 = y0;
						line2->x1 = x2;
						line2->y1 = y2;
						line2->r0 = 0;
						line2->g0 = 80;
						line2->b0 = 0;

						((char*)data)[3] = 9;
					}
					else if ((code & 0xFC) == 0x74)
					{
						//loc_5E368
						ntri++;

						x0 = ((unsigned short*)data)[4];
						y0 = ((unsigned short*)data)[5];
						x1 = ((unsigned short*)data)[10];
						y1 = ((unsigned short*)data)[11];
						x2 = ((unsigned short*)data)[16];
						y2 = ((unsigned short*)data)[17];

						((char*)data)[7] = 76;
						((char*)data)[4] = 0;
						((char*)data)[5] = 80;
						((char*)data)[6] = 0;
						((long*)data)[6] = 0x55555555;
						((char*)data)[3] = 6;
						((short*)data)[4] = x0;
						((short*)data)[5] = y0;
						((short*)data)[6] = x1;
						((short*)data)[7] = y1;
						((short*)data)[8] = x2;
						((short*)data)[9] = y2;
						((short*)data)[10] = x0;
						((short*)data)[11] = y0;
					}
				}//loc_5E3C4
			}
		}while (data[0] != 0xFFFFFF);
		//loc_5E3C4
	}

	//loc_5E3D8
	if (gfx_debugging_mode == 0)
	{
		return;
	}

	sprintf(&txbuf[0], "TRI %d", ntri);
	PrintString(34, 220, 3, &txbuf[0], 0);

	sprintf(&txbuf[0], "QUAD %d", nquad);
	PrintString(34, 232, 3, &txbuf[0], 0);
}

void GPU_FlipStory(unsigned long* gfx)//5E448(<), * (F)
{
	RECT r;
	RECT* fuckmyanalpassage;

	DrawSync(0);
	VSync(0);

	PutDispEnv(&db.disp[db.current_buffer]);
	fuckmyanalpassage = (RECT*) &db.disp[db.current_buffer ^ 1].disp;
	r.x = fuckmyanalpassage->x;
	r.y = fuckmyanalpassage->y;
	r.w = fuckmyanalpassage->w;
	r.h = fuckmyanalpassage->h;
	LoadImage(&r, gfx);
	DrawOTagEnv(&db.ot[db.nOTSize - 1], &db.draw[db.current_buffer]);
	db.current_buffer ^= 1;
}<|endoftext|>


<commit_before>/*
 *The MIT License (MIT)
 *
 * Copyright (c) <2016> <Stephan Gatzka>
 *
 * 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.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE http_connection_tests

#include <boost/test/unit_test.hpp>
#include <errno.h>

#include "buffered_socket.h"
#include "eventloop.h"
#include "http_connection.h"
#include "socket.h"

#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))

#ifndef ARRAY_SIZE
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

static bool close_called = false;
static bool create_called = false;

static const char *readbuffer;
static const char *readbuffer_ptr;
static size_t readbuffer_length;

static char write_buffer[5000];
size_t write_buffer_written;
static char *write_buffer_ptr;

static const int FD_WOULDBLOCK = 1;
static const int FD_COMPLETE_STARTLINE = 2;
static const int FD_CLOSE = 3;
static const int FD_ERROR = 4;

extern "C" {
	ssize_t socket_writev(socket_type sock, struct buffered_socket_io_vector *io_vec, unsigned int count)
	{
		(void)io_vec;
		(void)count;

		switch (sock) {
		case FD_COMPLETE_STARTLINE: {
			size_t complete_length = 0;
			for (unsigned int i = 0; i < count; i++) {
				memcpy(write_buffer_ptr, io_vec[i].iov_base, io_vec[i].iov_len);
				complete_length += io_vec[i].iov_len;
				write_buffer_ptr += io_vec[i].iov_len;
			}
			write_buffer_written = complete_length;
			return complete_length;
		}

		case FD_WOULDBLOCK:
		default:
			errno = EWOULDBLOCK;
			return -1;
		}
	}

	ssize_t socket_read(socket_type sock, void *buf, size_t count)
	{
		(void)buf;
		(void)count;

		switch (sock) {
		case FD_COMPLETE_STARTLINE:
			if (readbuffer_length > 0) {
				size_t len = MIN(readbuffer_length, count);
				memcpy(buf, readbuffer_ptr, len);
				readbuffer_length -= len;
				readbuffer_ptr += len;
				return len;
			} else {
				errno = EWOULDBLOCK;
				return -1;
			}
			break;

		case FD_CLOSE:
			return 0;

		case FD_ERROR:
			errno = EINVAL;
			return -1;

		case FD_WOULDBLOCK:
		default:
			errno = EWOULDBLOCK;
			return -1;
		}
	}

	int socket_close(socket_type sock)
	{
		(void)sock;
		close_called = true;
		return 0;
	}
}

static enum eventloop_return eventloop_fake_add(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	(void)ev;
	return EL_CONTINUE_LOOP;
}

static void eventloop_fake_remove(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	(void)ev;
}

int on_create(struct http_connection *connection)
{
	(void)connection;
	create_called = true;
	return 0;
}

struct F {
	F()
	{
		close_called = false;
		create_called = false;

		loop.this_ptr = NULL;
		loop.init = NULL;
		loop.destroy = NULL;
		loop.run = NULL;
		loop.add = eventloop_fake_add;
		loop.remove = eventloop_fake_remove;

		readbuffer_ptr = readbuffer;
		write_buffer_ptr = write_buffer;
		write_buffer_written = 0;

		http_parser_settings_init(&parser_settings);
		http_parser_init(&parser, HTTP_RESPONSE);

		handler[0].request_target = "/";
		handler[0].create = NULL;
		handler[0].on_header_field = NULL;
		handler[0].on_header_value = NULL;
		handler[0].on_headers_complete = NULL;
		handler[0].on_body = NULL;
		handler[0].on_message_complete = NULL;

		http_server.handler = handler;
		http_server.num_handlers = ARRAY_SIZE(handler);
	}

	~F()
	{
	}

	struct eventloop loop;
	http_parser parser;
	http_parser_settings parser_settings;
	struct url_handler handler[1];
	struct http_server http_server;
};

BOOST_FIXTURE_TEST_CASE(test_websocket_alloc, F)
{
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_WOULDBLOCK, false);
	BOOST_CHECK_MESSAGE(connection != NULL, "Connection allocation failed!");
	free_connection(connection);
}

BOOST_FIXTURE_TEST_CASE(test_buffered_socket_migration, F)
{
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_WOULDBLOCK, false);
	BOOST_CHECK(connection != NULL);

	struct buffered_socket *bs = connection->bs;
	connection->bs = NULL;
	free_connection(connection);
	BOOST_CHECK_MESSAGE(!close_called, "Close was called after buffered_socket migration!");
	buffered_socket_close(bs);
	free(bs);
	BOOST_CHECK_MESSAGE(close_called, "Close was not called after buffered_socket_close!");
}

BOOST_FIXTURE_TEST_CASE(test_read_invalid_startline, F)
{
	readbuffer = "aaaa\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_read_close, F)
{
	readbuffer = "aaaa\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_CLOSE, false);
	BOOST_CHECK(connection == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_read_error, F)
{
	readbuffer = "aaaa\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_ERROR, false);
	BOOST_CHECK(connection == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_url_match, F)
{
	readbuffer = "GET /infotext.html HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection != NULL);

	free_connection(connection);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_url_match_create_called, F)
{
	handler[0].create = on_create;
	readbuffer = "GET /infotext.html HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection != NULL);
	BOOST_CHECK_MESSAGE(create_called, "Create callback was not called!");

	free_connection(connection);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_url_no_match, F)
{
	handler[0].request_target = "/foobar/";

	readbuffer = "GET /infotext.html HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);

	size_t nparsed = http_parser_execute(&parser, &parser_settings, write_buffer, write_buffer_written);
	BOOST_CHECK(nparsed == write_buffer_written);
	BOOST_CHECK(parser.status_code == 404);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_invalid_url, F)
{
	handler[0].request_target = "/foobar/";

	readbuffer = "GET http://ww%.google.de/ HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);

	size_t nparsed = http_parser_execute(&parser, &parser_settings, write_buffer, write_buffer_written);
	BOOST_CHECK(nparsed == write_buffer_written);
	BOOST_CHECK(parser.status_code == 400);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_connect_request_url_match, F)
{
	readbuffer = "CONNECT www.example.com:443 HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);

	size_t nparsed = http_parser_execute(&parser, &parser_settings, write_buffer, write_buffer_written);
	BOOST_CHECK(nparsed == write_buffer_written);
	BOOST_CHECK(parser.status_code == 400);
}
<commit_msg>Initialize the event structure in http_server completely.<commit_after>/*
 *The MIT License (MIT)
 *
 * Copyright (c) <2016> <Stephan Gatzka>
 *
 * 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.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE http_connection_tests

#include <boost/test/unit_test.hpp>
#include <errno.h>

#include "buffered_socket.h"
#include "eventloop.h"
#include "http_connection.h"
#include "socket.h"

#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))

#ifndef ARRAY_SIZE
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

static bool close_called = false;
static bool create_called = false;

static const char *readbuffer;
static const char *readbuffer_ptr;
static size_t readbuffer_length;

static char write_buffer[5000];
size_t write_buffer_written;
static char *write_buffer_ptr;

static const int FD_WOULDBLOCK = 1;
static const int FD_COMPLETE_STARTLINE = 2;
static const int FD_CLOSE = 3;
static const int FD_ERROR = 4;

extern "C" {
	ssize_t socket_writev(socket_type sock, struct buffered_socket_io_vector *io_vec, unsigned int count)
	{
		(void)io_vec;
		(void)count;

		switch (sock) {
		case FD_COMPLETE_STARTLINE: {
			size_t complete_length = 0;
			for (unsigned int i = 0; i < count; i++) {
				memcpy(write_buffer_ptr, io_vec[i].iov_base, io_vec[i].iov_len);
				complete_length += io_vec[i].iov_len;
				write_buffer_ptr += io_vec[i].iov_len;
			}
			write_buffer_written = complete_length;
			return complete_length;
		}

		case FD_WOULDBLOCK:
		default:
			errno = EWOULDBLOCK;
			return -1;
		}
	}

	ssize_t socket_read(socket_type sock, void *buf, size_t count)
	{
		(void)buf;
		(void)count;

		switch (sock) {
		case FD_COMPLETE_STARTLINE:
			if (readbuffer_length > 0) {
				size_t len = MIN(readbuffer_length, count);
				memcpy(buf, readbuffer_ptr, len);
				readbuffer_length -= len;
				readbuffer_ptr += len;
				return len;
			} else {
				errno = EWOULDBLOCK;
				return -1;
			}
			break;

		case FD_CLOSE:
			return 0;

		case FD_ERROR:
			errno = EINVAL;
			return -1;

		case FD_WOULDBLOCK:
		default:
			errno = EWOULDBLOCK;
			return -1;
		}
	}

	int socket_close(socket_type sock)
	{
		(void)sock;
		close_called = true;
		return 0;
	}
}

static enum eventloop_return eventloop_fake_add(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	(void)ev;
	return EL_CONTINUE_LOOP;
}

static void eventloop_fake_remove(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	(void)ev;
}

int on_create(struct http_connection *connection)
{
	(void)connection;
	create_called = true;
	return 0;
}

struct F {
	F()
	{
		close_called = false;
		create_called = false;

		loop.this_ptr = NULL;
		loop.init = NULL;
		loop.destroy = NULL;
		loop.run = NULL;
		loop.add = eventloop_fake_add;
		loop.remove = eventloop_fake_remove;

		readbuffer_ptr = readbuffer;
		write_buffer_ptr = write_buffer;
		write_buffer_written = 0;

		http_parser_settings_init(&parser_settings);
		http_parser_init(&parser, HTTP_RESPONSE);

		handler[0].request_target = "/";
		handler[0].create = NULL;
		handler[0].on_header_field = NULL;
		handler[0].on_header_value = NULL;
		handler[0].on_headers_complete = NULL;
		handler[0].on_body = NULL;
		handler[0].on_message_complete = NULL;

		http_server.handler = handler;
		http_server.num_handlers = ARRAY_SIZE(handler);

		http_server.ev.read_function = NULL;
		http_server.ev.write_function = NULL;
		http_server.ev.error_function = NULL;
		http_server.ev.loop = NULL;
		http_server.ev.sock = 0;
	}

	~F()
	{
	}

	struct eventloop loop;
	http_parser parser;
	http_parser_settings parser_settings;
	struct url_handler handler[1];
	struct http_server http_server;
};

BOOST_FIXTURE_TEST_CASE(test_websocket_alloc, F)
{
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_WOULDBLOCK, false);
	BOOST_CHECK_MESSAGE(connection != NULL, "Connection allocation failed!");
	free_connection(connection);
}

BOOST_FIXTURE_TEST_CASE(test_buffered_socket_migration, F)
{
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_WOULDBLOCK, false);
	BOOST_CHECK(connection != NULL);

	struct buffered_socket *bs = connection->bs;
	connection->bs = NULL;
	free_connection(connection);
	BOOST_CHECK_MESSAGE(!close_called, "Close was called after buffered_socket migration!");
	buffered_socket_close(bs);
	free(bs);
	BOOST_CHECK_MESSAGE(close_called, "Close was not called after buffered_socket_close!");
}

BOOST_FIXTURE_TEST_CASE(test_read_invalid_startline, F)
{
	readbuffer = "aaaa\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_read_close, F)
{
	readbuffer = "aaaa\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_CLOSE, false);
	BOOST_CHECK(connection == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_read_error, F)
{
	readbuffer = "aaaa\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(NULL, &loop, FD_ERROR, false);
	BOOST_CHECK(connection == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_url_match, F)
{
	readbuffer = "GET /infotext.html HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection != NULL);

	free_connection(connection);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_url_match_create_called, F)
{
	handler[0].create = on_create;
	readbuffer = "GET /infotext.html HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection != NULL);
	BOOST_CHECK_MESSAGE(create_called, "Create callback was not called!");

	free_connection(connection);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_url_no_match, F)
{
	handler[0].request_target = "/foobar/";

	readbuffer = "GET /infotext.html HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);

	size_t nparsed = http_parser_execute(&parser, &parser_settings, write_buffer, write_buffer_written);
	BOOST_CHECK(nparsed == write_buffer_written);
	BOOST_CHECK(parser.status_code == 404);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_invalid_url, F)
{
	handler[0].request_target = "/foobar/";

	readbuffer = "GET http://ww%.google.de/ HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);

	size_t nparsed = http_parser_execute(&parser, &parser_settings, write_buffer, write_buffer_written);
	BOOST_CHECK(nparsed == write_buffer_written);
	BOOST_CHECK(parser.status_code == 400);
}

BOOST_FIXTURE_TEST_CASE(test_read_valid_startline_connect_request_url_match, F)
{
	readbuffer = "CONNECT www.example.com:443 HTTP/1.1\r\n";
	readbuffer_ptr = readbuffer;
	readbuffer_length = ::strlen(readbuffer);
	struct http_connection *connection = alloc_http_connection(&http_server, &loop, FD_COMPLETE_STARTLINE, false);
	BOOST_CHECK(connection == NULL);

	size_t nparsed = http_parser_execute(&parser, &parser_settings, write_buffer, write_buffer_written);
	BOOST_CHECK(nparsed == write_buffer_written);
	BOOST_CHECK(parser.status_code == 400);
}
<|endoftext|>


<commit_before>/**
 * @file /tip-server/src/tip/http/server/connection.cpp
 * @brief
 * @date Jul 8, 2015
 * @author: zmij
 */

#include <tip/http/server/connection.hpp>
#include <tip/http/server/request_handler.hpp>
#include <tip/http/server/remote_address.hpp>
#include <tip/http/server/reply_context.hpp>

#include <tip/http/common/request.hpp>
#include <tip/http/common/response.hpp>
#include <tip/http/common/grammar/response_generate.hpp>

#include <tip/http/version.hpp>

#include <tip/log.hpp>

#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/lexical_cast.hpp>

#include <vector>
#include <functional>

namespace tip {
namespace http {
namespace server {

LOCAL_LOGGING_FACILITY(HTTPCONN, TRACE);

connection::connection(io_service_ptr io_service,
                       request_handler_ptr handler) :
	io_service_(io_service),
	strand_(*io_service),
	socket_(*io_service),
	request_handler_(handler),
	default_headers_{
		{ Server, "tip-http-server/" + tip::VERSION }
	}
{
}

connection::~connection()
{
}

boost::asio::ip::tcp::socket& connection::socket()
{
	return socket_;
}

void
connection::start(endpoint_ptr peer)
{
	local_log() << "Start new connection with " << peer->address();
	peer_ = peer;
	read_request_headers();
}

void
connection::read_request_headers()
{
	boost::asio::async_read_until(socket_, incoming_, "\r\n\r\n",
		strand_.wrap(std::bind(&connection::handle_read_headers,
			shared_from_this(),
			std::placeholders::_1, std::placeholders::_2)));
}

void
connection::handle_read_headers(const boost::system::error_code& e,
								std::size_t bytes_transferred)
{
	if (!e) {
		typedef boost::spirit::istream_iterator buffer_iterator;
		std::istream is(&incoming_);
		request_ptr req = std::make_shared< request >();
		if (req->read_headers(is)) {
			read_request_body(req, req->read_body(is));
		} else {
			// Bad request
			send_error(req, response_status::bad_request);
			local_log(logger::ERROR) << "Error parsing headers";
		}
	} else {
		local_log(logger::DEBUG) << "Error reading request headers: "
				<< e.message();
	}
}

void
connection::read_request_body(request_ptr req, read_result_type res)
{
	using std::placeholders::_1;
	using std::placeholders::_2;
	if (res.result) {
		// success read
		io_service_ptr io = io_service_.lock();
		if (io) {
			reply rep{
				io,
				req,
				strand_.wrap(std::bind(&connection::send_response,
						shared_from_this(), req, std::placeholders::_1)),
				strand_.wrap(std::bind(&connection::send_error,
						shared_from_this(), req, std::placeholders::_1))
			};
			add_context(rep, new remote_address(rep, peer_));
			try {
				request_handler_->handle_request(rep);
			} catch (::std::exception const& e) {
				local_log(logger::ERROR) << "Exception when dispatching request "
						<< req->path << ": " << e.what();
			} catch (...) {
				local_log(logger::ERROR) << "Unknown exception when dispatching request "
						<< req->path;
			}
		} else {
			local_log(logger::WARNING) << "IO service weak pointer is bad";
		}
	} else if (!res.result) {
		// fail read
		local_log(logger::WARNING) << "Failed to read request body";
		send_error(req, response_status::bad_request);
	} else if (res.callback) {
		boost::asio::async_read(socket_, incoming_,
			boost::asio::transfer_at_least(1),
			strand_.wrap( std::bind( &connection::handle_read_body,
				shared_from_this(), _1, _2, req, res.callback) ));
	} else {
		// need more data but no callback
		local_log(logger::WARNING) << "Request read body returned "
				"indeterminate, but provided no callback";
	}
}

void
connection::handle_read_body(const boost::system::error_code& e,
								std::size_t bytes_transferred,
								request_ptr req,
								read_callback cb)
{
	if (!e) {
		std::istream is(&incoming_);
		read_request_body(req, cb(is));
	} else {
		local_log(logger::DEBUG) << "Error reading request body: "
				<< e.message();
	}

	// If an error occurs then no new asynchronous operations are started. This
	// means that all shared_ptr references to the connection object will
	// disappear and the object will be destroyed automatically after this
	// handler returns. The connection class's destructor closes the socket.
}

void
connection::send_response(request_ptr req, response_const_ptr resp)
{
	typedef std::vector< boost::asio::const_buffer > output_buffers_type;
	using std::placeholders::_1;
	using std::placeholders::_2;

	local_log() << req->method << " " << req->path
			<< " " << resp->status << " '" << resp->status_line << "'";
	if (is_error(resp->status) && (HTTPCONN_DEFAULT_SEVERITY != logger::OFF)) {
		local_log() << "Request headers:\n" << req->headers_;
	}

	std::ostream os(&outgoing_);
	os << *resp;
	if (!resp->headers_.count(ContentLength)) {
		header content_length{
			ContentLength,
			boost::lexical_cast<std::string>( resp->body_.size() )
		};
		os << content_length;
	}
	if (!default_headers_.empty()) {
		os << default_headers_;
	}
	os << "\r\n";

	output_buffers_type buffers;
	buffers.push_back(boost::asio::buffer(outgoing_.data()));
	buffers.push_back(boost::asio::buffer(resp->body_));
	boost::asio::async_write(socket_, buffers,
		strand_.wrap(std::bind(&connection::handle_write_response,
			shared_from_this(), _1, _2, resp)));
}

void
connection::send_error(request_ptr req, response_status status)
{
	response_const_ptr resp = response::stock_response(status);
	send_response(req, resp);
}

void
connection::handle_write(const boost::system::error_code& e)
{
	if (!e) {
		// Initiate graceful connection closure.
		boost::system::error_code ignored_ec;
		socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
				ignored_ec);
	}

	// TODO Keep-Alive and timer
	// No new asynchronous operations are started. This means that all shared_ptr
	// references to the connection object will disappear and the object will be
	// destroyed automatically after this handler returns. The connection class's
	// destructor closes the socket.
}

void
connection::handle_write_response(boost::system::error_code const& e,
		size_t bytes_transferred, response_const_ptr resp)
{
	if (!e) {
		// Initiate graceful connection closure.
		boost::system::error_code ignored_ec;
		socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
				ignored_ec);
	}

	// TODO Keep-Alive and timer
	// No new asynchronous operations are started. This means that all shared_ptr
	// references to the connection object will disappear and the object will be
	// destroyed automatically after this handler returns. The connection class's
	// destructor closes the socket.
}

} // namespace server
} // namespace http
}  // namespace tip
<commit_msg>Output first 100 bytes of erroneous request to trace log<commit_after>/**
 * @file /tip-server/src/tip/http/server/connection.cpp
 * @brief
 * @date Jul 8, 2015
 * @author: zmij
 */

#include <tip/http/server/connection.hpp>
#include <tip/http/server/request_handler.hpp>
#include <tip/http/server/remote_address.hpp>
#include <tip/http/server/reply_context.hpp>

#include <tip/http/common/request.hpp>
#include <tip/http/common/response.hpp>
#include <tip/http/common/grammar/response_generate.hpp>

#include <tip/http/version.hpp>

#include <tip/log.hpp>

#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/lexical_cast.hpp>

#include <vector>
#include <functional>

namespace tip {
namespace http {
namespace server {

LOCAL_LOGGING_FACILITY(HTTPCONN, TRACE);

connection::connection(io_service_ptr io_service,
                       request_handler_ptr handler) :
	io_service_(io_service),
	strand_(*io_service),
	socket_(*io_service),
	request_handler_(handler),
	default_headers_{
		{ Server, "tip-http-server/" + tip::VERSION }
	}
{
}

connection::~connection()
{
}

boost::asio::ip::tcp::socket& connection::socket()
{
	return socket_;
}

void
connection::start(endpoint_ptr peer)
{
	local_log() << "Start new connection with " << peer->address();
	peer_ = peer;
	read_request_headers();
}

void
connection::read_request_headers()
{
	boost::asio::async_read_until(socket_, incoming_, "\r\n\r\n",
		strand_.wrap(std::bind(&connection::handle_read_headers,
			shared_from_this(),
			std::placeholders::_1, std::placeholders::_2)));
}

void
connection::handle_read_headers(const boost::system::error_code& e,
								std::size_t bytes_transferred)
{
	if (!e) {
		typedef boost::spirit::istream_iterator buffer_iterator;
		std::istream is(&incoming_);
		request_ptr req = std::make_shared< request >();
		if (req->read_headers(is)) {
			read_request_body(req, req->read_body(is));
		} else {
			// Bad request
			send_error(req, response_status::bad_request);
			local_log(logger::ERROR) << "Error parsing headers";
		}
	} else {
		local_log(logger::DEBUG) << "Error reading request headers: "
				<< e.message();
	}
}

void
connection::read_request_body(request_ptr req, read_result_type res)
{
	using std::placeholders::_1;
	using std::placeholders::_2;
	if (res.result) {
		// success read
		io_service_ptr io = io_service_.lock();
		if (io) {
			reply rep{
				io,
				req,
				strand_.wrap(std::bind(&connection::send_response,
						shared_from_this(), req, std::placeholders::_1)),
				strand_.wrap(std::bind(&connection::send_error,
						shared_from_this(), req, std::placeholders::_1))
			};
			add_context(rep, new remote_address(rep, peer_));
			try {
				request_handler_->handle_request(rep);
			} catch (::std::exception const& e) {
				local_log(logger::ERROR) << "Exception when dispatching request "
						<< req->path << ": " << e.what();
			} catch (...) {
				local_log(logger::ERROR) << "Unknown exception when dispatching request "
						<< req->path;
			}
		} else {
			local_log(logger::WARNING) << "IO service weak pointer is bad";
		}
	} else if (!res.result) {
		// fail read
		local_log(logger::WARNING) << "Failed to read request body";
		send_error(req, response_status::bad_request);
	} else if (res.callback) {
		boost::asio::async_read(socket_, incoming_,
			boost::asio::transfer_at_least(1),
			strand_.wrap( std::bind( &connection::handle_read_body,
				shared_from_this(), _1, _2, req, res.callback) ));
	} else {
		// need more data but no callback
		local_log(logger::WARNING) << "Request read body returned "
				"indeterminate, but provided no callback";
	}
}

void
connection::handle_read_body(const boost::system::error_code& e,
								std::size_t bytes_transferred,
								request_ptr req,
								read_callback cb)
{
	if (!e) {
		std::istream is(&incoming_);
		read_request_body(req, cb(is));
	} else {
		local_log(logger::DEBUG) << "Error reading request body: "
				<< e.message();
	}

	// If an error occurs then no new asynchronous operations are started. This
	// means that all shared_ptr references to the connection object will
	// disappear and the object will be destroyed automatically after this
	// handler returns. The connection class's destructor closes the socket.
}

void
connection::send_response(request_ptr req, response_const_ptr resp)
{
	typedef std::vector< boost::asio::const_buffer > output_buffers_type;
	using std::placeholders::_1;
	using std::placeholders::_2;

	local_log() << req->method << " " << req->path
			<< " " << resp->status << " '" << resp->status_line << "'";
	if (is_error(resp->status) && (HTTPCONN_DEFAULT_SEVERITY != logger::OFF)) {
		local_log() << "Request headers:\n" << req->headers_;
		if (!req->body_.empty()) {
			::std::size_t bs = req->body_.size() < 100 ? req->body_.size() : 100;
			::std::string body(req->body_.begin(), req->body_.begin() + 100);
			local_log() << "Request body (max 100 bytes):\n"
					<< body;
		}
	}

	std::ostream os(&outgoing_);
	os << *resp;
	if (!resp->headers_.count(ContentLength)) {
		header content_length{
			ContentLength,
			boost::lexical_cast<std::string>( resp->body_.size() )
		};
		os << content_length;
	}
	if (!default_headers_.empty()) {
		os << default_headers_;
	}
	os << "\r\n";

	output_buffers_type buffers;
	buffers.push_back(boost::asio::buffer(outgoing_.data()));
	buffers.push_back(boost::asio::buffer(resp->body_));
	boost::asio::async_write(socket_, buffers,
		strand_.wrap(std::bind(&connection::handle_write_response,
			shared_from_this(), _1, _2, resp)));
}

void
connection::send_error(request_ptr req, response_status status)
{
	response_const_ptr resp = response::stock_response(status);
	send_response(req, resp);
}

void
connection::handle_write(const boost::system::error_code& e)
{
	if (!e) {
		// Initiate graceful connection closure.
		boost::system::error_code ignored_ec;
		socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
				ignored_ec);
	}

	// TODO Keep-Alive and timer
	// No new asynchronous operations are started. This means that all shared_ptr
	// references to the connection object will disappear and the object will be
	// destroyed automatically after this handler returns. The connection class's
	// destructor closes the socket.
}

void
connection::handle_write_response(boost::system::error_code const& e,
		size_t bytes_transferred, response_const_ptr resp)
{
	if (!e) {
		// Initiate graceful connection closure.
		boost::system::error_code ignored_ec;
		socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
				ignored_ec);
	}

	// TODO Keep-Alive and timer
	// No new asynchronous operations are started. This means that all shared_ptr
	// references to the connection object will disappear and the object will be
	// destroyed automatically after this handler returns. The connection class's
	// destructor closes the socket.
}

} // namespace server
} // namespace http
}  // namespace tip
<|endoftext|>


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

#include <emscripten/emscripten.h>
#include <map>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/trace_processor.h"

#include "perfetto/trace_processor/raw_query.pb.h"
#include "perfetto/trace_processor/sched.pb.h"

namespace perfetto {
namespace trace_processor {

using RequestID = uint32_t;

// Reply(): replies to a RPC method invocation.
// Called asynchronously (i.e. in a separate task) by the C++ code inside the
// trace processor to return data for a RPC method call.
// The function is generic and thankfully we need just one for all methods
// because the output is always a protobuf buffer.
// Args:
//  RequestID: the ID passed by the embedder when invoking the RPC method (e.g.,
//             the first argument passed to sched_getSchedEvents()).
using ReplyFunction = void (*)(RequestID,
                               bool success,
                               const char* /*proto_reply_data*/,
                               uint32_t /*len*/);

namespace {
TraceProcessor* g_trace_processor;
ReplyFunction g_reply;
}  // namespace
// +---------------------------------------------------------------------------+
// | Exported functions called by the JS/TS running in the worker.             |
// +---------------------------------------------------------------------------+
extern "C" {

void EMSCRIPTEN_KEEPALIVE Initialize(ReplyFunction);
void Initialize(ReplyFunction reply_function) {
  PERFETTO_ILOG("Initializing WASM bridge");
  Config config;
  g_trace_processor = TraceProcessor::CreateInstance(config).release();
  g_reply = reply_function;
}

void EMSCRIPTEN_KEEPALIVE trace_processor_parse(RequestID,
                                                const uint8_t*,
                                                uint32_t);
void trace_processor_parse(RequestID id, const uint8_t* data, size_t size) {
  // TODO(primiano): This copy is extremely unfortunate. Ideally there should be
  // a way to take the Blob coming from JS (either from FileReader or from th
  // fetch() stream) and move into WASM.
  // See https://github.com/WebAssembly/design/issues/1162.
  std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
  memcpy(buf.get(), data, size);
  g_trace_processor->Parse(std::move(buf), size);
  g_reply(id, true, "", 0);
}

// We keep the same signature as other methods even though we don't take input
// arguments for simplicity.
void EMSCRIPTEN_KEEPALIVE trace_processor_notifyEof(RequestID,
                                                    const uint8_t*,
                                                    uint32_t);
void trace_processor_notifyEof(RequestID id, const uint8_t*, uint32_t size) {
  PERFETTO_DCHECK(!size);
  g_trace_processor->NotifyEndOfFile();
  g_reply(id, true, "", 0);
}

void EMSCRIPTEN_KEEPALIVE trace_processor_rawQuery(RequestID,
                                                   const uint8_t*,
                                                   int);
void trace_processor_rawQuery(RequestID id,
                              const uint8_t* query_data,
                              int len) {
  protos::RawQueryArgs query;
  bool parsed = query.ParseFromArray(query_data, len);
  if (!parsed) {
    std::string err = "Failed to parse input request";
    g_reply(id, false, err.data(), err.size());
    return;
  }

  // When the C++ class implementing the service replies, serialize the protobuf
  // result and post it back to the worker script (|g_reply|).
  auto callback = [id](const protos::RawQueryResult& res) {
    std::string encoded;
    res.SerializeToString(&encoded);
    g_reply(id, true, encoded.data(), static_cast<uint32_t>(encoded.size()));
  };

  g_trace_processor->ExecuteQuery(query, callback);
}

}  // extern "C"

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>ui: make UI use the iterator API of trace processor<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <emscripten/emscripten.h>
#include <map>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/trace_processor.h"

#include "perfetto/trace_processor/raw_query.pb.h"
#include "perfetto/trace_processor/sched.pb.h"

namespace perfetto {
namespace trace_processor {

using RequestID = uint32_t;

// Reply(): replies to a RPC method invocation.
// Called asynchronously (i.e. in a separate task) by the C++ code inside the
// trace processor to return data for a RPC method call.
// The function is generic and thankfully we need just one for all methods
// because the output is always a protobuf buffer.
// Args:
//  RequestID: the ID passed by the embedder when invoking the RPC method (e.g.,
//             the first argument passed to sched_getSchedEvents()).
using ReplyFunction = void (*)(RequestID,
                               bool success,
                               const char* /*proto_reply_data*/,
                               uint32_t /*len*/);

namespace {
TraceProcessor* g_trace_processor;
ReplyFunction g_reply;
}  // namespace
// +---------------------------------------------------------------------------+
// | Exported functions called by the JS/TS running in the worker.             |
// +---------------------------------------------------------------------------+
extern "C" {

void EMSCRIPTEN_KEEPALIVE Initialize(ReplyFunction);
void Initialize(ReplyFunction reply_function) {
  PERFETTO_ILOG("Initializing WASM bridge");
  Config config;
  g_trace_processor = TraceProcessor::CreateInstance(config).release();
  g_reply = reply_function;
}

void EMSCRIPTEN_KEEPALIVE trace_processor_parse(RequestID,
                                                const uint8_t*,
                                                uint32_t);
void trace_processor_parse(RequestID id, const uint8_t* data, size_t size) {
  // TODO(primiano): This copy is extremely unfortunate. Ideally there should be
  // a way to take the Blob coming from JS (either from FileReader or from th
  // fetch() stream) and move into WASM.
  // See https://github.com/WebAssembly/design/issues/1162.
  std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
  memcpy(buf.get(), data, size);
  g_trace_processor->Parse(std::move(buf), size);
  g_reply(id, true, "", 0);
}

// We keep the same signature as other methods even though we don't take input
// arguments for simplicity.
void EMSCRIPTEN_KEEPALIVE trace_processor_notifyEof(RequestID,
                                                    const uint8_t*,
                                                    uint32_t);
void trace_processor_notifyEof(RequestID id, const uint8_t*, uint32_t size) {
  PERFETTO_DCHECK(!size);
  g_trace_processor->NotifyEndOfFile();
  g_reply(id, true, "", 0);
}

void EMSCRIPTEN_KEEPALIVE trace_processor_rawQuery(RequestID,
                                                   const uint8_t*,
                                                   int);
void trace_processor_rawQuery(RequestID id,
                              const uint8_t* query_data,
                              int len) {
  protos::RawQueryArgs query;
  bool parsed = query.ParseFromArray(query_data, len);
  if (!parsed) {
    std::string err = "Failed to parse input request";
    g_reply(id, false, err.data(), err.size());
    return;
  }

  using ColumnDesc = protos::RawQueryResult::ColumnDesc;
  protos::RawQueryResult result;
  auto it = g_trace_processor->ExecuteQuery(query.sql_query().c_str());
  for (uint32_t col = 0; col < it.ColumnCount(); ++col) {
    // Setup the descriptors.
    auto* descriptor = result.add_column_descriptors();
    descriptor->set_name(it.GetColumName(col));
    descriptor->set_type(ColumnDesc::UNKNOWN);

    // Add an empty column.
    result.add_columns();
  }

  for (uint32_t rows = 0; it.Next(); ++rows) {
    for (uint32_t col = 0; col < it.ColumnCount(); ++col) {
      auto* column = result.mutable_columns(static_cast<int>(col));
      auto* desc = result.mutable_column_descriptors(static_cast<int>(col));

      using SqlValue = trace_processor::SqlValue;
      auto cell = it.Get(col);
      if (desc->type() == ColumnDesc::UNKNOWN) {
        switch (cell.type) {
          case SqlValue::Type::kLong:
            desc->set_type(ColumnDesc::LONG);
            break;
          case SqlValue::Type::kString:
            desc->set_type(ColumnDesc::STRING);
            break;
          case SqlValue::Type::kDouble:
            desc->set_type(ColumnDesc::DOUBLE);
            break;
          case SqlValue::Type::kNull:
            break;
        }
      }

      // If either the column type is null or we still don't know the type,
      // just add null values to all the columns.
      if (cell.type == SqlValue::Type::kNull ||
          desc->type() == ColumnDesc::UNKNOWN) {
        column->add_long_values(0);
        column->add_string_values("[NULL]");
        column->add_double_values(0);
        column->add_is_nulls(true);
        continue;
      }

      // Cast the sqlite value to the type of the column.
      switch (desc->type()) {
        case ColumnDesc::LONG:
          PERFETTO_CHECK(cell.type == SqlValue::Type::kLong ||
                         cell.type == SqlValue::Type::kDouble);
          if (cell.type == SqlValue::Type::kLong) {
            column->add_long_values(cell.long_value);
          } else /* if (cell.type == SqlValue::Type::kDouble) */ {
            column->add_long_values(static_cast<int64_t>(cell.double_value));
          }
          column->add_is_nulls(false);
          break;
        case ColumnDesc::STRING: {
          PERFETTO_CHECK(cell.type == SqlValue::Type::kString);
          column->add_string_values(cell.string_value);
          column->add_is_nulls(false);
          break;
        }
        case ColumnDesc::DOUBLE:
          PERFETTO_CHECK(cell.type == SqlValue::Type::kLong ||
                         cell.type == SqlValue::Type::kDouble);
          if (cell.type == SqlValue::Type::kLong) {
            column->add_double_values(static_cast<double>(cell.long_value));
          } else /* if (cell.type == SqlValue::Type::kDouble) */ {
            column->add_double_values(cell.double_value);
          }
          column->add_is_nulls(false);
          break;
        case ColumnDesc::UNKNOWN:
          PERFETTO_FATAL("Handled in if statement above.");
      }
    }
    result.set_num_records(rows + 1);
  }
  if (auto opt_error = it.GetLastError()) {
    result.set_error(*opt_error);
  }

  std::string encoded;
  result.SerializeToString(&encoded);
  g_reply(id, true, encoded.data(), static_cast<uint32_t>(encoded.size()));
}

}  // extern "C"

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before>#ifndef H_EXTENSIONS_CUTEHMI_2_INCLUDE_CUTEHMI_LOGGINGMACROS_HPP
#define H_EXTENSIONS_CUTEHMI_2_INCLUDE_CUTEHMI_LOGGINGMACROS_HPP

#include <QLoggingCategory>

/**
 * @defgroup cutehmi-loggingMacros Logging macros
 *
 * Logging macros. Convenient macros to log messages with Qt logging categories. These macros can be used by other modules
 * providing that they implement loggingCategory() function in their own namespace. This function should return QLoggingCategory
 * object, which is declared and defined with Q_DECLARE_LOGGING_CATEGORY and Q_LOGGING_CATEGORY macros, as described in Qt
 * documentation. Macros are corresponding to Qt debug streams.
 *	- CUTEHMI_DEBUG - debug message (qCDebug()).
 *	- CUTEHMI_INFO - informative message (qCInfo()).
 *	- CUTEHMI_WARNING - informative message (qCWarning()).
 *	- CUTEHMI_CRITICAL - informative message (qCCritical()).
 *	.
 *
 * There's no CUTEHMI_FATAL, because Qt (5.12) does not provide QDebug output stream for fatal errors. Instead CUTEHMI_DIE macro
 * can be used. Unlike the other logging macros CUTEHMI_DIE does not wrap QDebug output stream, so a formatted string should be
 * passed as macro argument (see QMessageLogger::fatal()).
 */
///@{

/**
  @def CUTEHMI_DEBUG(EXPR)
  Print debug message.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NDEBUG
	#define CUTEHMI_DEBUG(EXPR) qCDebug(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_DEBUG(EXPR) (void)0
#endif

/**
  @def CUTEHMI_INFO(EXPR)
  Print informative message.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NINFO
	#define CUTEHMI_INFO(EXPR) qCInfo(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_INFO(EXPR) (void)0
#endif

/**
  @def CUTEHMI_WARNING(EXPR)
  Print warning.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NWARNING
	#define CUTEHMI_WARNING(EXPR) qCWarning(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_WARNING(EXPR) (void)0
#endif

/**
  @def CUTEHMI_CRITICAL(EXPR)
  Print critical message.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NCRITICAL
	#define CUTEHMI_CRITICAL(EXPR) qCCritical(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_CRITICAL(EXPR) (void)0
#endif

/**
  @def CUTEHMI_DIE(...)
  Print fatal message and abort or exit program.
  @param ... fatal message and optional list of arguments interpreted by message format string.
  */
#define CUTEHMI_DIE(...) QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, loggingCategory().categoryName()).fatal(__VA_ARGS__)

/**
  @def CUTEHMI_ASSERT(EXPR, MSG)
  Assert.
  @param EXPR assert expression
  @param MSG message printed in case of assertion failure.
  */
#ifndef CUTEHMI_NDEBUG
	#define CUTEHMI_ASSERT(EXPR, MSG) Q_ASSERT_X(EXPR, __FILE__, MSG)
#else
	#define CUTEHMI_ASSERT(EXPR, MSG) (void)0
#endif

///@}

#endif

//(c)C: Copyright © 2018-2019, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI 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 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI 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.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
<commit_msg>Fix Doxygen brief.<commit_after>#ifndef H_EXTENSIONS_CUTEHMI_2_INCLUDE_CUTEHMI_LOGGINGMACROS_HPP
#define H_EXTENSIONS_CUTEHMI_2_INCLUDE_CUTEHMI_LOGGINGMACROS_HPP

#include <QLoggingCategory>

/**
 * @defgroup cutehmi-loggingMacros Logging macros
 *
 * Logging macros.
 *
 * Convenient macros to log messages with Qt logging categories. These macros can be used by other modules providing that they
 * implement loggingCategory() function in their own namespace. This function should return QLoggingCategory object, which is
 * declared and defined with Q_DECLARE_LOGGING_CATEGORY and Q_LOGGING_CATEGORY macros, as described in Qt documentation. Macros are
 * corresponding to Qt debug streams.
 *	- CUTEHMI_DEBUG - debug message (qCDebug()).
 *	- CUTEHMI_INFO - informative message (qCInfo()).
 *	- CUTEHMI_WARNING - informative message (qCWarning()).
 *	- CUTEHMI_CRITICAL - informative message (qCCritical()).
 *	.
 *
 * There's no CUTEHMI_FATAL, because Qt (5.12) does not provide QDebug output stream for fatal errors. Instead CUTEHMI_DIE macro
 * can be used. Unlike the other logging macros CUTEHMI_DIE does not wrap QDebug output stream, so a formatted string should be
 * passed as macro argument (see QMessageLogger::fatal()).
 */
///@{

/**
  @def CUTEHMI_DEBUG(EXPR)
  Print debug message.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NDEBUG
	#define CUTEHMI_DEBUG(EXPR) qCDebug(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_DEBUG(EXPR) (void)0
#endif

/**
  @def CUTEHMI_INFO(EXPR)
  Print informative message.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NINFO
	#define CUTEHMI_INFO(EXPR) qCInfo(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_INFO(EXPR) (void)0
#endif

/**
  @def CUTEHMI_WARNING(EXPR)
  Print warning.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NWARNING
	#define CUTEHMI_WARNING(EXPR) qCWarning(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_WARNING(EXPR) (void)0
#endif

/**
  @def CUTEHMI_CRITICAL(EXPR)
  Print critical message.
  @param EXPR message (can be composed of stream expression).
  */
#ifndef CUTEHMI_NCRITICAL
	#define CUTEHMI_CRITICAL(EXPR) qCCritical(loggingCategory()).nospace().noquote() << EXPR
#else
	#define CUTEHMI_CRITICAL(EXPR) (void)0
#endif

/**
  @def CUTEHMI_DIE(...)
  Print fatal message and abort or exit program.
  @param ... fatal message and optional list of arguments interpreted by message format string.
  */
#define CUTEHMI_DIE(...) QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, loggingCategory().categoryName()).fatal(__VA_ARGS__)

/**
  @def CUTEHMI_ASSERT(EXPR, MSG)
  Assert.
  @param EXPR assert expression
  @param MSG message printed in case of assertion failure.
  */
#ifndef CUTEHMI_NDEBUG
	#define CUTEHMI_ASSERT(EXPR, MSG) Q_ASSERT_X(EXPR, __FILE__, MSG)
#else
	#define CUTEHMI_ASSERT(EXPR, MSG) (void)0
#endif

///@}

#endif

//(c)C: Copyright © 2018-2019, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI 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 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI 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.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
<|endoftext|>