<commit_before>#include "websock_lib.hh"

unsigned int convert_to_dec(char c) {
	if(c>='0' && c<='9') {
		return c-48;
	} else {
		switch(c) {
			case 'a': return 10;
			case 'b': return 11;
			case 'c': return 12;
			case 'd': return 13;
			case 'e': return 14;
			case 'f': return 15;
		}
	}
	return 16;//error
}

char get_base64_char(unsigned int c) {
	if(c>=0 && c<=25) {
		return c+65;
	} else if(c>=26 && c<=51) {
		return c+71;
	} else if(c>=52 && c<=61) {
		return c-4;
	} else if(c==62) {
		return 43;
	} else if(c==63) {
		return 47;
	} else {
		cerr << "not hex" << endl;
		return -1;
	}
}

string generate_random_base64() {
	string base64;
	int ch;

	for(int i=0;i<22;++i) {
		ch=rand()/(RAND_MAX/64)+1;
		if(ch>=1 && ch<=26) {
			base64+=ch+64;
		} else if(ch>=27 && ch<=52) {
			base64+=ch+70;
		} else if(ch>=53 && ch<=62) {
			base64+=ch-5;
		} else if(ch==63) {
			base64+="+";
		} else {
			base64+="/";
		}
	}
	base64+="==";
	return base64;
}

string base64_encode_sha1(string unencoded) {
	string base;
	unsigned int num=0;
	unsigned int mask=63;

	for(int i=0;i<13;++i) {
		for(int j=0;j<3;++j) {
			num<<=4;
			num+=convert_to_dec(unencoded[0]);
			unencoded.erase(0, 1);
		}
		mask<<=6;
		base+=get_base64_char((num&mask)>>6);
		mask>>=6;
		base+=get_base64_char(num&mask);
		num=0;
	}
	num=convert_to_dec(unencoded[0]);
	num<<=2;
	base+=get_base64_char(num);
	base+='=';
	return base;
}

string get_accept(string websocket_key) {
	const char *GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
	unsigned char* c=new unsigned char[SHA_DIGEST_LENGTH];
	stringstream accept_hex;
	accept_hex.fill('0');
	accept_hex << hex;

	websocket_key+=GUID;
	c=SHA1((unsigned char*)websocket_key.c_str(), websocket_key.size(), NULL);
	for(int i=0;i<20;++i) {
		accept_hex << setw(2) << (unsigned int)c[i];
	}
	return base64_encode_sha1(accept_hex.str());
}

void mask_data(char *frame, unsigned long size) {
	unsigned short index_ch_data=6;
	unsigned short index_ch_mask=2;

	if((frame[1]^(char)254)==0 || (frame[1]^(char)126)==0) {
		index_ch_data=8;
		index_ch_mask=4;
	} else if((frame[1]^(char)255)==0 || (frame[1]^(char)127)==0) {
		index_ch_data=14;
		index_ch_mask=10;
	}

	if(frame[1]&(1<<7)) {
		for(unsigned long i=0;i<size;++i) {
			frame[i+index_ch_data]^=frame[i%4+index_ch_mask];
		}
	}
}

char *create_frame(string data, unsigned long *size) {
	*size=6+data.size();
	short payload=0;
	short mask_index_ch=2;
	if(*size-6>125 && *size-6<65536) {
		*size+=2;
		mask_index_ch+=2;
		payload=1;
	} else if(*size-6>=65536) {
		*size+=8;
		mask_index_ch+=8;
		payload=2;
	}
	char *frame=(char*)malloc((*size+1)*sizeof(char));
	char *data_to_be_masked=(char*)malloc(sizeof(char)*(data.size()+1));
	memset(frame, '\0', *size+1);
	unsigned int mask;

	data_to_be_masked=(char*)data.c_str();
	data_to_be_masked[data.size()]='\0';

	frame[0]|=(1<<7);
	frame[0]|=1;

	if(payload==1) {
		frame[1]|=126;
		unsigned short payload_length=htobe16(data.size());
		memcpy(frame+2, &payload_length, sizeof(unsigned short));
	} else if(payload==2) {
		frame[1]|=127;
		unsigned long payload_long_length=htobe64(data.size());
		memcpy(frame+2, &payload_long_length, sizeof(unsigned long));
	} else {
		unsigned short length=data.size();
		memcpy(frame+1, &length, 1);
	}
	frame[1]|=(1<<7);

	mask=(rand()/(RAND_MAX/2)+1)*(rand());
	memcpy(frame+mask_index_ch, &mask, sizeof(unsigned int));
	memcpy(frame+mask_index_ch+4, data_to_be_masked, strlen(data_to_be_masked));
	mask_data(frame, data.size());

	return frame;
}

string WebSocket::create_opening_handshake(string hostname, string websocket_key) {
	string get;

	get+="GET / HTTP/1.1\r\n";
	get+="Host: "+hostname+"\r\n";
	get+="Upgrade: websocket\r\n";
	get+="Connection: Upgrade\r\n";
	get+="Sec-WebSocket-Key: "+websocket_key+"\r\n";
	get+="Origin: "+hostname+"\r\n";
	get+="Sec-WebSocket-Protocol: chat, superchat\r\n";
	get+="Sec-WebSocket-Version: 13\r\n\r\n";
	return get;
}

bool WebSocket::approve_server_handshake(string handshake, string expected_accept) {
	string delim("\r\n");
	string token;
	size_t pos=0;
	bool http=false, key=false;

	while((pos=handshake.find(delim))!=string::npos) {
		token=handshake.substr(0, pos);
		if(token.find("HTTP/1.1 101")!=string::npos) {
			http=true;
		}

		if(token.find("Sec-WebSocket-Accept")!=string::npos) {
			token.erase(0, 22);
			if(token==expected_accept) {
				key=true;
			}
		}
		handshake.erase(0, pos+delim.length());
	}

	return key && http;
}

WebSocket::WebSocket(short secure)
: secure_(secure) {}

void WebSocket::connect_to(string hostname) {
	struct hostent *h;
	struct sockaddr_in sin;
	string key;
	string get_request;
	const char *cp;
	ssize_t n_written;
	char buf[MAX_ACCEPT];

	h=gethostbyname(hostname.c_str());
	if( (fd=socket(AF_INET, SOCK_STREAM, 0))<0) {
		perror("socket error");
		return;
	}

	sin.sin_family=AF_INET;
	sin.sin_addr=*(struct in_addr*)h->h_addr;
	if(secure_==WEB_WS) {
		sin.sin_port=htons(80);
	} else if(secure_==WEB_WSS) {
		sin.sin_port=htons(443);
	}

	if(connect(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
		perror("connect error");
		return;
	}

	key+=generate_random_base64();
	get_request+=create_opening_handshake(hostname, key);
	cp=get_request.c_str();

	ssize_t remaining=get_request.size();
	while(remaining) {
		if( (n_written=send(fd, cp, remaining, 0))<=0) {
			perror("send");
			close(fd);
			return;
		}
		remaining-=n_written;
		cp+=n_written;
	}

	bool server_receiving=true;
	while(server_receiving) {
		ssize_t result=recv(fd, buf, sizeof(buf), 0);
		if(buf[strlen(buf)-1]=='\n' && buf[strlen(buf)-2]=='\r' && buf[strlen(buf)-3]=='\n' && buf[strlen(buf)-4]=='\r') {
			server_receiving=false;
		}

		if(result<0) {
			perror("recv");
			close(fd);
			return;
		} else if(result==0) {
			break;
		}
	}

	if(approve_server_handshake(buf, get_accept(key))) {
		cout << "connected" << endl;
	} else {
		cout << "connection failed" << endl;
		close(fd);
		exit(-1);
	}
}

void WebSocket::send_text(string data) {
	unsigned long size=0;
	char *frame=create_frame(data, &size);

	write(fd, frame, size);
	free(frame);
}

void WebSocket::receive(char *buf) {
//	read(fd, buf, 10000);
	unsigned short frame_size=2;
	unsigned long data_size=0;
	unsigned short buf_change=0;
	unsigned long remaining=0;

	read(fd, buf, 2);
	buf_change+=2;

	if((buf[1]^254)==0 || (buf[1]^126)==0) {
		read(fd, buf+buf_change, 2);
		buf_change+=2;
		frame_size+=2;
		memcpy(&data_size, buf+2, 2);
		data_size=be16toh(data_size);
	} else if((buf[1]^255)==0 || (buf[1]^127)==0) {
		read(fd, buf+buf_change, 8);
		buf_change+=8;
		frame_size+=8;
		memcpy(&data_size, buf+2, 8);
		data_size=be64toh(data_size);
	} else {
		data_size=buf[1];
	}

	if((buf[1]&(1<<7))) {
		remaining+=4;
		frame_size+=4;
		data_size-128;
	}

	remaining+=data_size;
	unsigned long check;
	while(remaining) {
		check=read(fd, buf+buf_change, remaining);
		remaining-=check;
		buf_change+=check;
	}

	mask_data(buf, data_size);
	memmove(buf, buf+frame_size, data_size);
	buf[data_size]='\0';
}

void WebSocket::disconnect() {
	close(fd);
}<commit_msg>A little change in protocols<commit_after>#include "websock_lib.hh"

unsigned int convert_to_dec(char c) {
	if(c>='0' && c<='9') {
		return c-48;
	} else {
		switch(c) {
			case 'a': return 10;
			case 'b': return 11;
			case 'c': return 12;
			case 'd': return 13;
			case 'e': return 14;
			case 'f': return 15;
		}
	}
	return 16;//error
}

char get_base64_char(unsigned int c) {
	if(c>=0 && c<=25) {
		return c+65;
	} else if(c>=26 && c<=51) {
		return c+71;
	} else if(c>=52 && c<=61) {
		return c-4;
	} else if(c==62) {
		return 43;
	} else if(c==63) {
		return 47;
	} else {
		cerr << "not hex" << endl;
		return -1;
	}
}

string generate_random_base64() {
	string base64;
	int ch;

	for(int i=0;i<22;++i) {
		ch=rand()/(RAND_MAX/64)+1;
		if(ch>=1 && ch<=26) {
			base64+=ch+64;
		} else if(ch>=27 && ch<=52) {
			base64+=ch+70;
		} else if(ch>=53 && ch<=62) {
			base64+=ch-5;
		} else if(ch==63) {
			base64+="+";
		} else {
			base64+="/";
		}
	}
	base64+="==";
	return base64;
}

string base64_encode_sha1(string unencoded) {
	string base;
	unsigned int num=0;
	unsigned int mask=63;

	for(int i=0;i<13;++i) {
		for(int j=0;j<3;++j) {
			num<<=4;
			num+=convert_to_dec(unencoded[0]);
			unencoded.erase(0, 1);
		}
		mask<<=6;
		base+=get_base64_char((num&mask)>>6);
		mask>>=6;
		base+=get_base64_char(num&mask);
		num=0;
	}
	num=convert_to_dec(unencoded[0]);
	num<<=2;
	base+=get_base64_char(num);
	base+='=';
	return base;
}

string get_accept(string websocket_key) {
	const char *GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
	unsigned char* c=new unsigned char[SHA_DIGEST_LENGTH];
	stringstream accept_hex;
	accept_hex.fill('0');
	accept_hex << hex;

	websocket_key+=GUID;
	c=SHA1((unsigned char*)websocket_key.c_str(), websocket_key.size(), NULL);
	for(int i=0;i<20;++i) {
		accept_hex << setw(2) << (unsigned int)c[i];
	}
	return base64_encode_sha1(accept_hex.str());
}

void mask_data(char *frame, unsigned long size) {
	unsigned short index_ch_data=6;
	unsigned short index_ch_mask=2;

	if((frame[1]^(char)254)==0 || (frame[1]^(char)126)==0) {
		index_ch_data=8;
		index_ch_mask=4;
	} else if((frame[1]^(char)255)==0 || (frame[1]^(char)127)==0) {
		index_ch_data=14;
		index_ch_mask=10;
	}

	if(frame[1]&(1<<7)) {
		for(unsigned long i=0;i<size;++i) {
			frame[i+index_ch_data]^=frame[i%4+index_ch_mask];
		}
	}
}

char *create_frame(string data, unsigned long *size) {
	*size=6+data.size();
	short payload=0;
	short mask_index_ch=2;
	if(*size-6>125 && *size-6<65536) {
		*size+=2;
		mask_index_ch+=2;
		payload=1;
	} else if(*size-6>=65536) {
		*size+=8;
		mask_index_ch+=8;
		payload=2;
	}
	char *frame=(char*)malloc((*size+1)*sizeof(char));
	char *data_to_be_masked=(char*)malloc(sizeof(char)*(data.size()+1));
	memset(frame, '\0', *size+1);
	unsigned int mask;

	data_to_be_masked=(char*)data.c_str();
	data_to_be_masked[data.size()]='\0';

	frame[0]|=(1<<7);
	frame[0]|=1;

	if(payload==1) {
		frame[1]|=126;
		unsigned short payload_length=htobe16(data.size());
		memcpy(frame+2, &payload_length, sizeof(unsigned short));
	} else if(payload==2) {
		frame[1]|=127;
		unsigned long payload_long_length=htobe64(data.size());
		memcpy(frame+2, &payload_long_length, sizeof(unsigned long));
	} else {
		unsigned short length=data.size();
		memcpy(frame+1, &length, 1);
	}
	frame[1]|=(1<<7);

	mask=(rand()/(RAND_MAX/2)+1)*(rand());
	memcpy(frame+mask_index_ch, &mask, sizeof(unsigned int));
	memcpy(frame+mask_index_ch+4, data_to_be_masked, strlen(data_to_be_masked));
	mask_data(frame, data.size());

	return frame;
}

string WebSocket::create_opening_handshake(string hostname, string websocket_key) {
	string get;

	get+="GET / HTTP/1.1\r\n";
	get+="Host: "+hostname+"\r\n";
	get+="Upgrade: websocket\r\n";
	get+="Connection: Upgrade\r\n";
	get+="Sec-WebSocket-Key: "+websocket_key+"\r\n";
	get+="Origin: "+hostname+"\r\n";
//	get+="Sec-WebSocket-Protocol: chat\r\n";
	get+="Sec-WebSocket-Version: 13\r\n\r\n";
	return get;
}

bool WebSocket::approve_server_handshake(string handshake, string expected_accept) {
	string delim("\r\n");
	string token;
	size_t pos=0;
	bool http=false, key=false;

	while((pos=handshake.find(delim))!=string::npos) {
		token=handshake.substr(0, pos);
		if(token.find("HTTP/1.1 101")!=string::npos) {
			http=true;
		}

		if(token.find("Sec-WebSocket-Accept")!=string::npos) {
			token.erase(0, 22);
			if(token==expected_accept) {
				key=true;
			}
		}
		handshake.erase(0, pos+delim.length());
	}

	return key && http;
}

WebSocket::WebSocket(short secure)
: secure_(secure) {}

void WebSocket::connect_to(string hostname) {
	struct hostent *h;
	struct sockaddr_in sin;
	string key;
	string get_request;
	const char *cp;
	ssize_t n_written;
	char buf[MAX_ACCEPT];

	h=gethostbyname(hostname.c_str());
	if( (fd=socket(AF_INET, SOCK_STREAM, 0))<0) {
		perror("socket error");
		return;
	}

	sin.sin_family=AF_INET;
	sin.sin_addr=*(struct in_addr*)h->h_addr;
	if(secure_==WEB_WS) {
		sin.sin_port=htons(80);
	} else if(secure_==WEB_WSS) {
		sin.sin_port=htons(443);
	}

	if(connect(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
		perror("connect error");
		return;
	}

	key+=generate_random_base64();
	get_request+=create_opening_handshake(hostname, key);
	cp=get_request.c_str();

	ssize_t remaining=get_request.size();
	while(remaining) {
		if( (n_written=send(fd, cp, remaining, 0))<=0) {
			perror("send");
			close(fd);
			return;
		}
		remaining-=n_written;
		cp+=n_written;
	}

	bool server_receiving=true;
	while(server_receiving) {
		ssize_t result=recv(fd, buf, sizeof(buf), 0);
		if(buf[strlen(buf)-1]=='\n' && buf[strlen(buf)-2]=='\r' && buf[strlen(buf)-3]=='\n' && buf[strlen(buf)-4]=='\r') {
			server_receiving=false;
		}

		if(result<0) {
			perror("recv");
			close(fd);
			return;
		} else if(result==0) {
			break;
		}
	}

	if(approve_server_handshake(buf, get_accept(key))) {
		cout << "connected" << endl;
	} else {
		cout << "connection failed" << endl;
		close(fd);
		exit(-1);
	}
}

void WebSocket::send_text(string data) {
	unsigned long size=0;
	char *frame=create_frame(data, &size);

	write(fd, frame, size);
	free(frame);
}

void WebSocket::receive(char *buf) {
//	read(fd, buf, 10000);
	unsigned short frame_size=2;
	unsigned long data_size=0;
	unsigned short buf_change=0;
	unsigned long remaining=0;

	read(fd, buf, 2);
	buf_change+=2;

	if((buf[1]^254)==0 || (buf[1]^126)==0) {
		read(fd, buf+buf_change, 2);
		buf_change+=2;
		frame_size+=2;
		memcpy(&data_size, buf+2, 2);
		data_size=be16toh(data_size);
	} else if((buf[1]^255)==0 || (buf[1]^127)==0) {
		read(fd, buf+buf_change, 8);
		buf_change+=8;
		frame_size+=8;
		memcpy(&data_size, buf+2, 8);
		data_size=be64toh(data_size);
	} else {
		data_size=buf[1];
	}

	if((buf[1]&(1<<7))) {
		remaining+=4;
		frame_size+=4;
		data_size-128;
	}

	remaining+=data_size;
	unsigned long check;
	while(remaining) {
		check=read(fd, buf+buf_change, remaining);
		remaining-=check;
		buf_change+=check;
	}

	mask_data(buf, data_size);
	memmove(buf, buf+frame_size, data_size);
	buf[data_size]='\0';
}

void WebSocket::disconnect() {
	close(fd);
}
<|endoftext|>


<commit_before>#include <iostream>

#include "libaps.h"
#include "constants.h"
#include <thread>
#include "logger.h"

#include "EthernetControl.h"

using namespace std;

int main ()
{
  cout << "BBN AP2 Test Executable" << endl;

  FILELog::ReportingLevel() = TLogLevel(5);;

  cout << "Testing only EthernetControl" << endl;

  // lookup based on device name
  //string dev("\\Device\\NPF_{F47ACE9E-1961-4A8E-BA14-2564E3764BFA}");

  // lookup based on description
  string dev("Intel(R) 82579LM Gigabit Network Connection");

  EthernetControl *ec = new EthernetControl();

  EthernetControl::set_device_active(dev,true);
  EthernetControl::enumerate();

#if 0
  set_logging_level(5);

  int numDevices = get_numDevices();

  cout << numDevices << " APS device" << (numDevices > 1 ? "s": "")  << " found" << endl;

  if (numDevices < 1)
  	return 0;

  char s[] = "stdout";
  set_log(s);

  cout << "Attempting to initialize libaps" << endl;

  init();

  char serialBuffer[100];

  for (int cnt; cnt < numDevices; cnt++) {
  	get_deviceSerial(cnt, serialBuffer);
  	cout << "Device " << cnt << " serial #: " << serialBuffer << endl;
  }

  int rc;
  rc = connect_by_ID(0);

  cout << "connect_by_ID(0) returned " << rc << endl;

  cout << "Set sample rate " << endl;

  set_sampleRate(0,100);

  cout << "current PLL frequency = " << get_sampleRate(0) << " MHz" << endl;

  cout << "setting trigger source = EXTERNAL" << endl;

  set_trigger_source(0, EXTERNAL);

  cout << "get trigger source returns " << ((get_trigger_source(0) == INTERNAL) ? "INTERNAL" : "EXTERNAL") << endl;

  cout << "setting trigger source = INTERNAL" << endl;

  set_trigger_source(0, INTERNAL);

  cout << "get trigger source returns " << ((get_trigger_source(0) == INTERNAL) ? "INTERNAL" : "EXTERNAL") << endl;

  cout << "get channel(0) enable: " << get_channel_enabled(0,0) << endl;

  cout << "set channel(0) enabled = 1" << endl;

  set_channel_enabled(0,0,true);

  const int wfs = 1000;
  short wf[wfs];
  for (int cnt = 0; cnt < wfs; cnt++)
    wf[cnt] = (cnt < wfs/2) ? 32767 : -32767;

  cout << "loading waveform" << endl;

  set_waveform_int(0, 0, wf, wfs);

  cout << "Running" << endl;

  set_sampleRate(0,50);

  run(0);

  std::this_thread::sleep_for(std::chrono::seconds(10));

  cout << "Stopping" << endl;

  stop(0);

  set_channel_enabled(0,0,false);

  cout << "get channel(0) enable: " << get_channel_enabled(0,0) << endl;

  rc = disconnect_by_ID(0);

  cout << "disconnect_by_ID(0) returned " << rc << endl;
#endif
  return 0;
}<commit_msg>Testing up through init()<commit_after>#include <iostream>

#include "libaps.h"
#include "constants.h"
#include <thread>
#include <string>
#include <algorithm>
#include "logger.h"

#include "EthernetControl.h"

using namespace std;

// command options functions taken from:
// http://stackoverflow.com/questions/865668/parse-command-line-arguments
string getCmdOption(char ** begin, char ** end, const std::string & option)
{
  char ** itr = std::find(begin, end, option);
  if (itr != end && ++itr != end)
  {
    return string(*itr);
  }
  return "";
}

bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
  return std::find(begin, end, option) != end;
}

int main (int argc, char* argv[])
{
  cout << "BBN AP2 Test Executable" << endl;

  FILELog::ReportingLevel() = TLogLevel(5);
  set_logging_level(5);

  // lookup based on device name
  //string dev("\\Device\\NPF_{F47ACE9E-1961-4A8E-BA14-2564E3764BFA}");

  // lookup based on description
  string dev("Intel(R) 82579LM Gigabit Network Connection");

  if (cmdOptionExists(argv, argv + argc, "-e")) {
    EthernetControl::debugAPSEcho(dev);
    return 0;
  }

  set_ethernet_active(const_cast<char*>(dev.c_str()),true);

  int numDevices = get_numDevices();

  cout << numDevices << " APS device" << (numDevices > 1 ? "s": "")  << " found" << endl;

  if (numDevices < 1)
  	return 0;

  cout << "Attempting to initialize libaps" << endl;

  init();

  cout << "Attempting to get serials" << endl;

  char serialBuffer[100];

  for (int cnt; cnt < numDevices; cnt++) {
  	get_deviceSerial(cnt, serialBuffer);
  	cout << "Device " << cnt << " serial #: " << serialBuffer << endl;
  }

#if 0
  int rc;
  rc = connect_by_ID(0);

  cout << "connect_by_ID(0) returned " << rc << endl;

  cout << "Set sample rate " << endl;

  set_sampleRate(0,100);

  cout << "current PLL frequency = " << get_sampleRate(0) << " MHz" << endl;

  cout << "setting trigger source = EXTERNAL" << endl;

  set_trigger_source(0, EXTERNAL);

  cout << "get trigger source returns " << ((get_trigger_source(0) == INTERNAL) ? "INTERNAL" : "EXTERNAL") << endl;

  cout << "setting trigger source = INTERNAL" << endl;

  set_trigger_source(0, INTERNAL);

  cout << "get trigger source returns " << ((get_trigger_source(0) == INTERNAL) ? "INTERNAL" : "EXTERNAL") << endl;

  cout << "get channel(0) enable: " << get_channel_enabled(0,0) << endl;

  cout << "set channel(0) enabled = 1" << endl;

  set_channel_enabled(0,0,true);

  const int wfs = 1000;
  short wf[wfs];
  for (int cnt = 0; cnt < wfs; cnt++)
    wf[cnt] = (cnt < wfs/2) ? 32767 : -32767;

  cout << "loading waveform" << endl;

  set_waveform_int(0, 0, wf, wfs);

  cout << "Running" << endl;

  set_sampleRate(0,50);

  run(0);

  std::this_thread::sleep_for(std::chrono::seconds(10));

  cout << "Stopping" << endl;

  stop(0);

  set_channel_enabled(0,0,false);

  cout << "get channel(0) enable: " << get_channel_enabled(0,0) << endl;

  rc = disconnect_by_ID(0);

  cout << "disconnect_by_ID(0) returned " << rc << endl;
#endif
  return 0;
}<|endoftext|>


<commit_before>/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 * Drizzle Client & Protocol Library
 *
 * Copyright (C) 2008-2013 Drizzle Developer Group
 * Copyright (C) 2008 Eric Day (eday@oddments.org)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *     * The names of its contributors may not be used to endorse or
 * promote products derived from this software without specific prior
 * written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @file
 * @brief Packing definitions
 */

#include "config.h"
#include "libdrizzle/common.h"

/*
 * Private declarations
 */

/**
 * @addtogroup drizzle_pack_private Private Packing Functions
 * @ingroup drizzle_pack
 * @{
 */

/**
 * Compute hash from password and scramble.
 */
static drizzle_return_t _pack_scramble_hash(drizzle_st *con,
                                            unsigned char *buffer);

/** @} */

/*
 * Public definitions
 */

unsigned char *drizzle_pack_length(uint64_t number, unsigned char *ptr)
{
  if (number < 251)
  {
    ptr[0]= (uint8_t)number;
    ptr++;
  }
  else if (number < 65536)
  {
    ptr[0]= 252;
    ptr++;
    drizzle_set_byte2(ptr, number);
    ptr+= 2;
  }
  else if (number < 16777216)
  {
    ptr[0]= 253;
    ptr++;
    drizzle_set_byte3(ptr, number);
    ptr+= 3;
  }
  else
  {
    ptr[0]= 254;
    ptr++;
    drizzle_set_byte8(ptr, number);
    ptr+= 8;
  }

  return ptr;
}

uint64_t drizzle_unpack_length(drizzle_st *con, drizzle_return_t *ret_ptr)
{
  uint64_t length;
  uint8_t bytes;

  drizzle_return_t unused_ret;
  if (ret_ptr == NULL)
  {
    ret_ptr= &unused_ret;
  }

  if (con == NULL)
  {
    *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
    return 0;
  }

  if (con->buffer_ptr[0] < 251)
  {
    length= (uint64_t)(con->buffer_ptr[0]);
    bytes= 1;
  }
  else if (con->buffer_ptr[0] == 251)
  {
    con->buffer_ptr++;
    con->buffer_size--;
    con->packet_size--;

    *ret_ptr= DRIZZLE_RETURN_NULL_SIZE;
    return 0;
  }
  else if (con->buffer_ptr[0] == 252 && con->buffer_size > 2)
  {
    length= drizzle_get_byte2(con->buffer_ptr + 1);
    bytes= 3;
  }
  else if (con->buffer_ptr[0] == 253 && con->buffer_size > 3)
  {
    length= drizzle_get_byte3(con->buffer_ptr + 1);
    bytes= 4;
  }
  else if (con->buffer_size > 8)
  {
    length= drizzle_get_byte8(con->buffer_ptr + 1);
    bytes= 9;
  }
  else
  {
    *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
    return 0;
  }

  con->buffer_ptr+= bytes;
  con->buffer_size-= bytes;
  con->packet_size-= bytes;

  *ret_ptr= DRIZZLE_RETURN_OK;
  return length;
}

unsigned char *drizzle_pack_string(char *string, unsigned char *ptr)
{
  if (string == NULL)
  {
    return NULL;
  }

  size_t size= strlen(string);

  ptr= drizzle_pack_length(size, ptr);
  if (size > 0)
  {
    memcpy(ptr, string, size);
    ptr+= size;
  }

  return ptr;
}

unsigned char *drizzle_pack_binary(unsigned char *data, size_t len, unsigned char *ptr)
{
  ptr= drizzle_pack_length(len, ptr);
  if (len > 0)
  {
    memcpy(ptr, data, len);
    ptr+= len;
  }

  return ptr;
}

unsigned char *drizzle_pack_time(drizzle_datetime_st *time, unsigned char *ptr)
{
  uint8_t length= 0;

  /* NOTE: MySQL has a bug here and doesn't follow this part of the protocol
   * when packing, we will for now, no idea if it works
   * */
  if (time->microsecond)
  {
    drizzle_set_byte4(ptr+9, time->microsecond);
    length= 12;
  }

  if (length || time->day || time->hour || time->minute || time->second)
  {
    ptr[1]= (time->negative) ? 1 : 0;
    drizzle_set_byte4(ptr+2, time->day);
    drizzle_set_byte1(ptr+6, time->hour);
    drizzle_set_byte1(ptr+7, time->minute);
    drizzle_set_byte1(ptr+8, time->second);
    /* If no microseconds, then we are packing 8 bytes */
    if (!length)
      length= 8;
  }

  /* If nothing is set then we are sending a 0 length time */

  drizzle_set_byte1(ptr, length);
  return ptr + 1 + length;
}

unsigned char *drizzle_pack_datetime(drizzle_datetime_st *datetime, unsigned char *ptr)
{
  uint8_t length= 0;

  if (datetime->microsecond)
  {
    drizzle_set_byte4(ptr+8, datetime->microsecond);
    length = 11;
  }

  if (length || datetime->hour || datetime->minute || datetime->second)
  {
    drizzle_set_byte1(ptr+5, datetime->hour);
    drizzle_set_byte1(ptr+6, datetime->minute);
    drizzle_set_byte1(ptr+7, datetime->second);
    /* If only date+time is provided then we are packing 7 bytes */
    if (!length)
      length = 7;
  }

  if (length || datetime->year || datetime->month || datetime->day)
  {
    drizzle_set_byte2(ptr+1, datetime->year);
    drizzle_set_byte1(ptr+3, datetime->month);
    drizzle_set_byte1(ptr+4, datetime->day);
    /* If only date is provided then we are packing 4 bytes */
    if (!length)
      length = 4;
  }

  /* If nothing is set then we are sending a 0 length datetime */

  drizzle_set_byte1(ptr, length);
  return ptr + 1 + length;
}

void drizzle_unpack_time(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime)
{
  memset(datetime, 0, length);

  if (length)
  {
    datetime->negative= field[0];
    datetime->day= drizzle_get_byte4(&field[1]);
    datetime->hour= field[5];
    datetime->hour= datetime->day * 24;
    datetime->day= 0;
    datetime->minute= field[6];
    datetime->second= field[7];
    if (length > 8)
    {
      datetime->microsecond= drizzle_get_byte4(&field[8]);
    }
  }
}

void drizzle_unpack_datetime(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime)
{
  memset(datetime, 0, length);

  if (length)
  {
    datetime->negative= false;
    datetime->year= drizzle_get_byte2(field);
    datetime->month= field[2];
    datetime->day= field[3];
    if (length > 4)
    {
      datetime->hour= field[4];
      datetime->minute= field[5];
      datetime->second= field[6];
      if (length > 7)
      {
        datetime->microsecond= drizzle_get_byte4(&field[7]);
      }
    }
  }
}

drizzle_return_t drizzle_unpack_string(drizzle_st *con, char *buffer,
                                       size_t max_length)
{
  drizzle_return_t ret= DRIZZLE_RETURN_OK;

  if (con == NULL)
  {
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
  }

  uint64_t length= drizzle_unpack_length(con, &ret);
  if (ret != DRIZZLE_RETURN_OK)
  {
    if (ret == DRIZZLE_RETURN_NULL_SIZE)
    {
      drizzle_set_error(con, "drizzle_unpack_string",
                        "unexpected NULL length");
    }

    return ret;
  }

  if (length > con->packet_size)
  {
    drizzle_set_error(con, "drizzle_unpack_string",
                           "string extends past end of packet");
    return DRIZZLE_RETURN_UNEXPECTED_DATA;
  }
  if (length > con->buffer_size)
  {
    return DRIZZLE_RETURN_IO_WAIT;
  }

  assert(max_length > 1);
  if (length < max_length)
  {
    if (length > 0)
      memcpy(buffer, con->buffer_ptr, (size_t)length);

    buffer[length]= 0;
  }
  else
  {
    memcpy(buffer, con->buffer_ptr, max_length - 1);
    buffer[max_length - 1]= 0;
  }

  con->buffer_ptr+= length;
  con->buffer_size-= length;
  con->packet_size-= (uint32_t)length;

  return DRIZZLE_RETURN_OK;
}

unsigned char *drizzle_pack_auth(drizzle_st *con, unsigned char *ptr,
                           drizzle_return_t *ret_ptr)
{
  drizzle_return_t unused_ret;
  if (ret_ptr == NULL)
  {
    ret_ptr= &unused_ret;
  }

  if (con == NULL)
  {
    *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
    return NULL;
  }

  if (con->user[0] != 0)
  {
    memcpy(ptr, con->user, strlen(con->user));
    ptr+= strlen(con->user);
  }

  ptr[0]= 0;
  ptr++;

  if (con->options.raw_scramble && con->scramble != NULL)
  {
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
    ptr++;

    memcpy(ptr, con->scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
  }
  else if (con->password[0] == 0)
  {
    ptr[0]= 0;
    ptr++;
    con->packet_size-= DRIZZLE_MAX_SCRAMBLE_SIZE;
  }
  else
  {
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
    ptr++;

    if (con->options.auth_plugin)
    {
      snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
      ptr[DRIZZLE_MAX_SCRAMBLE_SIZE-1]= 0;
    }
    else
    {
      *ret_ptr= _pack_scramble_hash(con, ptr);
      if (*ret_ptr != DRIZZLE_RETURN_OK)
        return ptr;
    }

    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
  }

  if (con->db[0] != 0)
  {
    memcpy(ptr, con->db, strlen(con->db));
    ptr+= strlen(con->db);
  }

  ptr[0]= 0;
  ptr++;

  *ret_ptr= DRIZZLE_RETURN_OK;
  return ptr;
}

/*
 * Private definitions
 */

static drizzle_return_t _pack_scramble_hash(drizzle_st *con,
                                            unsigned char *buffer)
{
  SHA1_CTX ctx;
  unsigned char hash_tmp1[SHA1_DIGEST_LENGTH];
  unsigned char hash_tmp2[SHA1_DIGEST_LENGTH];

  if (SHA1_DIGEST_LENGTH != DRIZZLE_MAX_SCRAMBLE_SIZE)
  {
    drizzle_set_error(con, "_pack_scramble_hash",
                      "SHA1 hash size mismatch:%u:%u", SHA1_DIGEST_LENGTH,
                      DRIZZLE_MAX_SCRAMBLE_SIZE);
    return DRIZZLE_RETURN_INTERNAL_ERROR;
  }

  if (con->scramble == NULL)
  {
    drizzle_set_error(con, "_pack_scramble_hash",
                      "no scramble buffer");
    return DRIZZLE_RETURN_NO_SCRAMBLE;
  }

  /* First hash the password. */
  SHA1Init(&ctx);
  SHA1Update(&ctx, (unsigned char *)(con->password), strlen(con->password));
  SHA1Final(hash_tmp1, &ctx);

  /* Second, hash the password hash. */
  SHA1Init(&ctx);
  SHA1Update(&ctx, hash_tmp1, SHA1_DIGEST_LENGTH);
  SHA1Final(hash_tmp2, &ctx);

  /* Third, hash the scramble and the double password hash. */
  SHA1Init(&ctx);
  SHA1Update(&ctx, con->scramble, SHA1_DIGEST_LENGTH);
  SHA1Update(&ctx, hash_tmp2, SHA1_DIGEST_LENGTH);
  SHA1Final(buffer, &ctx);

  /* Fourth, xor the last hash against the first password hash. */
  uint32_t x;
  for (x= 0; x < SHA1_DIGEST_LENGTH; x++)
  {
    buffer[x]= buffer[x] ^ hash_tmp1[x];
  }

  return DRIZZLE_RETURN_OK;
}
<commit_msg>Don't leave uninitialized data at the end of datetime_st<commit_after>/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 * Drizzle Client & Protocol Library
 *
 * Copyright (C) 2008-2013 Drizzle Developer Group
 * Copyright (C) 2008 Eric Day (eday@oddments.org)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *     * The names of its contributors may not be used to endorse or
 * promote products derived from this software without specific prior
 * written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @file
 * @brief Packing definitions
 */

#include "config.h"
#include "libdrizzle/common.h"

/*
 * Private declarations
 */

/**
 * @addtogroup drizzle_pack_private Private Packing Functions
 * @ingroup drizzle_pack
 * @{
 */

/**
 * Compute hash from password and scramble.
 */
static drizzle_return_t _pack_scramble_hash(drizzle_st *con,
                                            unsigned char *buffer);

/** @} */

/*
 * Public definitions
 */

unsigned char *drizzle_pack_length(uint64_t number, unsigned char *ptr)
{
  if (number < 251)
  {
    ptr[0]= (uint8_t)number;
    ptr++;
  }
  else if (number < 65536)
  {
    ptr[0]= 252;
    ptr++;
    drizzle_set_byte2(ptr, number);
    ptr+= 2;
  }
  else if (number < 16777216)
  {
    ptr[0]= 253;
    ptr++;
    drizzle_set_byte3(ptr, number);
    ptr+= 3;
  }
  else
  {
    ptr[0]= 254;
    ptr++;
    drizzle_set_byte8(ptr, number);
    ptr+= 8;
  }

  return ptr;
}

uint64_t drizzle_unpack_length(drizzle_st *con, drizzle_return_t *ret_ptr)
{
  uint64_t length;
  uint8_t bytes;

  drizzle_return_t unused_ret;
  if (ret_ptr == NULL)
  {
    ret_ptr= &unused_ret;
  }

  if (con == NULL)
  {
    *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
    return 0;
  }

  if (con->buffer_ptr[0] < 251)
  {
    length= (uint64_t)(con->buffer_ptr[0]);
    bytes= 1;
  }
  else if (con->buffer_ptr[0] == 251)
  {
    con->buffer_ptr++;
    con->buffer_size--;
    con->packet_size--;

    *ret_ptr= DRIZZLE_RETURN_NULL_SIZE;
    return 0;
  }
  else if (con->buffer_ptr[0] == 252 && con->buffer_size > 2)
  {
    length= drizzle_get_byte2(con->buffer_ptr + 1);
    bytes= 3;
  }
  else if (con->buffer_ptr[0] == 253 && con->buffer_size > 3)
  {
    length= drizzle_get_byte3(con->buffer_ptr + 1);
    bytes= 4;
  }
  else if (con->buffer_size > 8)
  {
    length= drizzle_get_byte8(con->buffer_ptr + 1);
    bytes= 9;
  }
  else
  {
    *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
    return 0;
  }

  con->buffer_ptr+= bytes;
  con->buffer_size-= bytes;
  con->packet_size-= bytes;

  *ret_ptr= DRIZZLE_RETURN_OK;
  return length;
}

unsigned char *drizzle_pack_string(char *string, unsigned char *ptr)
{
  if (string == NULL)
  {
    return NULL;
  }

  size_t size= strlen(string);

  ptr= drizzle_pack_length(size, ptr);
  if (size > 0)
  {
    memcpy(ptr, string, size);
    ptr+= size;
  }

  return ptr;
}

unsigned char *drizzle_pack_binary(unsigned char *data, size_t len, unsigned char *ptr)
{
  ptr= drizzle_pack_length(len, ptr);
  if (len > 0)
  {
    memcpy(ptr, data, len);
    ptr+= len;
  }

  return ptr;
}

unsigned char *drizzle_pack_time(drizzle_datetime_st *time, unsigned char *ptr)
{
  uint8_t length= 0;

  /* NOTE: MySQL has a bug here and doesn't follow this part of the protocol
   * when packing, we will for now, no idea if it works
   * */
  if (time->microsecond)
  {
    drizzle_set_byte4(ptr+9, time->microsecond);
    length= 12;
  }

  if (length || time->day || time->hour || time->minute || time->second)
  {
    ptr[1]= (time->negative) ? 1 : 0;
    drizzle_set_byte4(ptr+2, time->day);
    drizzle_set_byte1(ptr+6, time->hour);
    drizzle_set_byte1(ptr+7, time->minute);
    drizzle_set_byte1(ptr+8, time->second);
    /* If no microseconds, then we are packing 8 bytes */
    if (!length)
      length= 8;
  }

  /* If nothing is set then we are sending a 0 length time */

  drizzle_set_byte1(ptr, length);
  return ptr + 1 + length;
}

unsigned char *drizzle_pack_datetime(drizzle_datetime_st *datetime, unsigned char *ptr)
{
  uint8_t length= 0;

  if (datetime->microsecond)
  {
    drizzle_set_byte4(ptr+8, datetime->microsecond);
    length = 11;
  }

  if (length || datetime->hour || datetime->minute || datetime->second)
  {
    drizzle_set_byte1(ptr+5, datetime->hour);
    drizzle_set_byte1(ptr+6, datetime->minute);
    drizzle_set_byte1(ptr+7, datetime->second);
    /* If only date+time is provided then we are packing 7 bytes */
    if (!length)
      length = 7;
  }

  if (length || datetime->year || datetime->month || datetime->day)
  {
    drizzle_set_byte2(ptr+1, datetime->year);
    drizzle_set_byte1(ptr+3, datetime->month);
    drizzle_set_byte1(ptr+4, datetime->day);
    /* If only date is provided then we are packing 4 bytes */
    if (!length)
      length = 4;
  }

  /* If nothing is set then we are sending a 0 length datetime */

  drizzle_set_byte1(ptr, length);
  return ptr + 1 + length;
}

void drizzle_unpack_time(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime)
{
  memset(datetime, 0, sizeof(*datetime));

  if (length)
  {
    datetime->negative= field[0];
    datetime->day= drizzle_get_byte4(&field[1]);
    datetime->hour= field[5];
    datetime->hour= datetime->day * 24;
    datetime->day= 0;
    datetime->minute= field[6];
    datetime->second= field[7];
    if (length > 8)
    {
      datetime->microsecond= drizzle_get_byte4(&field[8]);
    }
  }
}

void drizzle_unpack_datetime(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime)
{
  memset(datetime, 0, sizeof(*datetime));

  if (length)
  {
    datetime->negative= false;
    datetime->year= drizzle_get_byte2(field);
    datetime->month= field[2];
    datetime->day= field[3];
    if (length > 4)
    {
      datetime->hour= field[4];
      datetime->minute= field[5];
      datetime->second= field[6];
      if (length > 7)
      {
        datetime->microsecond= drizzle_get_byte4(&field[7]);
      }
    }
  }
}

drizzle_return_t drizzle_unpack_string(drizzle_st *con, char *buffer,
                                       size_t max_length)
{
  drizzle_return_t ret= DRIZZLE_RETURN_OK;

  if (con == NULL)
  {
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
  }

  uint64_t length= drizzle_unpack_length(con, &ret);
  if (ret != DRIZZLE_RETURN_OK)
  {
    if (ret == DRIZZLE_RETURN_NULL_SIZE)
    {
      drizzle_set_error(con, "drizzle_unpack_string",
                        "unexpected NULL length");
    }

    return ret;
  }

  if (length > con->packet_size)
  {
    drizzle_set_error(con, "drizzle_unpack_string",
                           "string extends past end of packet");
    return DRIZZLE_RETURN_UNEXPECTED_DATA;
  }
  if (length > con->buffer_size)
  {
    return DRIZZLE_RETURN_IO_WAIT;
  }

  assert(max_length > 1);
  if (length < max_length)
  {
    if (length > 0)
      memcpy(buffer, con->buffer_ptr, (size_t)length);

    buffer[length]= 0;
  }
  else
  {
    memcpy(buffer, con->buffer_ptr, max_length - 1);
    buffer[max_length - 1]= 0;
  }

  con->buffer_ptr+= length;
  con->buffer_size-= length;
  con->packet_size-= (uint32_t)length;

  return DRIZZLE_RETURN_OK;
}

unsigned char *drizzle_pack_auth(drizzle_st *con, unsigned char *ptr,
                           drizzle_return_t *ret_ptr)
{
  drizzle_return_t unused_ret;
  if (ret_ptr == NULL)
  {
    ret_ptr= &unused_ret;
  }

  if (con == NULL)
  {
    *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
    return NULL;
  }

  if (con->user[0] != 0)
  {
    memcpy(ptr, con->user, strlen(con->user));
    ptr+= strlen(con->user);
  }

  ptr[0]= 0;
  ptr++;

  if (con->options.raw_scramble && con->scramble != NULL)
  {
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
    ptr++;

    memcpy(ptr, con->scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
  }
  else if (con->password[0] == 0)
  {
    ptr[0]= 0;
    ptr++;
    con->packet_size-= DRIZZLE_MAX_SCRAMBLE_SIZE;
  }
  else
  {
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
    ptr++;

    if (con->options.auth_plugin)
    {
      snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
      ptr[DRIZZLE_MAX_SCRAMBLE_SIZE-1]= 0;
    }
    else
    {
      *ret_ptr= _pack_scramble_hash(con, ptr);
      if (*ret_ptr != DRIZZLE_RETURN_OK)
        return ptr;
    }

    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
  }

  if (con->db[0] != 0)
  {
    memcpy(ptr, con->db, strlen(con->db));
    ptr+= strlen(con->db);
  }

  ptr[0]= 0;
  ptr++;

  *ret_ptr= DRIZZLE_RETURN_OK;
  return ptr;
}

/*
 * Private definitions
 */

static drizzle_return_t _pack_scramble_hash(drizzle_st *con,
                                            unsigned char *buffer)
{
  SHA1_CTX ctx;
  unsigned char hash_tmp1[SHA1_DIGEST_LENGTH];
  unsigned char hash_tmp2[SHA1_DIGEST_LENGTH];

  if (SHA1_DIGEST_LENGTH != DRIZZLE_MAX_SCRAMBLE_SIZE)
  {
    drizzle_set_error(con, "_pack_scramble_hash",
                      "SHA1 hash size mismatch:%u:%u", SHA1_DIGEST_LENGTH,
                      DRIZZLE_MAX_SCRAMBLE_SIZE);
    return DRIZZLE_RETURN_INTERNAL_ERROR;
  }

  if (con->scramble == NULL)
  {
    drizzle_set_error(con, "_pack_scramble_hash",
                      "no scramble buffer");
    return DRIZZLE_RETURN_NO_SCRAMBLE;
  }

  /* First hash the password. */
  SHA1Init(&ctx);
  SHA1Update(&ctx, (unsigned char *)(con->password), strlen(con->password));
  SHA1Final(hash_tmp1, &ctx);

  /* Second, hash the password hash. */
  SHA1Init(&ctx);
  SHA1Update(&ctx, hash_tmp1, SHA1_DIGEST_LENGTH);
  SHA1Final(hash_tmp2, &ctx);

  /* Third, hash the scramble and the double password hash. */
  SHA1Init(&ctx);
  SHA1Update(&ctx, con->scramble, SHA1_DIGEST_LENGTH);
  SHA1Update(&ctx, hash_tmp2, SHA1_DIGEST_LENGTH);
  SHA1Final(buffer, &ctx);

  /* Fourth, xor the last hash against the first password hash. */
  uint32_t x;
  for (x= 0; x < SHA1_DIGEST_LENGTH; x++)
  {
    buffer[x]= buffer[x] ^ hash_tmp1[x];
  }

  return DRIZZLE_RETURN_OK;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2013 Plenluno All rights reserved.

#include <gtest/gtest.h>
#include <libj/console.h>
#include <libj/detail/gc_base.h>

#ifdef LIBJ_USE_BDWGC
    #include <gc.h>
#endif

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);
    int r = RUN_ALL_TESTS();

#ifdef LIBJ_USE_BDWGC
    libj::Long before;
    libj::Long after;
    do {
        before = LIBJ_DEBUG_OBJECT_COUNT;
        GC_gcollect();
        after = LIBJ_DEBUG_OBJECT_COUNT;
    } while (before > after);
#endif

#ifdef LIBJ_DEBUG
    libj::console::debug(
        "[LIBJ DEBUG] remaining objects: %d",
        LIBJ_DEBUG_OBJECT_COUNT);
#endif

    return r;
}
<commit_msg>fix a build error<commit_after>// Copyright (c) 2012-2013 Plenluno All rights reserved.

#include <gtest/gtest.h>
#include <libj/console.h>
#include <libj/detail/gc_base.h>

#ifdef LIBJ_USE_BDWGC
    #include <gc.h>
#endif

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);
    int r = RUN_ALL_TESTS();

#ifdef LIBJ_DEBUG
# ifdef LIBJ_USE_BDWGC
    libj::Long before;
    libj::Long after;
    do {
        before = LIBJ_DEBUG_OBJECT_COUNT;
        GC_gcollect();
        after = LIBJ_DEBUG_OBJECT_COUNT;
    } while (before > after);
# endif
    libj::console::debug(
        "[LIBJ DEBUG] remaining objects: %d",
        LIBJ_DEBUG_OBJECT_COUNT);
#endif

    return r;
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <time.h>
#include <string.h>
using namespace std;

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Value_Slider.H>
#include <FL/Fl_File_Chooser.H>
#include "Fl_Rotated_Text/Fl_Rotated_Text.H"
#include "cartesian/Cartesian.H"

#include "cvFltkWidget.hh"
#include "ffmpegInterface.hh"
#include "cameraSource.hh"

extern "C"
{
#include "wormProcessing.h"
}

#define DATA_FRAME_RATE_FPS     (1.0 / 15.0) /* I collect at 15 frames per second */
#define PLAYBACK_FRAME_RATE_FPS 15
#define CIRCLE_RADIUS           50
#define CIRCLE_COLOR            CV_RGB(0xFF, 0, 0)
#define POINTED_CIRCLE_COLOR    CV_RGB(0, 0xFF, 0)

#define FRAME_W       480
#define FRAME_H       480
#define CROP_RECT     cvRect(80, 0, FRAME_W, FRAME_H)
#define WINDOW_W      1000
#define WINDOW_H      (FRAME_H + BUTTON_H + PLOT_H + X_AXIS_HEIGHT + AXIS_EXTRA_SPACE)
#define BUTTON_W      100
#define BUTTON_H      30
#define PLOT_W        (WINDOW_W - (Y_AXIS_WIDTH + AXIS_EXTRA_SPACE))
#define PLOT_H        400
#define X_AXIS_HEIGHT 30
#define Y_AXIS_WIDTH  30
#define ACCUM_W       100
#define ACCUM_H       BUTTON_H

// due to a bug (most likely), the axis aren't drawn completely inside their box. Thus I leave a bit
// of extra space to see the labels
#define AXIS_EXTRA_SPACE 30

#define AM_READING_CAMERA (dynamic_cast<CameraSource*>(source) != NULL)

static FrameSource*  source;
static CvFltkWidget* widgetImage;
static Fl_Button*    goResetButton;
static Ca_Canvas*    plot = NULL;
static Ca_X_Axis*    Xaxis;
static Ca_Y_Axis*    Yaxis;

static Fl_Output* leftAccum;
static Fl_Output* rightAccum;
static double     leftAccumValue  = 0.0;
static double     rightAccumValue = 0.0;

// the analysis could be idle, running, or idle examining data (STOPPED)
static enum { RESET, RUNNING, STOPPED } analysisState;

static int           numPoints;
static Ca_LinePoint* lastLeftPoint       = NULL;
static Ca_LinePoint* lastRightPoint      = NULL;
static CvPoint       leftCircleCenter    = cvPoint(-1, -1);
static CvPoint       rightCircleCenter   = cvPoint(-1, -1);
static CvPoint       pointedCircleCenter = cvPoint(-1, -1);

#define HAVE_LEFT_CIRCLE    (leftCircleCenter .x > 0 && leftCircleCenter .y > 0)
#define HAVE_RIGHT_CIRCLE   (rightCircleCenter.x > 0 && rightCircleCenter.y > 0)
#define HAVE_CIRCLES        (HAVE_LEFT_CIRCLE && HAVE_RIGHT_CIRCLE)
#define HAVE_POINTED_CIRCLE (pointedCircleCenter.x > 0 && pointedCircleCenter.y > 0)

void gotNewFrame(IplImage* buffer, uint64_t timestamp_us __attribute__((unused)))
{
    cvMerge(buffer, buffer, buffer, NULL, *widgetImage);

    const CvMat* result = isolateWorms(buffer);
    cvSetImageCOI(*widgetImage, 1);
    cvCopy(result, *widgetImage);
    cvSetImageCOI(*widgetImage, 0);

    if(HAVE_LEFT_CIRCLE)
        cvCircle(*widgetImage, leftCircleCenter,    CIRCLE_RADIUS, CIRCLE_COLOR, 1, 8);

    if(HAVE_RIGHT_CIRCLE)
        cvCircle(*widgetImage, rightCircleCenter,   CIRCLE_RADIUS, CIRCLE_COLOR, 1, 8);

    if(HAVE_POINTED_CIRCLE)
        cvCircle(*widgetImage, pointedCircleCenter, CIRCLE_RADIUS, POINTED_CIRCLE_COLOR, 1, 8);

    // This critical section is likely larger than it needs to be, but this keeps me safe. The
    // analysis state can change in the FLTK thread, so I err on the side of safety
    Fl::lock();
    {
        if(analysisState == RUNNING)
        {
            double leftOccupancy, rightOccupancy;
            computeWormOccupancy(result, &leftCircleCenter, &rightCircleCenter,
                                 CIRCLE_RADIUS,
                                 &leftOccupancy, &rightOccupancy);

            Yaxis->rescale(CA_WHEN_MAX, fmax(leftOccupancy, rightOccupancy) );

            lastLeftPoint  = new Ca_LinePoint(lastLeftPoint,
                                              numPoints, leftOccupancy,  1,FL_RED,   CA_NO_POINT);
            lastRightPoint = new Ca_LinePoint(lastRightPoint,
                                              numPoints, rightOccupancy, 1,FL_GREEN, CA_NO_POINT);
            Xaxis->maximum(numPoints);
            numPoints++;

            leftAccumValue  += leftOccupancy  / DATA_FRAME_RATE_FPS;
            rightAccumValue += rightOccupancy / DATA_FRAME_RATE_FPS;
            char results[128];
            snprintf(results, sizeof(results), "%.3f", leftAccumValue);
            leftAccum->value(results);
            snprintf(results, sizeof(results), "%.3f", rightAccumValue);
            rightAccum->value(results);
        }

        widgetImage->redrawNewFrame();
    }
    Fl::unlock();
}

static void widgetImageCallback(Fl_Widget* widget __attribute__((unused)), void* cookie __attribute__((unused)))
{
    if(Fl::event() == FL_LEAVE)
    {
        // I want to make sure to never miss this, so I handle it unconditionally
        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        return;
    }

    if(analysisState == RUNNING)
    {
        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        return;
    }

    bool onLeftHalf = (Fl::event_x() - widget->x()) < FRAME_W/2;
    switch(Fl::event())
    {
    case FL_MOVE:
        pointedCircleCenter.x = Fl::event_x() - widget->x();
        pointedCircleCenter.y = Fl::event_y() - widget->y();
        break;

    case FL_LEAVE:
        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        break;

    case FL_PUSH:
        if(onLeftHalf)
        {
            leftCircleCenter.x = Fl::event_x() - widget->x();
            leftCircleCenter.y = Fl::event_y() - widget->y();
        }
        else
        {
            rightCircleCenter.x = Fl::event_x() - widget->x();
            rightCircleCenter.y = Fl::event_y() - widget->y();
        }

        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        break;

    default: ;
    }

    if(HAVE_CIRCLES && analysisState == RESET)
        goResetButton->activate();
}

static void setResetAnalysis(void)
{
    goResetButton->labelfont(FL_HELVETICA_BOLD);
    goResetButton->labelcolor(FL_RED);
    goResetButton->type(FL_TOGGLE_BUTTON);
    goResetButton->label("Analyze");

    numPoints       = 0;
    if(plot) plot->clear();
    lastLeftPoint   = lastRightPoint = NULL;
    leftAccumValue  = 0.0;
    rightAccumValue = 0.0;
    leftAccum ->value("0.0");
    rightAccum->value("0.0");

    analysisState = RESET;
}

static void setRunningAnalysis(void)
{
    goResetButton->labelfont(FL_HELVETICA);
    goResetButton->labelcolor(FL_BLACK);
    goResetButton->type(FL_TOGGLE_BUTTON);
    goResetButton->label("Stop analysis");

    pointedCircleCenter.x = pointedCircleCenter.y = -1;

    analysisState = RUNNING;
}

static void setStoppedAnalysis(void)
{
    goResetButton->labelfont(FL_HELVETICA);
    goResetButton->labelcolor(FL_BLACK);
    goResetButton->type(FL_NORMAL_BUTTON);
    goResetButton->label("Reset analysis data");

    analysisState = STOPPED;
}

static void pressedGoReset(Fl_Widget* widget __attribute__((unused)), void* cookie __attribute__((unused)))
{
    if     (analysisState == RUNNING) setStoppedAnalysis();
    else if(analysisState == STOPPED) setResetAnalysis();
    else                              setRunningAnalysis();
}

int main(int argc, char* argv[])
{
    Fl::lock();
    Fl::visual(FL_RGB);

    // open the first source. If there's an argument, assume it's an input video. Otherwise, try
    // reading a camera
    if(argc >= 2) source = new FFmpegDecoder(argv[1], FRAMESOURCE_GRAYSCALE, false, CROP_RECT);
    else          source = new CameraSource (FRAMESOURCE_GRAYSCALE, false, 0, CROP_RECT);

    if(! *source)
    {
        fprintf(stderr, "couldn't open source\n");
        delete source;
        return 0;
    }

    Fl_Double_Window* window =
        new Fl_Double_Window(WINDOW_W, WINDOW_H, "Wormtracker 3");
    widgetImage = new CvFltkWidget(0, 0, source->w(), source->h(),
                                   WIDGET_COLOR);

    widgetImage->callback(widgetImageCallback);

    goResetButton = new Fl_Button( 0, source->h(), BUTTON_W, BUTTON_H);
    goResetButton->callback(pressedGoReset);
    goResetButton->deactivate();

    plot = new Ca_Canvas( Y_AXIS_WIDTH + AXIS_EXTRA_SPACE, goResetButton->y() + goResetButton->h(), PLOT_W, PLOT_H,
                          "Worm occupancy");
    plot->align(FL_ALIGN_TOP);

    // This is extremely important for some reason. Without it the plots do not refresh property and
    // there're artifacts every time the plot is resized
    plot->box(FL_DOWN_BOX);

    Xaxis = new Ca_X_Axis(plot->x(), plot->y() + plot->h(), plot->w(), X_AXIS_HEIGHT, "Points");
    Xaxis->align(FL_ALIGN_BOTTOM);
    Xaxis->minimum(0);
    Xaxis->maximum(1);
    Xaxis->label_format("%g");
    Xaxis->major_step(10);
    Xaxis->label_step(10);
    Xaxis->axis_color(FL_BLACK);
    Xaxis->axis_align(CA_BOTTOM | CA_LINE);

    Yaxis = new Ca_Y_Axis(AXIS_EXTRA_SPACE, plot->y(), Y_AXIS_WIDTH, plot->h());
    Fl_Rotated_Text YaxisLabel("occupancy ratio", FL_HELVETICA, 14, 0, 1);
    Yaxis->image(&YaxisLabel);
    Yaxis->minimum(0);
    Yaxis->maximum(0.01);
    Yaxis->align(FL_ALIGN_LEFT);
    Yaxis->axis_align(CA_LEFT | CA_LINE);
    Yaxis->axis_color(FL_BLACK);

    leftAccum  = new Fl_Output(widgetImage->x() + widgetImage->w(), widgetImage->y(),
                              ACCUM_W, ACCUM_H, "Left accumulator (occupancy-seconds)");
    rightAccum = new Fl_Output(leftAccum->x(), leftAccum->y() + leftAccum->h(),
                              ACCUM_W, ACCUM_H, "Right accumulator (occupancy-seconds)");
    leftAccum ->align(FL_ALIGN_RIGHT);
    rightAccum->align(FL_ALIGN_RIGHT);
    leftAccum ->labelcolor(FL_RED);
    rightAccum->labelcolor(FL_GREEN);

    window->end();
    window->show();

    processingInit(source->w(), source->h());

    setResetAnalysis();

    // I read the data with a tiny delay. This makes sure that I skip old frames (only an issue if I
    // can't keep up with the data rate), but yet got as fast as I can
    IplImage* buffer = cvCreateImage(cvSize(source->w(), source->h()), IPL_DEPTH_8U, 1);

    // If reading from a stored video file, go as fast as possible
    if(AM_READING_CAMERA) source->startSourceThread(&gotNewFrame, 1e6/DATA_FRAME_RATE_FPS, buffer);
    else                  source->startSourceThread(&gotNewFrame, 0,                       buffer);

    while (Fl::wait())
    {
    }

    Fl::unlock();

    delete source;
    delete window;
    cvReleaseImage(&buffer);

    processingCleanup();
    return 0;
}
<commit_msg>if we're reading from a stored video, but aren't yet running the analysis, go slow<commit_after>#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <time.h>
#include <string.h>
using namespace std;

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Value_Slider.H>
#include <FL/Fl_File_Chooser.H>
#include "Fl_Rotated_Text/Fl_Rotated_Text.H"
#include "cartesian/Cartesian.H"

#include "cvFltkWidget.hh"
#include "ffmpegInterface.hh"
#include "cameraSource.hh"

extern "C"
{
#include "wormProcessing.h"
}

#define DATA_FRAME_RATE_FPS     (1.0 / 15.0) /* I collect at 15 seconds per frame */
#define SETUP_FRAME_RATE_FPS    5
#define CIRCLE_RADIUS           50
#define CIRCLE_COLOR            CV_RGB(0xFF, 0, 0)
#define POINTED_CIRCLE_COLOR    CV_RGB(0, 0xFF, 0)

#define FRAME_W       480
#define FRAME_H       480
#define CROP_RECT     cvRect(80, 0, FRAME_W, FRAME_H)
#define WINDOW_W      1000
#define WINDOW_H      (FRAME_H + BUTTON_H + PLOT_H + X_AXIS_HEIGHT + AXIS_EXTRA_SPACE)
#define BUTTON_W      100
#define BUTTON_H      30
#define PLOT_W        (WINDOW_W - (Y_AXIS_WIDTH + AXIS_EXTRA_SPACE))
#define PLOT_H        400
#define X_AXIS_HEIGHT 30
#define Y_AXIS_WIDTH  30
#define ACCUM_W       100
#define ACCUM_H       BUTTON_H

// due to a bug (most likely), the axis aren't drawn completely inside their box. Thus I leave a bit
// of extra space to see the labels
#define AXIS_EXTRA_SPACE 30

#define AM_READING_CAMERA (dynamic_cast<CameraSource*>(source) != NULL)

static FrameSource*  source;
static CvFltkWidget* widgetImage;
static Fl_Button*    goResetButton;
static Ca_Canvas*    plot = NULL;
static Ca_X_Axis*    Xaxis;
static Ca_Y_Axis*    Yaxis;

static Fl_Output* leftAccum;
static Fl_Output* rightAccum;
static double     leftAccumValue  = 0.0;
static double     rightAccumValue = 0.0;

// the analysis could be idle, running, or idle examining data (STOPPED)
static enum { RESET, RUNNING, STOPPED } analysisState;

static int           numPoints;
static Ca_LinePoint* lastLeftPoint       = NULL;
static Ca_LinePoint* lastRightPoint      = NULL;
static CvPoint       leftCircleCenter    = cvPoint(-1, -1);
static CvPoint       rightCircleCenter   = cvPoint(-1, -1);
static CvPoint       pointedCircleCenter = cvPoint(-1, -1);

#define HAVE_LEFT_CIRCLE    (leftCircleCenter .x > 0 && leftCircleCenter .y > 0)
#define HAVE_RIGHT_CIRCLE   (rightCircleCenter.x > 0 && rightCircleCenter.y > 0)
#define HAVE_CIRCLES        (HAVE_LEFT_CIRCLE && HAVE_RIGHT_CIRCLE)
#define HAVE_POINTED_CIRCLE (pointedCircleCenter.x > 0 && pointedCircleCenter.y > 0)

void gotNewFrame(IplImage* buffer, uint64_t timestamp_us __attribute__((unused)))
{
    cvMerge(buffer, buffer, buffer, NULL, *widgetImage);

    const CvMat* result = isolateWorms(buffer);
    cvSetImageCOI(*widgetImage, 1);
    cvCopy(result, *widgetImage);
    cvSetImageCOI(*widgetImage, 0);

    if(HAVE_LEFT_CIRCLE)
        cvCircle(*widgetImage, leftCircleCenter,    CIRCLE_RADIUS, CIRCLE_COLOR, 1, 8);

    if(HAVE_RIGHT_CIRCLE)
        cvCircle(*widgetImage, rightCircleCenter,   CIRCLE_RADIUS, CIRCLE_COLOR, 1, 8);

    if(HAVE_POINTED_CIRCLE)
        cvCircle(*widgetImage, pointedCircleCenter, CIRCLE_RADIUS, POINTED_CIRCLE_COLOR, 1, 8);

    // This critical section is likely larger than it needs to be, but this keeps me safe. The
    // analysis state can change in the FLTK thread, so I err on the side of safety
    Fl::lock();
    {
        if(analysisState == RUNNING)
        {
            double leftOccupancy, rightOccupancy;
            computeWormOccupancy(result, &leftCircleCenter, &rightCircleCenter,
                                 CIRCLE_RADIUS,
                                 &leftOccupancy, &rightOccupancy);

            Yaxis->rescale(CA_WHEN_MAX, fmax(leftOccupancy, rightOccupancy) );

            lastLeftPoint  = new Ca_LinePoint(lastLeftPoint,
                                              numPoints, leftOccupancy,  1,FL_RED,   CA_NO_POINT);
            lastRightPoint = new Ca_LinePoint(lastRightPoint,
                                              numPoints, rightOccupancy, 1,FL_GREEN, CA_NO_POINT);
            Xaxis->maximum(numPoints);
            numPoints++;

            leftAccumValue  += leftOccupancy  / DATA_FRAME_RATE_FPS;
            rightAccumValue += rightOccupancy / DATA_FRAME_RATE_FPS;
            char results[128];
            snprintf(results, sizeof(results), "%.3f", leftAccumValue);
            leftAccum->value(results);
            snprintf(results, sizeof(results), "%.3f", rightAccumValue);
            rightAccum->value(results);
        }

        widgetImage->redrawNewFrame();
    }

    if(!AM_READING_CAMERA && analysisState != RUNNING)
    {
        Fl::unlock();

        // reading from a video file and not actually running the analysis yet. In this case I
        // rewind back to the beginning and delay, to force a reasonable refresh rate
        source->restartStream();

        struct timespec tv;
        tv.tv_sec  = 0;
        tv.tv_nsec = 1e9 / SETUP_FRAME_RATE_FPS;
        nanosleep(&tv, NULL);
    }
    else
        Fl::unlock();
}

static void widgetImageCallback(Fl_Widget* widget __attribute__((unused)), void* cookie __attribute__((unused)))
{
    if(Fl::event() == FL_LEAVE)
    {
        // I want to make sure to never miss this, so I handle it unconditionally
        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        return;
    }

    if(analysisState == RUNNING)
    {
        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        return;
    }

    bool onLeftHalf = (Fl::event_x() - widget->x()) < FRAME_W/2;
    switch(Fl::event())
    {
    case FL_MOVE:
        pointedCircleCenter.x = Fl::event_x() - widget->x();
        pointedCircleCenter.y = Fl::event_y() - widget->y();
        break;

    case FL_LEAVE:
        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        break;

    case FL_PUSH:
        if(onLeftHalf)
        {
            leftCircleCenter.x = Fl::event_x() - widget->x();
            leftCircleCenter.y = Fl::event_y() - widget->y();
        }
        else
        {
            rightCircleCenter.x = Fl::event_x() - widget->x();
            rightCircleCenter.y = Fl::event_y() - widget->y();
        }

        pointedCircleCenter.x = pointedCircleCenter.y = -1;
        break;

    default: ;
    }

    if(HAVE_CIRCLES && analysisState == RESET)
        goResetButton->activate();
}

static void setResetAnalysis(void)
{
    goResetButton->labelfont(FL_HELVETICA_BOLD);
    goResetButton->labelcolor(FL_RED);
    goResetButton->type(FL_TOGGLE_BUTTON);
    goResetButton->label("Analyze");

    numPoints       = 0;
    if(plot) plot->clear();
    lastLeftPoint   = lastRightPoint = NULL;
    leftAccumValue  = 0.0;
    rightAccumValue = 0.0;
    leftAccum ->value("0.0");
    rightAccum->value("0.0");

    analysisState = RESET;
}

static void setRunningAnalysis(void)
{
    goResetButton->labelfont(FL_HELVETICA);
    goResetButton->labelcolor(FL_BLACK);
    goResetButton->type(FL_TOGGLE_BUTTON);
    goResetButton->label("Stop analysis");

    pointedCircleCenter.x = pointedCircleCenter.y = -1;

    analysisState = RUNNING;
}

static void setStoppedAnalysis(void)
{
    goResetButton->labelfont(FL_HELVETICA);
    goResetButton->labelcolor(FL_BLACK);
    goResetButton->type(FL_NORMAL_BUTTON);
    goResetButton->label("Reset analysis data");

    analysisState = STOPPED;
}

static void pressedGoReset(Fl_Widget* widget __attribute__((unused)), void* cookie __attribute__((unused)))
{
    if     (analysisState == RUNNING) setStoppedAnalysis();
    else if(analysisState == STOPPED) setResetAnalysis();
    else                              setRunningAnalysis();
}

int main(int argc, char* argv[])
{
    Fl::lock();
    Fl::visual(FL_RGB);

    // open the first source. If there's an argument, assume it's an input video. Otherwise, try
    // reading a camera
    if(argc >= 2) source = new FFmpegDecoder(argv[1], FRAMESOURCE_GRAYSCALE, false, CROP_RECT);
    else          source = new CameraSource (FRAMESOURCE_GRAYSCALE, false, 0, CROP_RECT);

    if(! *source)
    {
        fprintf(stderr, "couldn't open source\n");
        delete source;
        return 0;
    }

    Fl_Double_Window* window =
        new Fl_Double_Window(WINDOW_W, WINDOW_H, "Wormtracker 3");
    widgetImage = new CvFltkWidget(0, 0, source->w(), source->h(),
                                   WIDGET_COLOR);

    widgetImage->callback(widgetImageCallback);

    goResetButton = new Fl_Button( 0, source->h(), BUTTON_W, BUTTON_H);
    goResetButton->callback(pressedGoReset);
    goResetButton->deactivate();

    plot = new Ca_Canvas( Y_AXIS_WIDTH + AXIS_EXTRA_SPACE, goResetButton->y() + goResetButton->h(), PLOT_W, PLOT_H,
                          "Worm occupancy");
    plot->align(FL_ALIGN_TOP);

    // This is extremely important for some reason. Without it the plots do not refresh property and
    // there're artifacts every time the plot is resized
    plot->box(FL_DOWN_BOX);

    Xaxis = new Ca_X_Axis(plot->x(), plot->y() + plot->h(), plot->w(), X_AXIS_HEIGHT, "Points");
    Xaxis->align(FL_ALIGN_BOTTOM);
    Xaxis->minimum(0);
    Xaxis->maximum(1);
    Xaxis->label_format("%g");
    Xaxis->major_step(10);
    Xaxis->label_step(10);
    Xaxis->axis_color(FL_BLACK);
    Xaxis->axis_align(CA_BOTTOM | CA_LINE);

    Yaxis = new Ca_Y_Axis(AXIS_EXTRA_SPACE, plot->y(), Y_AXIS_WIDTH, plot->h());
    Fl_Rotated_Text YaxisLabel("occupancy ratio", FL_HELVETICA, 14, 0, 1);
    Yaxis->image(&YaxisLabel);
    Yaxis->minimum(0);
    Yaxis->maximum(0.01);
    Yaxis->align(FL_ALIGN_LEFT);
    Yaxis->axis_align(CA_LEFT | CA_LINE);
    Yaxis->axis_color(FL_BLACK);

    leftAccum  = new Fl_Output(widgetImage->x() + widgetImage->w(), widgetImage->y(),
                              ACCUM_W, ACCUM_H, "Left accumulator (occupancy-seconds)");
    rightAccum = new Fl_Output(leftAccum->x(), leftAccum->y() + leftAccum->h(),
                              ACCUM_W, ACCUM_H, "Right accumulator (occupancy-seconds)");
    leftAccum ->align(FL_ALIGN_RIGHT);
    rightAccum->align(FL_ALIGN_RIGHT);
    leftAccum ->labelcolor(FL_RED);
    rightAccum->labelcolor(FL_GREEN);

    window->end();
    window->show();

    processingInit(source->w(), source->h());

    setResetAnalysis();

    // I read the data with a tiny delay. This makes sure that I skip old frames (only an issue if I
    // can't keep up with the data rate), but yet got as fast as I can
    IplImage* buffer = cvCreateImage(cvSize(source->w(), source->h()), IPL_DEPTH_8U, 1);

    // If reading from a stored video file, go as fast as possible
    if(AM_READING_CAMERA) source->startSourceThread(&gotNewFrame, 1e6/DATA_FRAME_RATE_FPS, buffer);
    else                  source->startSourceThread(&gotNewFrame, 0,                       buffer);

    while (Fl::wait())
    {
    }

    Fl::unlock();

    delete source;
    delete window;
    cvReleaseImage(&buffer);

    processingCleanup();
    return 0;
}
<|endoftext|>


<commit_before>/*

  Copyright 2009 University of Helsinki

  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.

*/

/*
  This is a toy commandline utility for testing spellers on standard io.
 */

#if HAVE_CONFIG_H
#  include <config.h>
#endif
#if HAVE_GETOPT_H
#  include <getopt.h>
#endif

#ifdef WINDOWS
#  include <windows.h>
#endif

#include <cstdarg>
#include <stdio.h>
#include <errno.h>

#include "ol-exceptions.h"
#include "ospell.h"
#include "ZHfstOspeller.h"

using hfst_ol::ZHfstOspeller;
using hfst_ol::Transducer;

static bool quiet = false;
static bool verbose = false;
static bool analyse = false;
static unsigned long suggs = 0;
static hfst_ol::Weight max_weight = -1.0;
#ifdef WINDOWS
  static bool output_to_console = false;
#endif
static bool suggest = false;
static bool suggest_reals = false;

#ifdef WINDOWS
static std::string wide_string_to_string(const std::wstring & wstr)
{
  int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)§wstr.size(), NULL, 0, NULL, NULL);
  std::string str( size_needed, 0 );
  WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], size_needed, NULL, NULL);
  return str;
}
#endif

static int hfst_fprintf(FILE * stream, const char * format, ...)
{
  va_list args;
  va_start(args, format);
#ifdef WINDOWS
  if (output_to_console && (stream == stdout || stream == stderr))
    {
      char buffer [1024];
      int r = vsprintf(buffer, format, args);
      va_end(args);
      if (r < 0)
        return r;
      HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
      if (stream == stderr)
        stdHandle = GetStdHandle(STD_ERROR_HANDLE);

      std::string pstr(buffer);
      DWORD numWritten = 0;
        int wchars_num =
          MultiByteToWideChar(CP_UTF8 , 0 , pstr.c_str() , -1, NULL , 0 );
        wchar_t* wstr = new wchar_t[wchars_num];
        MultiByteToWideChar(CP_UTF8 , 0 ,
                            pstr.c_str() , -1, wstr , wchars_num );
        int retval = WriteConsoleW(stdHandle, wstr, wchars_num-1, &numWritten, NULL);
        delete[] wstr;

        return retval;
    }
  else
    {
      int retval = vfprintf(stream, format, args);
      va_end(args);
      return retval;
    }
#else
  errno = 0;
  int retval = vfprintf(stream, format, args);
  if (retval < 0)
    {
      perror("hfst_fprintf");
    }
  va_end(args);
  return retval;
#endif
}

bool print_usage(void)
{
    std::cout <<
    "\n" <<
    "Usage: " << PACKAGE_NAME << " [OPTIONS] ZHFST-ARCHIVE\n" <<
    "Use automata in ZHFST-ARCHIVE to check and correct\n"
    "\n" <<
    "  -h, --help                  Print this help message\n" <<
    "  -V, --version               Print version information\n" <<
    "  -v, --verbose               Be verbose\n" <<
    "  -q, --quiet                 Don't be verbose (default)\n" <<
    "  -s, --silent                Same as quiet\n" <<
    "  -a, --analyse               Analyse strings and corrections\n" <<
    "  -n, --limit=N               Show at most N suggestions\n" <<
    "  -w, --max_weight=W          Suppress corrections with weights above W\n" <<
    "  -S, --suggest               Suggest corrections to mispellings\n" <<
    "  -X, --real-word             Also suggest corrections to correct words\n" <<
#ifdef WINDOWS
    "  -k, --output-to-console     Print output to console (Windows-specific)" <<
#endif
    "\n" <<
    "\n" <<
    "Report bugs to " << PACKAGE_BUGREPORT << "\n" <<
    "\n";
    return true;
}

bool print_version(void)
{
    std::cout <<
    "\n" <<
    PACKAGE_STRING << std::endl <<
    __DATE__ << " " __TIME__ << std::endl <<
    "copyright (C) 2009 - 2014 University of Helsinki\n";
    return true;
}

bool print_short_help(void)
{
    print_usage();
    return true;
}

void
do_suggest(ZHfstOspeller& speller, const std::string& str)
  {
    hfst_ol::CorrectionQueue corrections = speller.suggest(str);
    if (corrections.size() > 0)
      {
        hfst_fprintf(stdout, "Corrections for \"%s\":\n", str.c_str());
        while (corrections.size() > 0)
          {
            const std::string& corr = corrections.top().first;
            if (analyse)
              {
                hfst_ol::AnalysisQueue anals = speller.analyse(corr, true);
                bool all_discarded = true;
                while (anals.size() > 0)
                  {
                    if (anals.top().first.find("Use/SpellNoSugg") !=
                        std::string::npos)
                      {
                        hfst_fprintf(stdout, "%s    %f    %s    "
                                       "[DISCARDED BY ANALYSES]\n",
                                       corr.c_str(), corrections.top().second,
                                       anals.top().first.c_str());
                      }
                    else
                      {
                        all_discarded = false;
                        hfst_fprintf(stdout, "%s    %f    %s\n",
                                       corr.c_str(), corrections.top().second,
                                       anals.top().first.c_str());
                      }
                    anals.pop();
                  }
                if (all_discarded)
                  {
                    hfst_fprintf(stdout, "All corrections were "
                                       "invalidated by analysis! "
                                       "No score!\n");
                  }
              }
            else
              {
                hfst_fprintf(stdout, "%s    %f\n",
                                   corr.c_str(),
                                   corrections.top().second);
              }
            corrections.pop();
          }
        hfst_fprintf(stdout, "\n");
      }
    else
      {
        hfst_fprintf(stdout,
                           "Unable to correct \"%s\"!\n\n", str.c_str());
      }

  }

void
do_spell(ZHfstOspeller& speller, const std::string& str)
  {
    if (speller.spell(str))
      {
        hfst_fprintf(stdout, "\"%s\" is in the lexicon...\n",
                           str.c_str());
        if (analyse)
          {
            hfst_fprintf(stdout, "analysing:\n");
            hfst_ol::AnalysisQueue anals = speller.analyse(str, false);
            bool all_no_spell = true;
            while (anals.size() > 0)
              {
                if (anals.top().first.find("Use/-Spell") != std::string::npos)
                  {
                    hfst_fprintf(stdout,
                                       "%s   %f [DISCARDED AS -Spell]\n",
                                       anals.top().first.c_str(),
                                       anals.top().second);
                  }
                else
                  {
                    all_no_spell = false;
                    hfst_fprintf(stdout, "%s   %f\n",
                                   anals.top().first.c_str(),
                                   anals.top().second);
                  }
                anals.pop();
              }
            if (all_no_spell)
              {
                hfst_fprintf(stdout,
                             "All spellings were invalidated by analysis! "
                             ".:. Not in lexicon!\n");
              }
          }
        if (suggest_reals)
          {
            hfst_fprintf(stdout, "(but correcting anyways)\n", str.c_str());
            do_suggest(speller, str);
          }
      }
    else
      {
        hfst_fprintf(stdout, "\"%s\" is NOT in the lexicon:\n",
                           str.c_str());
        if (suggest)
          {
            do_suggest(speller, str);
          }
      }
  }

int
zhfst_spell(char* zhfst_filename)
{
  ZHfstOspeller speller;
  try
    {
      speller.read_zhfst(zhfst_filename);
    }
  catch (hfst_ol::ZHfstMetaDataParsingError zhmdpe)
    {
      hfst_fprintf(stderr, "cannot finish reading zhfst archive %s:\n%s.\n",
                         zhfst_filename, zhmdpe.what());
      //std::cerr << "cannot finish reading zhfst archive " << zhfst_filename <<
      //             ":\n" << zhmdpe.what() << "." << std::endl;
      return EXIT_FAILURE;
    }
  catch (hfst_ol::ZHfstZipReadingError zhzre)
    {
      //std::cerr << "cannot read zhfst archive " << zhfst_filename << ":\n"
      //    << zhzre.what() << "." << std::endl
      //    << "trying to read as legacy automata directory" << std::endl;
      hfst_fprintf(stderr,
                         "cannot read zhfst archive %s:\n"
                         "%s.\n",
                         zhfst_filename, zhzre.what());
      return EXIT_FAILURE;
    }
  catch (hfst_ol::ZHfstXmlParsingError zhxpe)
    {
      //std::cerr << "Cannot finish reading index.xml from "
      //  << zhfst_filename << ":" << std::endl
      //  << zhxpe.what() << "." << std::endl;
      hfst_fprintf(stderr,
                         "Cannot finish reading index.xml from %s:\n"
                         "%s.\n",
                         zhfst_filename, zhxpe.what());
      return EXIT_FAILURE;
    }
  if (verbose)
    {
      //std::cout << "Following metadata was read from ZHFST archive:" << std::endl
      //          << speller.metadata_dump() << std::endl;
      hfst_fprintf(stdout,
                         "Following metadata was read from ZHFST archive:\n"
                         "%s\n",
                         speller.metadata_dump().c_str());
    }
  speller.set_queue_limit(suggs);
  if (suggs != 0 && verbose)
    {
      hfst_fprintf(stdout, "Printing only %lu top suggestions per line\n", suggs);
    }
  speller.set_weight_limit(max_weight);
  if (max_weight >= 0.0 && verbose)
  {
      hfst_fprintf(stdout, "Not printing suggestions worse than %f\n", suggs);
  }
  char * str = (char*) malloc(2000);

#ifdef WINDOWS
    SetConsoleCP(65001);
    const HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
    WCHAR buffer[0x1000];
    DWORD numRead = 0;
    while (ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL))
      {
        std::wstring wstr(buffer, numRead-1); // skip the newline
        std::string linestr = wide_string_to_string(wstr);
        free(str);
        str = strdup(linestr.c_str());
#else
    while (!std::cin.eof()) {
        std::cin.getline(str, 2000);
#endif
        if (str[0] == '\0') {
            continue;
        }
        if (str[strlen(str) - 1] == '\r')
          {
#ifdef WINDOWS
            str[strlen(str) - 1] = '\0';
#else
            hfst_fprintf(stderr, "There is a WINDOWS linebreak in this file\n"
                               "Please convert with dos2unix or fromdos\n");
            exit(1);
#endif
          }
        do_spell(speller, str);
      }
    free(str);
    return EXIT_SUCCESS;
}

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

    int c;
    //std::locale::global(std::locale(""));

#if HAVE_GETOPT_H
    while (true) {
        static struct option long_options[] =
            {
            // first the hfst-mandated options
            {"help",         no_argument,       0, 'h'},
            {"version",      no_argument,       0, 'V'},
            {"verbose",      no_argument,       0, 'v'},
            {"quiet",        no_argument,       0, 'q'},
            {"silent",       no_argument,       0, 's'},
            {"analyse",      no_argument,       0, 'a'},
            {"limit",  required_argument,       0, 'n'},
            {"max_weight", required_argument,   0, 'w'},
            {"suggest",      no_argument,       0, 'S'},
            {"real-word",    no_argument,       0, 'X'},
#ifdef WINDOWS
            {"output-to-console",       no_argument,       0, 'k'},
#endif
            {0,              0,                 0,  0 }
            };

        int option_index = 0;
        c = getopt_long(argc, argv, "hVvqskaSnw:", long_options, &option_index);
        char* endptr = 0;

        if (c == -1) // no more options to look at
            break;

        switch (c) {
        case 'h':
            print_usage();
            return EXIT_SUCCESS;
            break;

        case 'V':
            print_version();
            return EXIT_SUCCESS;
            break;

        case 'v':
            verbose = true;
            quiet = false;
            break;

        case 'q': // fallthrough
        case 's':
            quiet = true;
            verbose = false;
            break;
        case 'a':
            analyse = true;
            break;
        case 'n':
            suggs = strtoul(optarg, &endptr, 10);
            if (endptr == optarg)
              {
                fprintf(stderr, "%s not a strtoul number\n", optarg);
                exit(1);
              }
            else if (*endptr != '\0')
              {
                fprintf(stderr, "%s truncated from limit parameter\n", endptr);
              }
            break;
        case 'w':
            max_weight = strtof(optarg, &endptr);
            if (endptr == optarg)
            {
                fprintf(stderr, "%s is not a float\n", optarg);
                exit(1);
              }
            else if (*endptr != '\0')
              {
                fprintf(stderr, "%s truncated from limit parameter\n", endptr);
              }

            break;
#ifdef WINDOWS
        case 'k':
            output_to_console = true;
            break;
#endif
        case 'S':
            suggest = true;
            break;
        case 'X':
            suggest_reals = true;
            break;
        default:
            std::cerr << "Invalid option\n\n";
            print_short_help();
            return EXIT_FAILURE;
            break;
        }
    }
#else
    int optind = 1;
#endif
    // no more options, we should now be at the input filenames
    if (optind == (argc - 1))
      {
        return zhfst_spell(argv[optind]);
      }
    else if (optind < (argc - 1))
      {
        std::cerr << "Too many file parameters" << std::endl;
        print_short_help();
        return EXIT_FAILURE;
      }
    else if (optind >= argc)
      {
        std::cerr << "Give full path to a zhfst speller"
            << std::endl;
        print_short_help();
        return EXIT_FAILURE;
      }
    return EXIT_SUCCESS;
  }
<commit_msg>Change max_weight to max-weight in the help string and argument name <commit_after>/*

  Copyright 2009 University of Helsinki

  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.

*/

/*
  This is a toy commandline utility for testing spellers on standard io.
 */

#if HAVE_CONFIG_H
#  include <config.h>
#endif
#if HAVE_GETOPT_H
#  include <getopt.h>
#endif

#ifdef WINDOWS
#  include <windows.h>
#endif

#include <cstdarg>
#include <stdio.h>
#include <errno.h>

#include "ol-exceptions.h"
#include "ospell.h"
#include "ZHfstOspeller.h"

using hfst_ol::ZHfstOspeller;
using hfst_ol::Transducer;

static bool quiet = false;
static bool verbose = false;
static bool analyse = false;
static unsigned long suggs = 0;
static hfst_ol::Weight max_weight = -1.0;
#ifdef WINDOWS
  static bool output_to_console = false;
#endif
static bool suggest = false;
static bool suggest_reals = false;

#ifdef WINDOWS
static std::string wide_string_to_string(const std::wstring & wstr)
{
  int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)§wstr.size(), NULL, 0, NULL, NULL);
  std::string str( size_needed, 0 );
  WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], size_needed, NULL, NULL);
  return str;
}
#endif

static int hfst_fprintf(FILE * stream, const char * format, ...)
{
  va_list args;
  va_start(args, format);
#ifdef WINDOWS
  if (output_to_console && (stream == stdout || stream == stderr))
    {
      char buffer [1024];
      int r = vsprintf(buffer, format, args);
      va_end(args);
      if (r < 0)
        return r;
      HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
      if (stream == stderr)
        stdHandle = GetStdHandle(STD_ERROR_HANDLE);

      std::string pstr(buffer);
      DWORD numWritten = 0;
        int wchars_num =
          MultiByteToWideChar(CP_UTF8 , 0 , pstr.c_str() , -1, NULL , 0 );
        wchar_t* wstr = new wchar_t[wchars_num];
        MultiByteToWideChar(CP_UTF8 , 0 ,
                            pstr.c_str() , -1, wstr , wchars_num );
        int retval = WriteConsoleW(stdHandle, wstr, wchars_num-1, &numWritten, NULL);
        delete[] wstr;

        return retval;
    }
  else
    {
      int retval = vfprintf(stream, format, args);
      va_end(args);
      return retval;
    }
#else
  errno = 0;
  int retval = vfprintf(stream, format, args);
  if (retval < 0)
    {
      perror("hfst_fprintf");
    }
  va_end(args);
  return retval;
#endif
}

bool print_usage(void)
{
    std::cout <<
    "\n" <<
    "Usage: " << PACKAGE_NAME << " [OPTIONS] ZHFST-ARCHIVE\n" <<
    "Use automata in ZHFST-ARCHIVE to check and correct\n"
    "\n" <<
    "  -h, --help                  Print this help message\n" <<
    "  -V, --version               Print version information\n" <<
    "  -v, --verbose               Be verbose\n" <<
    "  -q, --quiet                 Don't be verbose (default)\n" <<
    "  -s, --silent                Same as quiet\n" <<
    "  -a, --analyse               Analyse strings and corrections\n" <<
    "  -n, --limit=N               Show at most N suggestions\n" <<
    "  -w, --max-weight=W          Suppress corrections with weights above W\n" <<
    "  -S, --suggest               Suggest corrections to mispellings\n" <<
    "  -X, --real-word             Also suggest corrections to correct words\n" <<
#ifdef WINDOWS
    "  -k, --output-to-console     Print output to console (Windows-specific)" <<
#endif
    "\n" <<
    "\n" <<
    "Report bugs to " << PACKAGE_BUGREPORT << "\n" <<
    "\n";
    return true;
}

bool print_version(void)
{
    std::cout <<
    "\n" <<
    PACKAGE_STRING << std::endl <<
    __DATE__ << " " __TIME__ << std::endl <<
    "copyright (C) 2009 - 2014 University of Helsinki\n";
    return true;
}

bool print_short_help(void)
{
    print_usage();
    return true;
}

void
do_suggest(ZHfstOspeller& speller, const std::string& str)
  {
    hfst_ol::CorrectionQueue corrections = speller.suggest(str);
    if (corrections.size() > 0)
      {
        hfst_fprintf(stdout, "Corrections for \"%s\":\n", str.c_str());
        while (corrections.size() > 0)
          {
            const std::string& corr = corrections.top().first;
            if (analyse)
              {
                hfst_ol::AnalysisQueue anals = speller.analyse(corr, true);
                bool all_discarded = true;
                while (anals.size() > 0)
                  {
                    if (anals.top().first.find("Use/SpellNoSugg") !=
                        std::string::npos)
                      {
                        hfst_fprintf(stdout, "%s    %f    %s    "
                                       "[DISCARDED BY ANALYSES]\n",
                                       corr.c_str(), corrections.top().second,
                                       anals.top().first.c_str());
                      }
                    else
                      {
                        all_discarded = false;
                        hfst_fprintf(stdout, "%s    %f    %s\n",
                                       corr.c_str(), corrections.top().second,
                                       anals.top().first.c_str());
                      }
                    anals.pop();
                  }
                if (all_discarded)
                  {
                    hfst_fprintf(stdout, "All corrections were "
                                       "invalidated by analysis! "
                                       "No score!\n");
                  }
              }
            else
              {
                hfst_fprintf(stdout, "%s    %f\n",
                                   corr.c_str(),
                                   corrections.top().second);
              }
            corrections.pop();
          }
        hfst_fprintf(stdout, "\n");
      }
    else
      {
        hfst_fprintf(stdout,
                           "Unable to correct \"%s\"!\n\n", str.c_str());
      }

  }

void
do_spell(ZHfstOspeller& speller, const std::string& str)
  {
    if (speller.spell(str))
      {
        hfst_fprintf(stdout, "\"%s\" is in the lexicon...\n",
                           str.c_str());
        if (analyse)
          {
            hfst_fprintf(stdout, "analysing:\n");
            hfst_ol::AnalysisQueue anals = speller.analyse(str, false);
            bool all_no_spell = true;
            while (anals.size() > 0)
              {
                if (anals.top().first.find("Use/-Spell") != std::string::npos)
                  {
                    hfst_fprintf(stdout,
                                       "%s   %f [DISCARDED AS -Spell]\n",
                                       anals.top().first.c_str(),
                                       anals.top().second);
                  }
                else
                  {
                    all_no_spell = false;
                    hfst_fprintf(stdout, "%s   %f\n",
                                   anals.top().first.c_str(),
                                   anals.top().second);
                  }
                anals.pop();
              }
            if (all_no_spell)
              {
                hfst_fprintf(stdout,
                             "All spellings were invalidated by analysis! "
                             ".:. Not in lexicon!\n");
              }
          }
        if (suggest_reals)
          {
            hfst_fprintf(stdout, "(but correcting anyways)\n", str.c_str());
            do_suggest(speller, str);
          }
      }
    else
      {
        hfst_fprintf(stdout, "\"%s\" is NOT in the lexicon:\n",
                           str.c_str());
        if (suggest)
          {
            do_suggest(speller, str);
          }
      }
  }

int
zhfst_spell(char* zhfst_filename)
{
  ZHfstOspeller speller;
  try
    {
      speller.read_zhfst(zhfst_filename);
    }
  catch (hfst_ol::ZHfstMetaDataParsingError zhmdpe)
    {
      hfst_fprintf(stderr, "cannot finish reading zhfst archive %s:\n%s.\n",
                         zhfst_filename, zhmdpe.what());
      //std::cerr << "cannot finish reading zhfst archive " << zhfst_filename <<
      //             ":\n" << zhmdpe.what() << "." << std::endl;
      return EXIT_FAILURE;
    }
  catch (hfst_ol::ZHfstZipReadingError zhzre)
    {
      //std::cerr << "cannot read zhfst archive " << zhfst_filename << ":\n"
      //    << zhzre.what() << "." << std::endl
      //    << "trying to read as legacy automata directory" << std::endl;
      hfst_fprintf(stderr,
                         "cannot read zhfst archive %s:\n"
                         "%s.\n",
                         zhfst_filename, zhzre.what());
      return EXIT_FAILURE;
    }
  catch (hfst_ol::ZHfstXmlParsingError zhxpe)
    {
      //std::cerr << "Cannot finish reading index.xml from "
      //  << zhfst_filename << ":" << std::endl
      //  << zhxpe.what() << "." << std::endl;
      hfst_fprintf(stderr,
                         "Cannot finish reading index.xml from %s:\n"
                         "%s.\n",
                         zhfst_filename, zhxpe.what());
      return EXIT_FAILURE;
    }
  if (verbose)
    {
      //std::cout << "Following metadata was read from ZHFST archive:" << std::endl
      //          << speller.metadata_dump() << std::endl;
      hfst_fprintf(stdout,
                         "Following metadata was read from ZHFST archive:\n"
                         "%s\n",
                         speller.metadata_dump().c_str());
    }
  speller.set_queue_limit(suggs);
  if (suggs != 0 && verbose)
    {
      hfst_fprintf(stdout, "Printing only %lu top suggestions per line\n", suggs);
    }
  speller.set_weight_limit(max_weight);
  if (max_weight >= 0.0 && verbose)
  {
      hfst_fprintf(stdout, "Not printing suggestions worse than %f\n", suggs);
  }
  char * str = (char*) malloc(2000);

#ifdef WINDOWS
    SetConsoleCP(65001);
    const HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
    WCHAR buffer[0x1000];
    DWORD numRead = 0;
    while (ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL))
      {
        std::wstring wstr(buffer, numRead-1); // skip the newline
        std::string linestr = wide_string_to_string(wstr);
        free(str);
        str = strdup(linestr.c_str());
#else
    while (!std::cin.eof()) {
        std::cin.getline(str, 2000);
#endif
        if (str[0] == '\0') {
            continue;
        }
        if (str[strlen(str) - 1] == '\r')
          {
#ifdef WINDOWS
            str[strlen(str) - 1] = '\0';
#else
            hfst_fprintf(stderr, "There is a WINDOWS linebreak in this file\n"
                               "Please convert with dos2unix or fromdos\n");
            exit(1);
#endif
          }
        do_spell(speller, str);
      }
    free(str);
    return EXIT_SUCCESS;
}

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

    int c;
    //std::locale::global(std::locale(""));

#if HAVE_GETOPT_H
    while (true) {
        static struct option long_options[] =
            {
            // first the hfst-mandated options
            {"help",         no_argument,       0, 'h'},
            {"version",      no_argument,       0, 'V'},
            {"verbose",      no_argument,       0, 'v'},
            {"quiet",        no_argument,       0, 'q'},
            {"silent",       no_argument,       0, 's'},
            {"analyse",      no_argument,       0, 'a'},
            {"limit",  required_argument,       0, 'n'},
            {"max-weight", required_argument,   0, 'w'},
            {"suggest",      no_argument,       0, 'S'},
            {"real-word",    no_argument,       0, 'X'},
#ifdef WINDOWS
            {"output-to-console",       no_argument,       0, 'k'},
#endif
            {0,              0,                 0,  0 }
            };

        int option_index = 0;
        c = getopt_long(argc, argv, "hVvqskaSnw:", long_options, &option_index);
        char* endptr = 0;

        if (c == -1) // no more options to look at
            break;

        switch (c) {
        case 'h':
            print_usage();
            return EXIT_SUCCESS;
            break;

        case 'V':
            print_version();
            return EXIT_SUCCESS;
            break;

        case 'v':
            verbose = true;
            quiet = false;
            break;

        case 'q': // fallthrough
        case 's':
            quiet = true;
            verbose = false;
            break;
        case 'a':
            analyse = true;
            break;
        case 'n':
            suggs = strtoul(optarg, &endptr, 10);
            if (endptr == optarg)
              {
                fprintf(stderr, "%s not a strtoul number\n", optarg);
                exit(1);
              }
            else if (*endptr != '\0')
              {
                fprintf(stderr, "%s truncated from limit parameter\n", endptr);
              }
            break;
        case 'w':
            max_weight = strtof(optarg, &endptr);
            if (endptr == optarg)
            {
                fprintf(stderr, "%s is not a float\n", optarg);
                exit(1);
              }
            else if (*endptr != '\0')
              {
                fprintf(stderr, "%s truncated from limit parameter\n", endptr);
              }

            break;
#ifdef WINDOWS
        case 'k':
            output_to_console = true;
            break;
#endif
        case 'S':
            suggest = true;
            break;
        case 'X':
            suggest_reals = true;
            break;
        default:
            std::cerr << "Invalid option\n\n";
            print_short_help();
            return EXIT_FAILURE;
            break;
        }
    }
#else
    int optind = 1;
#endif
    // no more options, we should now be at the input filenames
    if (optind == (argc - 1))
      {
        return zhfst_spell(argv[optind]);
      }
    else if (optind < (argc - 1))
      {
        std::cerr << "Too many file parameters" << std::endl;
        print_short_help();
        return EXIT_FAILURE;
      }
    else if (optind >= argc)
      {
        std::cerr << "Give full path to a zhfst speller"
            << std::endl;
        print_short_help();
        return EXIT_FAILURE;
      }
    return EXIT_SUCCESS;
  }
<|endoftext|>


<commit_before>#include <iostream>

#include "getfeatures_wrapper.hh"
#include "msz_model.hh"

using std::cerr;
using std::cout;

/**
 * Welcome, this  is the main maxsatzilla source file.
 * After some weeks of programming from scripts, to coaching
 * test files and mathematical functions we get to the main
 * file of maxsatzilla.
 *
 * Main purpose of maxsatzilla is just to read the models available,
 * compute the feature of the instance to solve,
 * run the models over the feature set,
 * and compute the expected runtime.
 */

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

  if(argc != 2) {
    cerr << "usage: maxsatzilla <instance.cnf>\n";
    exit(EXIT_FAILURE);
  }

  const char *instance = argv[1];

  // Let's compute the features
  cout << "Computing Features...";
  map<string, double> feats = getFeatures(instance);

  cout << " DONE\n";
#ifndef NDEBUG
  for(std::map<string, double>::const_iterator it = feats.begin(); it != feats.end(); it++)
    cout << it->first << " : " << it->second << "\n";
#endif NDEBUG

  // Let's compute the model

  // Let's display the models, from best to worst.

  return 0;
}
<commit_msg>Computing predicted runtime.<commit_after>#include <iostream>
#include <cassert>

#include "getfeatures_wrapper.hh"
#include "msz_model.hh"

using std::cerr;
using std::cout;

/**
 * Welcome, this  is the main maxsatzilla source file.
 * After some weeks of programming from scripts, to coaching
 * test files and mathematical functions we get to the main
 * file of maxsatzilla.
 *
 * Main purpose of maxsatzilla is just to read the models available,
 * compute the feature of the instance to solve,
 * run the models over the feature set,
 * and compute the expected runtime.
 */

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

  if(argc != 2) {
    cerr << "usage: maxsatzilla <instance.cnf>\n";
    exit(EXIT_FAILURE);
  }

  const char *instance = argv[1];

  // Let's compute the features
  cout << "Computing Features...";
  map<string, double> feats = getFeatures(instance);

  cout << " DONE\n";
#ifndef NDEBUG
  for(std::map<string, double>::const_iterator it = feats.begin(); it != feats.end(); it++)
    cout << it->first << " : " << it->second << "\n";
#endif // NDEBUG

  // Let's compute the model
  map<Solver, double> predRt;
  for(int s = 0; s < NUMSOLVERS; s++) {
    // Computing model for solver s.
    double runtime = 0.0;
    for(size_t f = 0; f < nbFeatures[s]; f++) {
      assert(feats.find(features[s][f]) != feats.end());
      assert(weights[f] != 0);
      runtime += feats[features[s][f]] * weights[s][f];
    }
    predRt[(Solver)s] = runtime;
  }

  // Let's display the models, from best to worst.
  cout << "Predicted Runtimes:\n";
  for(map<Solver, double>::const_iterator it = predRt.begin();
      it != predRt.end();
      it++)
    cout << "\t" << solverNames[it->first] << ": " << it->second << "\n";

  return 0;
}
<|endoftext|>