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

/*******************************************************************************************************************//**
* @file realsense_request.cpp
* @brief C++ example for receiving realsense image frames via a zmq request / response scheme.
* @author Team WALL-E & Christopher D. McMurrough
***********************************************************************************************************************/

#include <string>
#include <iostream>
#include <zmq.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
#include <pcl/common/time.h>
#include <ncurses.h>

// configuration parameters
#define NUM_COMNMAND_LINE_ARGUMENTS 1
#define DISPLAY_WINDOW_NAME "Received Image"

/*******************************************************************************************************************//**
* @brief program entry point
* @param[in] argc number of command line arguments
* @param[in] argv string array of command line arguments
* @return return code (0 for normal termination)
* @author Christoper D. McMurrough
***********************************************************************************************************************/
int main(int argc, char **argv)
{
    // character capturing intialization
    initscr();
    int ch;
    nodelay(stdscr, TRUE);
    noecho();

    // store display parameters
    bool showFrames = false;

    // create the cloud viewer object
    pcl::visualization::CloudViewer m_viewer (DISPLAY_WINDOW_NAME);

    // validate and parse the command line arguments
    if(argc != NUM_COMNMAND_LINE_ARGUMENTS + 1)
    {
        printw("USAGE: %s <display_mode> \n", argv[0]);
        printw("WARNING: Proceeding with default execution parameters... \n");
        showFrames = true;
    }
    else
    {
        showFrames = atoi(argv[1]) > 0;
    }

    // initialize the zmq context and socket
    zmq::context_t context(1);
    zmq::socket_t subscriber(context, ZMQ_SUB);

    // connect to the image server
    printw("Connecting to server...\n");

    subscriber.connect ("tcp://129.107.132.27:5555");

    printw("Press S to stream images and C to capture one image...\n");

    // create a request object
    //zmq::message_t request(5);
    //memcpy(request.data(), "Hello", 5);

    // get new frames until the user presses the 'q' key
    bool running = true;
    bool stream = false;
    bool capture = false;
    while(running)
    {
        if ((ch = getch()) == int('s')) { // if presses "stream" button
            if (stream) { // if we were already streaming
                subscriber.setsockopt(ZMQ_UNSUBSCRIBE, "", 0); // UNSUBSCRIBE
                printw("S pressed: Stopping stream.\n");
            } else { // else
                subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0); //SUBSCRIBE
                printw("S pressed: Starting stream.\n");
            }
            stream = !(stream); // toggle stream
        } else if (ch == int('c')) { // else if presses "capture" button
            subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
            capture = true;
            printw("C pressed: Capturing image.\n");
        }

        if (stream || capture) {
            //check for subscription
            // get the reply
            zmq::message_t reply;
            subscriber.recv(&reply);
            //std::vector<uchar> buffer;
            std::cout << "Received reply: " << reply.size() << " bytes" << std::endl;

            // store the reply data into an image structure
            pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
            cloud->height = 480;
            cloud->width = 640;
            cloud->is_dense = false;
            cloud->points.resize(640*480);
            std::memcpy(cloud->points.data(), reply.data(), reply.size());
            //std::cout << cloud->points[0] << std::endl;
            //cv::Mat image(480, 640, CV_8UC3, reply.data());

            //cloud->points = reply.data();

            // display the result
            if(showFrames) {
                m_viewer.showCloud(cloud);
            }

            if (capture) { // we've received one image and can stop
                subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
                capture = false;
            }
        }

        // check for program termination
        if(m_viewer.wasStopped ()) {
            running = false;
        }
    }

    // close the subscriber
    subscriber.close();
    return 0;
}
<commit_msg>Added simple UI to client using ncurses<commit_after>//
//    Copyright 2014 Team WALL-E
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

/*******************************************************************************************************************//**
* @file realsense_request.cpp
* @brief C++ example for receiving realsense image frames via a zmq request / response scheme.
* @author Team WALL-E & Christopher D. McMurrough
***********************************************************************************************************************/

#include <string>
#include <iostream>
#include <zmq.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
#include <pcl/common/time.h>
#include <ncurses.h>

// configuration parameters
#define NUM_COMNMAND_LINE_ARGUMENTS 1
#define DISPLAY_WINDOW_NAME "Received Image"

/*******************************************************************************************************************//**
* @brief program entry point
* @param[in] argc number of command line arguments
* @param[in] argv string array of command line arguments
* @return return code (0 for normal termination)
* @author Christoper D. McMurrough
***********************************************************************************************************************/
int main(int argc, char **argv)
{
    // character capturing intialization
    initscr();
    int ch;
    nodelay(stdscr, TRUE);
    noecho();

    // store display parameters
    bool showFrames = false;

    // create the cloud viewer object
    pcl::visualization::CloudViewer m_viewer (DISPLAY_WINDOW_NAME);

    // validate and parse the command line arguments
    if(argc != NUM_COMNMAND_LINE_ARGUMENTS + 1)
    {
        printw("USAGE: %s <display_mode> \n", argv[0]);
        printw("WARNING: Proceeding with default execution parameters... \n");
        showFrames = true;
    }
    else
    {
        showFrames = atoi(argv[1]) > 0;
    }

    // initialize the zmq context and socket
    zmq::context_t context(1);
    zmq::socket_t subscriber(context, ZMQ_SUB);

    // connect to the image server
    printw("Connecting to server...\n");

    subscriber.connect ("tcp://129.107.132.27:5555");

    printw("Press S to stream images and C to capture one image...\n");

    // create a request object
    //zmq::message_t request(5);
    //memcpy(request.data(), "Hello", 5);

    // get new frames until the user presses the 'q' key
    bool running = true;
    bool stream = false;
    bool capture = false;
    while(running)
    {
        if ((ch = getch()) == int('s')) { // if presses "stream" button
            if (stream) { // if we were already streaming
                subscriber.setsockopt(ZMQ_UNSUBSCRIBE, "", 0); // UNSUBSCRIBE
                printw("S pressed: Stopping stream.\n");
            } else { // else
                subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0); //SUBSCRIBE
                printw("S pressed: Starting stream.\n");
            }
            stream = !(stream); // toggle stream
        } else if (ch == int('c')) { // else if presses "capture" button
            subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
            capture = true;
            printw("C pressed: Capturing image.\n");
        }

        if (stream || capture) {
            //check for subscription
            // get the reply
            zmq::message_t reply;
            subscriber.recv(&reply);
            //std::vector<uchar> buffer;
            std::cout << "Received reply: " << reply.size() << " bytes" << std::endl;

            // store the reply data into an image structure
            pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
            cloud->height = 480;
            cloud->width = 640;
            cloud->is_dense = false;
            cloud->points.resize(640*480);
            std::memcpy(cloud->points.data(), reply.data(), reply.size());
            //std::cout << cloud->points[0] << std::endl;
            //cv::Mat image(480, 640, CV_8UC3, reply.data());

            //cloud->points = reply.data();

            // display the result
            if(showFrames) {
                m_viewer.showCloud(cloud);
            }

            if (capture) { // we've received one image and can stop
                subscriber.setsockopt(ZMQ_UNSUBSCRIBE, "", 0);
                capture = false;
            }
        }

        // check for program termination
        if(m_viewer.wasStopped ()) {
            running = false;
        }
    }

    // close the subscriber
    subscriber.close();
    return 0;
}
<|endoftext|>


<commit_before>#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <sstream>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <errno.h>

#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/objects.h>

#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "base64.h"

using namespace std;
using namespace rapidjson;

#define MACHINE_IP  inet_addr("127.0.0.1")

vector<string> split(string str, char delimiter) {
	vector<string> internal;
	stringstream ss(str);
	string tok;

	while(getline(ss, tok, delimiter)) {
		internal.push_back(tok);
	}

	return internal;
}

int sign(Document* d)
{

	const char private_key[] = "F2506E09D4153EED5ACBE1D620C93CA0D5580EF41AC0A401";
	const char pub_key[] = "027134EE605CB10FAE017BDD9FD88C96C8C080F08271637BB1";

	ECDSA_SIG *sig;
	char sig_str[B64SIZE];
	BN_CTX *ctx;
	BIGNUM *a;
	EVP_MD_CTX* mdctx;
	const EVP_MD* md;
	unsigned char md_value[EVP_MAX_MD_SIZE];
	unsigned int md_len;
	EC_KEY* auth_key;
	Value si;

	auth_key = EC_KEY_new_by_curve_name(NID_X9_62_prime192v3);
	if (auth_key == NULL) {
		printf("failed to initialize curve\n");
		return 1;
  	}

	ctx = BN_CTX_new();
	if(!ctx) {
		printf("failed to create bn ctx\n");
		return 1;
  	}

	EC_KEY_set_public_key(auth_key,
	EC_POINT_hex2point(EC_KEY_get0_group(auth_key),pub_key, NULL, ctx));
	a = BN_new();
	BN_hex2bn(&a, private_key);
	EC_KEY_set_private_key(auth_key, a);

	BN_CTX_free(ctx);

	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);
	d->Accept(writer);

	printf("sig is signing: %s\n", buffer.GetString());

	OpenSSL_add_all_digests();
	md = EVP_get_digestbyname("sha256");
	if(md == 0) {
		printf("Unknown message digest\n");
		return 1;
	}

	mdctx = EVP_MD_CTX_create();
	EVP_DigestInit_ex(mdctx, md, NULL);
	EVP_DigestUpdate(mdctx, buffer.GetString(), buffer.GetSize());
	EVP_DigestFinal_ex(mdctx, md_value, &md_len);
	EVP_MD_CTX_destroy(mdctx);

	printf("digest: ");
	dump_mem(md_value, md_len);

	sig = ECDSA_do_sign(md_value, md_len, auth_key);

	if (sig == NULL) {
		printf("Signing failed\n");
		return 1;
  	}

	base64encode(sig_str, sig->r, sig->s);
	si.SetString(sig_str, B64SIZE, d->GetAllocator());
	d->AddMember("si", si, d->GetAllocator());

	printf("sig: %s, %s\n", BN_bn2hex(sig->r), BN_bn2hex(sig->s));
	return 0;
}

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

char* get_request(int fd) {
  char* message;
  size_t size = TOKENSIZE;
  int offset;

  message = (char*) realloc(NULL, sizeof(char)*size);
  if(!message) {
    printf("get_request: Failure to realloc\n");
    exit(1);
  }

  offset = -1;
  do {
    offset++;
    if (offset == size) {
      message = (char*) realloc(message, sizeof(char)*(size += 16)); //??
      if(!message) {
	printf("get_request: Failure to realloc\n");
	exit(1);
      }
    }
    if(read(fd, message+offset, 1) <= 0) {
      printf("get_request: EOF encountered\n");

      char c = message[offset];
      message[offset] = 0;
      printf("story so far (%d): %s%c\n", offset, message, c);

      exit(1);
    }
  } while (message[offset] != 0);

  printf("get_request: message at %p: %s\n", message, message);

  return message;
}

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

/*int process_mode(int fd, int choice, const char* port_mode1, const char* port_mode2) {

        int fd;
        socklen_t peer_addr_size = sizeof(struct sockaddr_in);
        char * sub_request;
        unsigned char response;
        struct sockaddr_in retAddress;

        printf("DEBUG: entering network loop\n");
        while(true) {

            printf("DEBUG: network loop: accepting connection...\n");
            fd = accept(soc, (struct sockaddr *) &retAddress, &peer_addr_size);
            if( fd == -1) {
              printf("listen: Failed to accept: %s\n", strerror(errno));
              exit(1);
            }
            printf( "DEBUG: network loop: connection accepted, getting request from subject...\n");

            sub_request = get_request(fd);

        }

	char* message;
	size_t size = TOKENSIZE;
	unsigned int offset;

	// step 1: read request from client, common for both mode1 and mode2

	message = (char*) realloc(NULL, sizeof(char)*size);
	if(!message) {
		printf("process_mode: Failure to realloc\n");
		exit(1);
  	}

	offset = 0;
	do {

		if (offset == size) {
			message = (char*) realloc(message, sizeof(char)*(size += 16));
			if(!message) {
		        	printf("process_mode: Failure to realloc\n");
		        	exit(1);
      			}
    		}

		if(read(fd, message+offset, 1) <= 0) {
			printf("process_mode: EOF encountered\n");

			char c = message[offset];
			message[offset] = '\0';
			printf("story so far (%d): %s%c\n", offset, message, c);

			exit(1);
    		}
		offset++;
	} while (message[offset-1] != '\0');

	printf("DEBUG: process_mode: message at %p: %s\n", message, message);

	// step 2: create token 'd', common for both mode1 and mode2

	vector<string> sep = split(message, '\n');
	const char * pub_key = sep[0].c_str();
	const char * res_add = sep[1].c_str();

	cout << "public key (b64): " << pub_key << "\n";
	cout << "resource address: " << res_add << "\n";

	Document d;
	Value ii, nb, na, suv, dev;
	unsigned int now;

	d.Parse("{}");

	now = time(NULL);
	ii.SetInt(now);
	nb.SetInt(now);
	na.SetInt(1600000000);
	suv.SetString(pub_key, strlen(pub_key), d.GetAllocator());
	dev.SetString(res_add, strlen(res_add), d.GetAllocator());

	d.AddMember("id", "fake identifier", d.GetAllocator());
	d.AddMember("ii", ii, d.GetAllocator());
	d.AddMember("is", "fake issuer", d.GetAllocator());
	d.AddMember("su", suv, d.GetAllocator());
	d.AddMember("de", dev, d.GetAllocator());
	d.AddMember("ar", "fake access rights", d.GetAllocator());
	d.AddMember("nb", nb, d.GetAllocator());
	d.AddMember("na", na, d.GetAllocator());

	sign(&d);

	// Step 3: Mode choice dependent
	// (Mode 1, return token to client)
	if (choice == 1) {
		StringBuffer buffer;
		Writer<StringBuffer> writer(buffer);
	        d.Accept(writer);

        	cout << "buffer data : " << buffer.GetString();
		cout << "\n buffer len:" << buffer.GetSize();

	        if(write(fd, buffer.GetString(), buffer.GetSize()+1) < 0) {
		        printf("Failed to write to socket\n");
          	}
	       // return 1;

	}

	// (Mode 2, return token to resource, token ID to client)

	else if(choice == 2 ){

        	cout << "Mode 2\n";

	        int soc2;
        	uint16_t port = strtol(port_mode2, NULL, 10);
	        char null_string[17];

        	soc2 = socket(AF_INET, SOCK_STREAM, 0);
	        if(soc2 < 0) {
        		printf("failed to create socket: %s\n", strerror(errno));
          	}

	 	struct sockaddr_in connectAddress;
	        memset(&connectAddress, 0, sizeof(connectAddress));
        	connectAddress.sin_family = AF_INET;
	        connectAddress.sin_addr.s_addr = MACHINE_IP;
          	connectAddress.sin_port = htons(port);

	        if(connect(soc2, (struct sockaddr *) &connectAddress, sizeof(connectAddress)) < 0) {
            		printf("send token to resource: failed to connect to resource: %s\n", strerror(errno));
          	}

		// insert code for null string here
        	int i;

		// add 17 NULLS before sending the json to resource -- one socket
		        for (i = 0; i <=17; i++){
	        	null_string[i] = (char) 0;
	        }

	        if(write(soc2, null_string, 17) < 0) {
	        	printf("Failed to write null string to resource socket\n");
	        }

	        //send token to resource here
	        StringBuffer buffer;
	        Writer<StringBuffer> writer(buffer);
	        d.Accept(writer);

	        cout << "buffer data : "<< buffer.GetString() ;
	        cout << "\n buffer len:" << buffer.GetSize() << "\n";

	        if(write(soc2, buffer.GetString(), buffer.GetSize()+1) < 0) {
	        	printf("Failed to write to token to resource socket\n");
	        }

	        //send token ID to client

            int tokenID = d["ii"].GetInt();
  	        std::string s_ID = std::to_string(tokenID);
            char const *tokenID_str = s_ID.c_str();

            cout << "string token ID: " << tokenID_str << "\n";

	        if(write(fd, tokenID_str, strlen(tokenID_str)+1) < 0) {
	        	printf("Failed to write to socket\n");

	        }

	    //    return 1;
	}// end of mode 2

}*/

int bootstrap_network(const char* port_sub){

	int soc;
	uint16_t port = strtol(port_sub, NULL, 10);   // from arguments

	soc = socket(AF_INET, SOCK_STREAM, 0);
	if (soc == -1)	{
		printf("Failed to open socket\n");
		return 1;
  	}

 	struct sockaddr_in connectAddress;
	memset(&connectAddress, 0, sizeof(connectAddress));
	connectAddress.sin_family = AF_INET;
	connectAddress.sin_addr.s_addr = MACHINE_IP;
	connectAddress.sin_port = htons(port);

	if(bind(soc, (struct sockaddr *) &connectAddress, sizeof(connectAddress)) == -1) {
		printf("bootstrap: Failed to bind\n");
		exit(1);
  	}

	if(listen(soc, 5) == -1) {
		printf( "bootstrap: Failed to listen\n");
		exit(1);
  	}

	return soc;
}

int listen_block(int soc,int choice, const char* port_mode1, const char* port_mode2){

	int fd;
	socklen_t peer_addr_size = sizeof(struct sockaddr_in);
	struct sockaddr_in retAddress;
    char * sub_request;

	printf("DEBUG: entering network loop\n");

	while(true) {
		printf("DEBUG: network loop: accepting connection...\n");
		fd = accept(soc, (struct sockaddr *) &retAddress, &peer_addr_size);

		if( fd == -1) {
			printf("listen: Failed to accept: %s\n", strerror(errno));
			exit(1);
    		}

		printf( "DEBUG: network loop: connection accepted, getting request from subject...\n");

		sub_request = get_request(fd);

  	}

      	string message = sub_request;
      	vector<string> sep = split(message, '\n');
	    const char * pub_key = sep[0].c_str();
	    const char * res_add = sep[1].c_str();

	    cout << "public key (b64): " << pub_key << "\n";
	    cout << "resource address: " << res_add << "\n";

	/////////////////////**********************************************
	    Document d;
	    Value ii, nb, na, suv, dev;
	    unsigned int now;

	    d.Parse("{}");

	    now = time(NULL);
	    ii.SetInt(now);
	    nb.SetInt(now);
	    na.SetInt(1600000000);
	    suv.SetString(pub_key, strlen(pub_key), d.GetAllocator());
	    dev.SetString(res_add, strlen(res_add), d.GetAllocator());

	    d.AddMember("id", "fake identifier", d.GetAllocator());
	    d.AddMember("ii", ii, d.GetAllocator());
	    d.AddMember("is", "fake issuer", d.GetAllocator());
	    d.AddMember("su", suv, d.GetAllocator());
	    d.AddMember("de", dev, d.GetAllocator());
	    d.AddMember("ar", "fake access rights", d.GetAllocator());
	    d.AddMember("nb", nb, d.GetAllocator());
	    d.AddMember("na", na, d.GetAllocator());

	    sign(&d);

	    // Step 3: Mode choice dependent
	    // (Mode 1, return token to client)
	    if (choice == 1) {
		        StringBuffer buffer;
		        Writer<StringBuffer> writer(buffer);
	            d.Accept(writer);

                cout << "buffer data : " << buffer.GetString();
		        cout << "\n buffer len:" << buffer.GetSize();

	            if(write(fd, buffer.GetString(), buffer.GetSize()+1) < 0) {
		                printf("Failed to write to socket\n");
                }
                   // return 1;
         }

	    // (Mode 2, return token to resource, token ID to client)

	    else if(choice == 2 ){

            	cout << "Mode 2\n";

	            int soc2;
            	uint16_t port = strtol(port_mode2, NULL, 10);
	            char null_string[17];

            	soc2 = socket(AF_INET, SOCK_STREAM, 0);
	            if(soc2 < 0) {
            		printf("failed to create socket: %s\n", strerror(errno));
              	}

	     	    struct sockaddr_in connectAddress;
	            memset(&connectAddress, 0, sizeof(connectAddress));
            	connectAddress.sin_family = AF_INET;
	            connectAddress.sin_addr.s_addr = MACHINE_IP;
              	connectAddress.sin_port = htons(port);

	            if(connect(soc2, (struct sockaddr *) &connectAddress, sizeof(connectAddress)) < 0) {
                		printf("send token to resource: failed to connect to resource: %s\n", strerror(errno));
              	}

		    // insert code for null string here
            	int i;

		    // add 17 NULLS before sending the json to resource -- one socket
		            for (i = 0; i <=17; i++){
	            	null_string[i] = (char) 0;
	            }

	            if(write(soc2, null_string, 17) < 0) {
	            	printf("Failed to write null string to resource socket\n");
	            }

	            //send token to resource here
	            StringBuffer buffer;
	            Writer<StringBuffer> writer(buffer);
	            d.Accept(writer);

	            cout << "buffer data : "<< buffer.GetString() ;
	            cout << "\n buffer len:" << buffer.GetSize() << "\n";

	            if(write(soc2, buffer.GetString(), buffer.GetSize()+1) < 0) {
	            	printf("Failed to write to token to resource socket\n");
	            }

	            //send token ID to client

                int tokenID = d["ii"].GetInt();
      	        std::string s_ID = std::to_string(tokenID);
                char const *tokenID_str = s_ID.c_str();

                cout << "string token ID: " << tokenID_str << "\n";

	            if(write(fd, tokenID_str, strlen(tokenID_str)+1) < 0) {
	            	printf("Failed to write to socket\n");

	            }

	        //    return 1;
	    }// end of mode 2
	/////////////////////**********************************************

}

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

	if(argc <= 3){
		printf("insufficient arguments\n");
		printf("sample argument: ./auth <mode> <port_client> <port_resource>\n");
		return 1;
  	}

	int fd1, soc1;
  	soc1 = bootstrap_network(argv[2]);
	//fd1 = listen_block(soc1);
	const char* port_client = argv[2];
	const char* port_resource = argv[3];

  	if(!strcmp(argv[1], "1"))
		listen_block(soc1,1,port_client,port_resource);

    	else if(!strcmp(argv[1], "2")){
		listen_block(soc1,2,port_client,port_resource);

	}

	else{
		printf("Invalid mode: %s", argv[1]);
		exit(1);
  	}

	return 1;
}
<commit_msg>auth.cpp updated<commit_after>#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <sstream>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <errno.h>

#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/objects.h>

#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "base64.h"

using namespace std;
using namespace rapidjson;

#define MACHINE_IP  inet_addr("127.0.0.1")

vector<string> split(string str, char delimiter) {
	vector<string> internal;
	stringstream ss(str);
	string tok;

	while(getline(ss, tok, delimiter)) {
		internal.push_back(tok);
	}

	return internal;
}

int sign(Document* d)
{

	const char private_key[] = "F2506E09D4153EED5ACBE1D620C93CA0D5580EF41AC0A401";
	const char pub_key[] = "027134EE605CB10FAE017BDD9FD88C96C8C080F08271637BB1";

	ECDSA_SIG *sig;
	char sig_str[B64SIZE];
	BN_CTX *ctx;
	BIGNUM *a;
	EVP_MD_CTX* mdctx;
	const EVP_MD* md;
	unsigned char md_value[EVP_MAX_MD_SIZE];
	unsigned int md_len;
	EC_KEY* auth_key;
	Value si;

	auth_key = EC_KEY_new_by_curve_name(NID_X9_62_prime192v3);
	if (auth_key == NULL) {
		printf("failed to initialize curve\n");
		return 1;
  	}

	ctx = BN_CTX_new();
	if(!ctx) {
		printf("failed to create bn ctx\n");
		return 1;
  	}

	EC_KEY_set_public_key(auth_key,
	EC_POINT_hex2point(EC_KEY_get0_group(auth_key),pub_key, NULL, ctx));
	a = BN_new();
	BN_hex2bn(&a, private_key);
	EC_KEY_set_private_key(auth_key, a);

	BN_CTX_free(ctx);

	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);
	d->Accept(writer);

	printf("sig is signing: %s\n", buffer.GetString());

	OpenSSL_add_all_digests();
	md = EVP_get_digestbyname("sha256");
	if(md == 0) {
		printf("Unknown message digest\n");
		return 1;
	}

	mdctx = EVP_MD_CTX_create();
	EVP_DigestInit_ex(mdctx, md, NULL);
	EVP_DigestUpdate(mdctx, buffer.GetString(), buffer.GetSize());
	EVP_DigestFinal_ex(mdctx, md_value, &md_len);
	EVP_MD_CTX_destroy(mdctx);

	printf("digest: ");
	dump_mem(md_value, md_len);

	sig = ECDSA_do_sign(md_value, md_len, auth_key);

	if (sig == NULL) {
		printf("Signing failed\n");
		return 1;
  	}

	base64encode(sig_str, sig->r, sig->s);
	si.SetString(sig_str, B64SIZE, d->GetAllocator());
	d->AddMember("si", si, d->GetAllocator());

	printf("sig: %s, %s\n", BN_bn2hex(sig->r), BN_bn2hex(sig->s));
	return 0;
}

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

int get_request(int fd, int choice, const char* port_mode) {

          char* message;
          size_t size = TOKENSIZE;
          int offset;

          // step 1: read request from client, common for both mode1 and mode2

          message = (char*) realloc(NULL, sizeof(char)*size);
          if(!message) {
            printf("get_request: Failure to realloc\n");
            exit(1);
          }

          offset = -1;
          do {
                offset++;
                if (offset == size) {

                        message = (char*) realloc(message, sizeof(char)*(size += 16));
                        if(!message) {
                            printf("get_request: Failure to realloc\n");
	                        exit(1);
                        }
                    }

                if(read(fd, message+offset, 1) <= 0) {
                        printf("get_request: EOF encountered\n");
                        char c = message[offset];
                        message[offset] = 0;
                        printf("story so far (%d): %s%c\n", offset, message, c);
                        exit(1);
                }
          } while (message[offset] != 0);

            printf("get_request: message at %p: %s\n", message, message);

	        vector<string> sep = split(message, '\n');
	        const char * pub_key = sep[0].c_str();
	        const char * res_add = sep[1].c_str();

	        cout << "public key (b64): " << pub_key << "\n";
	        cout << "resource address: " << res_add << "\n";

            // step 2: create token 'd', common for both mode1 and mode2
	        Document d;
	        Value ii, nb, na, suv, dev;
	        unsigned int now;

	        d.Parse("{}");

	        now = time(NULL);
	        ii.SetInt(now);
	        nb.SetInt(now);
	        na.SetInt(1600000000);
	        suv.SetString(pub_key, strlen(pub_key), d.GetAllocator());
	        dev.SetString(res_add, strlen(res_add), d.GetAllocator());

	        d.AddMember("id", "fake identifier", d.GetAllocator());
	        d.AddMember("ii", ii, d.GetAllocator());
	        d.AddMember("is", "fake issuer", d.GetAllocator());
	        d.AddMember("su", suv, d.GetAllocator());
	        d.AddMember("de", dev, d.GetAllocator());
	        d.AddMember("ar", "fake access rights", d.GetAllocator());
	        d.AddMember("nb", nb, d.GetAllocator());
	        d.AddMember("na", na, d.GetAllocator());

	        sign(&d);

	        // Step 3: Mode choice dependent
	        // (Mode 1, return token to client)
	        if (choice == 1) {
		        StringBuffer buffer;
		        Writer<StringBuffer> writer(buffer);
	            d.Accept(writer);

                cout << "buffer data : " << buffer.GetString();
		        cout << "\n buffer len:" << buffer.GetSize();

                if(write(fd, buffer.GetString(), buffer.GetSize()+1) < 0) {
                    printf("Failed to write to socket\n");
              	}
                return 1;
	        }

	        // (Mode 2, return token to resource, token ID to client)

	        else if(choice == 2 ){

                cout << "Mode 2\n";

                int soc2;
                uint16_t port = strtol(port_mode, NULL, 10);
                char null_string[17];

                soc2 = socket(AF_INET, SOCK_STREAM, 0);
                if(soc2 < 0) {
	                printf("failed to create socket: %s\n", strerror(errno));
                }

                struct sockaddr_in connectAddress;
                memset(&connectAddress, 0, sizeof(connectAddress));
                connectAddress.sin_family = AF_INET;
                connectAddress.sin_addr.s_addr = MACHINE_IP;
                connectAddress.sin_port = htons(port);

                if(connect(soc2, (struct sockaddr *) &connectAddress, sizeof(connectAddress)) < 0) {
		                printf("send token to resource: failed to connect to resource: %s\n", strerror(errno));
                }

		        // insert code for null string here
               	int i;

		        // add 17 NULLS before sending the json to resource -- one socket
                for (i = 0; i <=17; i++){
                    null_string[i] = (char) 0;
                }

                if(write(soc2, null_string, 17) < 0) {
                    printf("Failed to write null string to resource socket\n");
                }

                //send token to resource here
                StringBuffer buffer;
                Writer<StringBuffer> writer(buffer);
                d.Accept(writer);

                cout << "buffer data : "<< buffer.GetString() ;
                cout << "\n buffer len:" << buffer.GetSize() << "\n";

                if(write(soc2, buffer.GetString(), buffer.GetSize()+1) < 0) {
                     printf("Failed to write to token to resource socket\n");
                }

                //send token ID to client

                int tokenID = d["ii"].GetInt();
                std::string s_ID = std::to_string(tokenID);
                char const *tokenID_str = s_ID.c_str();

                cout << "string token ID: " << tokenID_str << "\n";

                if(write(fd, tokenID_str, strlen(tokenID_str)+1) < 0) {
                     printf("Failed to write to socket\n");
                }

                return 1;
	      }// end of mode 2
}

int bootstrap_network(const char* port_sub){

	int soc;
	uint16_t port = strtol(port_sub, NULL, 10);   // from arguments

	soc = socket(AF_INET, SOCK_STREAM, 0);
	if (soc == -1)	{
		printf("Failed to open socket\n");
		return 1;
  	}

 	struct sockaddr_in connectAddress;
	memset(&connectAddress, 0, sizeof(connectAddress));
	connectAddress.sin_family = AF_INET;
	connectAddress.sin_addr.s_addr = MACHINE_IP;
	connectAddress.sin_port = htons(port);

	if(bind(soc, (struct sockaddr *) &connectAddress, sizeof(connectAddress)) == -1) {
		printf("bootstrap: Failed to bind\n");
		exit(1);
  	}

	if(listen(soc, 5) == -1) {
		printf( "bootstrap: Failed to listen\n");
		exit(1);
  	}

	return soc;
}

int listen_block(int soc,int choice, const char* port_mode){

	int fd;
	socklen_t peer_addr_size = sizeof(struct sockaddr_in);
	struct sockaddr_in retAddress;
    int req1;

	printf("DEBUG: entering network loop\n");

	while(true) {
		printf("DEBUG: network loop: accepting connection...\n");
		fd = accept(soc, (struct sockaddr *) &retAddress, &peer_addr_size);
		printf("fd value: %d\n",fd);
		if( fd == -1) {
			printf("listen: Failed to accept: %s\n", strerror(errno));
			exit(1);
    		}

		printf( "DEBUG: network loop: connection accepted, getting request from subject...\n");

		req1 = get_request(fd,choice,port_mode);
		close(fd);
	}

}

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

	if(argc <= 3){
		printf("insufficient arguments\n");
		printf("sample argument: ./auth <mode> <port_client> <port_resource>\n {Enter dummy value for port_resource in Mode 1}");
		return 1;
  	}

	int fd1, soc1;
  	soc1 = bootstrap_network(argv[2]);

	const char* port_client = argv[2];
	const char* port_resource = argv[3];

  	if(!strcmp(argv[1], "1"))
		listen_block(soc1,1,port_resource);

    	else if(!strcmp(argv[1], "2"))
		listen_block(soc1,2,port_resource);

	else{
		printf("Invalid mode: %s", argv[1]);
		exit(1);
  	}

	return 1;
}
<|endoftext|>


<commit_before>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/

#include "otbConfigure.h"

#include "itkMersenneTwisterRandomVariateGenerator.h"

#ifdef OTB_USE_OPENCV
#include "otbNeuralNetworkMachineLearningModel.h"
#include "otbSVMMachineLearningModel.h"
#include "otbBoostMachineLearningModel.h"
#include "otbDecisionTreeMachineLearningModel.h"
#include "otbGradientBoostedTreeMachineLearningModel.h"
#include "otbKNearestNeighborsMachineLearningModel.h"
#include "otbRandomForestsMachineLearningModel.h"
#endif

#ifdef OTB_USE_LIBSVM
#include "otbLibSVMMachineLearningModel.h"
#endif

typedef float PrecisionType;
typedef otb::MachineLearningModel<PrecisionType,PrecisionType>   MachineLearningModelRegressionType;
typedef MachineLearningModelRegressionType::InputValueType       InputValueRegressionType;
typedef MachineLearningModelRegressionType::InputSampleType      InputSampleRegressionType;
typedef MachineLearningModelRegressionType::InputListSampleType  InputListSampleRegressionType;
typedef MachineLearningModelRegressionType::TargetValueType      TargetValueRegressionType;
typedef MachineLearningModelRegressionType::TargetSampleType     TargetSampleRegressionType;
typedef MachineLearningModelRegressionType::TargetListSampleType TargetListSampleRegressionType;
typedef itk::Statistics::MersenneTwisterRandomVariateGenerator   RandomGeneratorType;

const double epsilon = 0.1;

typedef struct RegressionTestParamStruct
{
  double vMin;
  double vMax;
  size_t count;
  double eps;
} RegressionTestParam;

template <typename TPrecision>
struct LinearFunctionSampleGenerator
{
  typedef TPrecision PrecisionType;
  LinearFunctionSampleGenerator(TPrecision a, TPrecision b)
    : m_a(a), m_b(b), m_NbInputVars(1), m_NbOutputVars(1) {
    m_isl = InputListSampleRegressionType::New();
    m_tsl = TargetListSampleRegressionType::New();
  };
  void GenerateSamples(TPrecision sMin, TPrecision sMax, size_t nbSamples)
  {
    m_isl->Clear();
    m_tsl->Clear();
    m_isl->SetMeasurementVectorSize(m_NbInputVars);
    m_tsl->SetMeasurementVectorSize(m_NbOutputVars);

    RandomGeneratorType::Pointer randomGenerator = RandomGeneratorType::GetInstance();
    InputSampleRegressionType inputSample;
    inputSample.SetSize(m_NbInputVars);
    TargetSampleRegressionType outputSample;

    TPrecision sampleStep = (sMax-sMin)/nbSamples;
    for(size_t i=0; i<nbSamples; ++i)
      {
      TPrecision x = randomGenerator->GetUniformVariate(0.0, 1.0) * static_cast<TPrecision>(nbSamples);
      TPrecision inputValue = sMin+ x*sampleStep;
      inputSample[0] = inputValue;
      outputSample[0] = m_a*inputValue+m_b;
      m_isl->PushBack(inputSample);
      m_tsl->PushBack(outputSample);
      }
  }

  TPrecision m_a;
  TPrecision m_b;
  const size_t m_NbInputVars;
  const size_t m_NbOutputVars;
  InputListSampleRegressionType::Pointer m_isl;
  TargetListSampleRegressionType::Pointer m_tsl;
};

template <typename SampleGeneratorType, typename RegressionType>
int testRegression(SampleGeneratorType& sg, RegressionType& rgrsn, RegressionTestParam param)
{
  std::cout << "Generating training samples" << std::endl;
  sg.GenerateSamples(param.vMin, param.vMax, param.count);

  rgrsn->SetInputListSample(sg.m_isl);
  rgrsn->SetTargetListSample(sg.m_tsl);
  std::cout << "Training" << std::endl;
  rgrsn->Train();

  std::cout << "Generate validation samples"<<std::endl;
  sg.GenerateSamples(param.vMin, param.vMax, param.count);

  std::cout << "Validation" << std::endl;
  //Check the prediction accuracy
  typename InputListSampleRegressionType::Iterator sampleIt = sg.m_isl->Begin();
  typename TargetListSampleRegressionType::Iterator resultIt = sg.m_tsl->Begin();
  typename InputListSampleRegressionType::Iterator sampleLast = sg.m_isl->End();
  typename TargetListSampleRegressionType::Iterator resultLast = sg.m_tsl->End();
  typename SampleGeneratorType::PrecisionType rmse = 0.0;
  while(sampleIt != sampleLast && resultIt != resultLast)
    {
    //typename SampleGeneratorType::PrecisionType invalue = sampleIt.GetMeasurementVector()[0];
    typename SampleGeneratorType::PrecisionType prediction = rgrsn->Predict(sampleIt.GetMeasurementVector())[0];
    typename SampleGeneratorType::PrecisionType expected = resultIt.GetMeasurementVector()[0];
    rmse += pow(prediction - expected, 2.0);
    ++sampleIt;
    ++resultIt;
    }

  rmse = sqrt( rmse / static_cast<double>(param.count) );
  std::cout << "RMSE = "<< rmse << std::endl;
  if(rmse > param.eps)
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}

#ifdef OTB_USE_LIBSVM
int otbLibSVMRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::LibSVMMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    libsvmType;
  libsvmType::Pointer regression = libsvmType::New();
  regression->SetRegressionMode(true);
  regression->SetSVMType(EPSILON_SVR);
  regression->SetKernelType(RBF);
  regression->SetEpsilon(1e-5);
  regression->SetParameterOptimization(true);

  return testRegression(lfsg,regression,param);
}
#endif

#ifdef OTB_USE_OPENCV
int otbNeuralNetworkRegressionLinearMonovariate(int itkNotUsed(argc),
                                                char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 20000;
  param.eps = 0.1;

  typedef otb::NeuralNetworkMachineLearningModel<InputValueRegressionType,
                                                 TargetValueRegressionType>
    NeuralNetworkType;
  NeuralNetworkType::Pointer regression = NeuralNetworkType::New();

  regression->SetRegressionMode(1);
  regression->SetTrainMethod(CvANN_MLP_TrainParams::BACKPROP);
  std::vector<unsigned int> layerSizes;
  layerSizes.push_back(1);
  layerSizes.push_back(5);
  layerSizes.push_back(1);
  regression->SetLayerSizes(layerSizes);
  regression->SetActivateFunction(CvANN_MLP::SIGMOID_SYM);
  regression->SetAlpha(1.0);
  regression->SetBeta(1.0);
  regression->SetBackPropDWScale(0.1);
  regression->SetBackPropMomentScale(0.1);
  regression->SetRegPropDW0(0.1);
  regression->SetRegPropDWMin(1e-7);
  regression->SetTermCriteriaType(CV_TERMCRIT_EPS);
  regression->SetEpsilon(1e-5);
  regression->SetMaxIter(1e4);

  return testRegression(lfsg,regression,param);
}

int otbSVMRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::SVMMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    SVMType;
  SVMType::Pointer regression = SVMType::New();

  regression->SetRegressionMode(1);
  regression->SetNu(0.5);
  regression->SetKernelType(CvSVM::RBF);
  regression->SetTermCriteriaType(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS);
  regression->SetMaxIter(100000);
  regression->SetEpsilon(1e-5);
  regression->SetParameterOptimization(true);

  return testRegression(lfsg,regression,param);
}

int otbDecisionTreeRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::DecisionTreeMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    DTreeType;
  DTreeType::Pointer regression = DTreeType::New();
  regression->SetRegressionMode(true);

  return testRegression(lfsg,regression,param);
}

int otbGradientBoostedTreeRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::GradientBoostedTreeMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    GBTreeType;
  GBTreeType::Pointer regression = GBTreeType::New();
  regression->SetRegressionMode(true);
  regression->SetLossFunctionType(CvGBTrees::SQUARED_LOSS);

  return testRegression(lfsg,regression,param);
}

int otbKNearestNeighborsRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::KNearestNeighborsMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    KNNType;
  KNNType::Pointer regression = KNNType::New();
  regression->SetRegressionMode(true);
  regression->SetK(1);

  return testRegression(lfsg,regression,param);
}

int otbRandomForestsRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::RandomForestsMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    RFType;
  RFType::Pointer regression = RFType::New();
  regression->SetRegressionMode(true);

  return testRegression(lfsg,regression,param);
}
#endif
<commit_msg>ENH: added sample generators for bilinear et polynomial cases<commit_after>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/

#include "otbConfigure.h"

#include "itkMersenneTwisterRandomVariateGenerator.h"

#ifdef OTB_USE_OPENCV
#include "otbNeuralNetworkMachineLearningModel.h"
#include "otbSVMMachineLearningModel.h"
#include "otbBoostMachineLearningModel.h"
#include "otbDecisionTreeMachineLearningModel.h"
#include "otbGradientBoostedTreeMachineLearningModel.h"
#include "otbKNearestNeighborsMachineLearningModel.h"
#include "otbRandomForestsMachineLearningModel.h"
#endif

#ifdef OTB_USE_LIBSVM
#include "otbLibSVMMachineLearningModel.h"
#endif

typedef float PrecisionType;
typedef otb::MachineLearningModel<PrecisionType,PrecisionType>   MachineLearningModelRegressionType;
typedef MachineLearningModelRegressionType::InputValueType       InputValueRegressionType;
typedef MachineLearningModelRegressionType::InputSampleType      InputSampleRegressionType;
typedef MachineLearningModelRegressionType::InputListSampleType  InputListSampleRegressionType;
typedef MachineLearningModelRegressionType::TargetValueType      TargetValueRegressionType;
typedef MachineLearningModelRegressionType::TargetSampleType     TargetSampleRegressionType;
typedef MachineLearningModelRegressionType::TargetListSampleType TargetListSampleRegressionType;
typedef itk::Statistics::MersenneTwisterRandomVariateGenerator   RandomGeneratorType;

const double epsilon = 0.1;

typedef struct RegressionTestParamStruct
{
  double vMin;
  double vMax;
  size_t count;
  double eps;
} RegressionTestParam;

template <typename TPrecision>
struct LinearFunctionSampleGenerator
{
  typedef TPrecision PrecisionType;
  LinearFunctionSampleGenerator(TPrecision a, TPrecision b)
    : m_a(a), m_b(b), m_NbInputVars(1), m_NbOutputVars(1) {
    m_isl = InputListSampleRegressionType::New();
    m_tsl = TargetListSampleRegressionType::New();
  };
  void GenerateSamples(TPrecision sMin, TPrecision sMax, size_t nbSamples)
  {
    m_isl->Clear();
    m_tsl->Clear();
    m_isl->SetMeasurementVectorSize(m_NbInputVars);
    m_tsl->SetMeasurementVectorSize(m_NbOutputVars);

    RandomGeneratorType::Pointer randomGenerator = RandomGeneratorType::GetInstance();
    InputSampleRegressionType inputSample;
    inputSample.SetSize(m_NbInputVars);
    TargetSampleRegressionType outputSample;

    TPrecision sampleStep = (sMax-sMin)/nbSamples;
    for(size_t i=0; i<nbSamples; ++i)
      {
      TPrecision x = randomGenerator->GetUniformVariate(0.0, 1.0) * static_cast<TPrecision>(nbSamples);
      TPrecision inputValue = sMin+ x*sampleStep;
      inputSample[0] = inputValue;
      outputSample[0] = m_a*inputValue+m_b;
      m_isl->PushBack(inputSample);
      m_tsl->PushBack(outputSample);
      }
  }

  TPrecision m_a;
  TPrecision m_b;
  const size_t m_NbInputVars;
  const size_t m_NbOutputVars;
  InputListSampleRegressionType::Pointer m_isl;
  TargetListSampleRegressionType::Pointer m_tsl;
};

template <typename TPrecision>
struct BilinearFunctionSampleGenerator
{
  typedef TPrecision PrecisionType;
  BilinearFunctionSampleGenerator(TPrecision a, TPrecision b, TPrecision c)
    : m_a(a), m_b(b), m_c(c), m_NbInputVars(2), m_NbOutputVars(1) {
    m_isl = InputListSampleRegressionType::New();
    m_tsl = TargetListSampleRegressionType::New();
  };
  void GenerateSamples(TPrecision sMin, TPrecision sMax, size_t nbSamples)
  {
    m_isl->Clear();
    m_tsl->Clear();
    m_isl->SetMeasurementVectorSize(m_NbInputVars);
    m_tsl->SetMeasurementVectorSize(m_NbOutputVars);

    RandomGeneratorType::Pointer randomGenerator = RandomGeneratorType::GetInstance();
    InputSampleRegressionType inputSample;
    inputSample.SetSize(m_NbInputVars);
    TargetSampleRegressionType outputSample;

    TPrecision sampleStep = (sMax-sMin)/nbSamples;
    for(size_t i=0; i<nbSamples; ++i)
      {
      TPrecision x = randomGenerator->GetUniformVariate(0.0, 1.0) * static_cast<TPrecision>(nbSamples);
      TPrecision inputValue1 = sMin+ x*sampleStep;
      x = randomGenerator->GetUniformVariate(0.0, 1.0) * static_cast<TPrecision>(nbSamples);
      TPrecision inputValue2 = sMin+ x*sampleStep;
      inputSample[0] = inputValue1;
      inputSample[1] = inputValue2;
      outputSample[0] = m_a*inputValue1+m_b*inputValue2+m_c;
      m_isl->PushBack(inputSample);
      m_tsl->PushBack(outputSample);
      }
  }

  TPrecision m_a;
  TPrecision m_b;
  TPrecision m_c;
  const size_t m_NbInputVars;
  const size_t m_NbOutputVars;
  InputListSampleRegressionType::Pointer m_isl;
  TargetListSampleRegressionType::Pointer m_tsl;
};

template <typename TPrecision>
struct PolynomialFunctionSampleGenerator
{
  typedef TPrecision PrecisionType;
  PolynomialFunctionSampleGenerator(std::vector<TPrecision> c)
    : m_c(c), m_NbInputVars(1), m_NbOutputVars(1) {
    m_isl = InputListSampleRegressionType::New();
    m_tsl = TargetListSampleRegressionType::New();
  };
  void GenerateSamples(TPrecision sMin, TPrecision sMax, size_t nbSamples)
  {
    m_isl->Clear();
    m_tsl->Clear();
    m_isl->SetMeasurementVectorSize(m_NbInputVars);
    m_tsl->SetMeasurementVectorSize(m_NbOutputVars);

    RandomGeneratorType::Pointer randomGenerator = RandomGeneratorType::GetInstance();
    InputSampleRegressionType inputSample;
    inputSample.SetSize(m_NbInputVars);
    TargetSampleRegressionType outputSample;

    TPrecision sampleStep = (sMax-sMin)/nbSamples;
    for(size_t i=0; i<nbSamples; ++i)
      {
      TPrecision x = randomGenerator->GetUniformVariate(0.0, 1.0) * static_cast<TPrecision>(nbSamples);
      TPrecision inputValue = sMin+ x*sampleStep;
      inputSample[0] = inputValue;
      TPrecision y = 0.0;
      for (unsigned int j=0; j<m_c.size() ; ++j)
        {
        y += m_c[j] * pow(static_cast<double>(inputValue), static_cast<double>(j));
        }
      outputSample[0] = y;
      m_isl->PushBack(inputSample);
      m_tsl->PushBack(outputSample);
      }
  }

  std::vector<TPrecision> m_c;
  const size_t m_NbInputVars;
  const size_t m_NbOutputVars;
  InputListSampleRegressionType::Pointer m_isl;
  TargetListSampleRegressionType::Pointer m_tsl;
};

template <typename SampleGeneratorType, typename RegressionType>
int testRegression(SampleGeneratorType& sg, RegressionType& rgrsn, RegressionTestParam param)
{
  std::cout << "Generating training samples" << std::endl;
  sg.GenerateSamples(param.vMin, param.vMax, param.count);

  rgrsn->SetInputListSample(sg.m_isl);
  rgrsn->SetTargetListSample(sg.m_tsl);
  std::cout << "Training" << std::endl;
  rgrsn->Train();

  std::cout << "Generate validation samples"<<std::endl;
  sg.GenerateSamples(param.vMin, param.vMax, param.count);

  std::cout << "Validation" << std::endl;
  //Check the prediction accuracy
  typename InputListSampleRegressionType::Iterator sampleIt = sg.m_isl->Begin();
  typename TargetListSampleRegressionType::Iterator resultIt = sg.m_tsl->Begin();
  typename InputListSampleRegressionType::Iterator sampleLast = sg.m_isl->End();
  typename TargetListSampleRegressionType::Iterator resultLast = sg.m_tsl->End();
  typename SampleGeneratorType::PrecisionType rmse = 0.0;
  while(sampleIt != sampleLast && resultIt != resultLast)
    {
    //typename SampleGeneratorType::PrecisionType invalue = sampleIt.GetMeasurementVector()[0];
    typename SampleGeneratorType::PrecisionType prediction = rgrsn->Predict(sampleIt.GetMeasurementVector())[0];
    typename SampleGeneratorType::PrecisionType expected = resultIt.GetMeasurementVector()[0];
    rmse += pow(prediction - expected, 2.0);
    ++sampleIt;
    ++resultIt;
    }

  rmse = sqrt( rmse / static_cast<double>(param.count) );
  std::cout << "RMSE = "<< rmse << std::endl;
  if(rmse > param.eps)
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}

#ifdef OTB_USE_LIBSVM
int otbLibSVMRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::LibSVMMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    libsvmType;
  libsvmType::Pointer regression = libsvmType::New();
  regression->SetRegressionMode(true);
  regression->SetSVMType(EPSILON_SVR);
  regression->SetKernelType(RBF);
  regression->SetEpsilon(1e-5);
  regression->SetParameterOptimization(true);

  return testRegression(lfsg,regression,param);
}
#endif

#ifdef OTB_USE_OPENCV
int otbNeuralNetworkRegressionLinearMonovariate(int itkNotUsed(argc),
                                                char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 20000;
  param.eps = 0.1;

  typedef otb::NeuralNetworkMachineLearningModel<InputValueRegressionType,
                                                 TargetValueRegressionType>
    NeuralNetworkType;
  NeuralNetworkType::Pointer regression = NeuralNetworkType::New();

  regression->SetRegressionMode(1);
  regression->SetTrainMethod(CvANN_MLP_TrainParams::BACKPROP);
  std::vector<unsigned int> layerSizes;
  layerSizes.push_back(1);
  layerSizes.push_back(5);
  layerSizes.push_back(1);
  regression->SetLayerSizes(layerSizes);
  regression->SetActivateFunction(CvANN_MLP::SIGMOID_SYM);
  regression->SetAlpha(1.0);
  regression->SetBeta(1.0);
  regression->SetBackPropDWScale(0.1);
  regression->SetBackPropMomentScale(0.1);
  regression->SetRegPropDW0(0.1);
  regression->SetRegPropDWMin(1e-7);
  regression->SetTermCriteriaType(CV_TERMCRIT_EPS);
  regression->SetEpsilon(1e-5);
  regression->SetMaxIter(1e4);

  return testRegression(lfsg,regression,param);
}

int otbSVMRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::SVMMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    SVMType;
  SVMType::Pointer regression = SVMType::New();

  regression->SetRegressionMode(1);
  regression->SetNu(0.5);
  regression->SetKernelType(CvSVM::RBF);
  regression->SetTermCriteriaType(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS);
  regression->SetMaxIter(100000);
  regression->SetEpsilon(1e-5);
  regression->SetParameterOptimization(true);

  return testRegression(lfsg,regression,param);
}

int otbDecisionTreeRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::DecisionTreeMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    DTreeType;
  DTreeType::Pointer regression = DTreeType::New();
  regression->SetRegressionMode(true);

  return testRegression(lfsg,regression,param);
}

int otbGradientBoostedTreeRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::GradientBoostedTreeMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    GBTreeType;
  GBTreeType::Pointer regression = GBTreeType::New();
  regression->SetRegressionMode(true);
  regression->SetLossFunctionType(CvGBTrees::SQUARED_LOSS);

  return testRegression(lfsg,regression,param);
}

int otbKNearestNeighborsRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::KNearestNeighborsMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    KNNType;
  KNNType::Pointer regression = KNNType::New();
  regression->SetRegressionMode(true);
  regression->SetK(1);

  return testRegression(lfsg,regression,param);
}

int otbRandomForestsRegressionLinearMonovariate(int itkNotUsed(argc),
                                      char * itkNotUsed(argv) [])
{
  LinearFunctionSampleGenerator<PrecisionType> lfsg(2.0, 1.0);

  RegressionTestParam param;
  param.vMin = -0.5;
  param.vMax = 0.5;
  param.count = 200;
  param.eps = 0.1;

  typedef otb::RandomForestsMachineLearningModel<InputValueRegressionType,
                                       TargetValueRegressionType>
    RFType;
  RFType::Pointer regression = RFType::New();
  regression->SetRegressionMode(true);

  return testRegression(lfsg,regression,param);
}
#endif
<|endoftext|>


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

#include "config.h"
#include "core/platform/graphics/FontPlatformData.h"

#include "RuntimeEnabledFeatures.h"
#include "SkPaint.h"
#include "SkTypeface.h"
#include "SkTypeface_win.h"
#include "core/platform/graphics/FontCache.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/skia/SkiaFontWin.h"
#include "platform/LayoutTestSupport.h"
#include "platform/SharedBuffer.h"
#include "platform/win/HWndDC.h"
#include "public/platform/Platform.h"
#include "public/platform/win/WebSandboxSupport.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"
#include <mlang.h>
#include <objidl.h>
#include <windows.h>

namespace WebCore {

void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
{
    const float ts = m_textSize >= 0 ? m_textSize : 12;
    paint->setTextSize(SkFloatToScalar(m_textSize));
    paint->setTypeface(typeface());
    paint->setFakeBoldText(m_fakeBold);
    paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
    if (RuntimeEnabledFeatures::subpixelFontScalingEnabled())
        paint->setSubpixelText(true);

    // Only set painting flags when we're actually painting.
    if (context) {
        int textFlags = paintTextFlags();
        if (!context->couldUseLCDRenderedText()) {
            textFlags &= ~SkPaint::kLCDRenderText_Flag;
            // If we *just* clear our request for LCD, then GDI seems to
            // sometimes give us AA text, and sometimes give us BW text. Since the
            // original intent was LCD, we want to force AA (rather than BW), so we
            // add a special bit to tell Skia to do its best to avoid the BW: by
            // drawing LCD offscreen and downsampling that to AA.
            textFlags |= SkPaint::kGenA8FromLCD_Flag;
        }

        static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
            SkPaint::kLCDRenderText_Flag |
            SkPaint::kGenA8FromLCD_Flag;

        SkASSERT(!(textFlags & ~textFlagsMask));
        uint32_t flags = paint->getFlags();
        flags &= ~textFlagsMask;
        flags |= textFlags;
        paint->setFlags(flags);
    }
}

// Lookup the current system settings for font smoothing.
// We cache these values for performance, but if the browser has a way to be
// notified when these change, we could re-query them at that time.
static uint32_t getDefaultGDITextFlags()
{
    static bool gInited;
    static uint32_t gFlags;
    if (!gInited) {
        BOOL enabled;
        gFlags = 0;
        if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
            gFlags |= SkPaint::kAntiAlias_Flag;

            UINT smoothType;
            if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
                if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
                    gFlags |= SkPaint::kLCDRenderText_Flag;
            }
        }
        gInited = true;
    }
    return gFlags;
}

static bool isWebFont(const LOGFONT& lf)
{
    // web-fonts have artifical names constructed to always be
    // 1. 24 characters, followed by a '\0'
    // 2. the last two characters are '=='
    return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
}

static int computePaintTextFlags(const LOGFONT& lf)
{
    int textFlags = 0;
    switch (lf.lfQuality) {
    case NONANTIALIASED_QUALITY:
        textFlags = 0;
        break;
    case ANTIALIASED_QUALITY:
        textFlags = SkPaint::kAntiAlias_Flag;
        break;
    case CLEARTYPE_QUALITY:
        textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
        break;
    default:
        textFlags = getDefaultGDITextFlags();
        break;
    }

    // only allow features that SystemParametersInfo allows
    textFlags &= getDefaultGDITextFlags();

    /*
     *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
     *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
     *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
     *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
     *
     *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
     *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
     *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
     */
    if (isWebFont(lf) && !isRunningLayoutTest())
        textFlags |= SkPaint::kAntiAlias_Flag;
    return textFlags;
}

PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
{
    LOGFONT info;
    GetObject(hfont, sizeof(info), &info);
    if (size) {
        int height = info.lfHeight;
        if (height < 0)
            height = -height;
        *size = height;
    }
    if (paintTextFlags)
        *paintTextFlags = computePaintTextFlags(info);
    return adoptRef(SkCreateTypefaceFromLOGFONT(info));
}

FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    : m_font(0)
    , m_textSize(-1)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(true)
{
}

FontPlatformData::FontPlatformData()
    : m_font(0)
    , m_textSize(0)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

#if ENABLE(GDI_FONTS_ON_WINDOWS)
FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    : m_font(RefCountedHFONT::create(font))
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    , m_isHashTableDeletedValue(false)
{
}
#endif

// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    : m_font(0)
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data)
    : m_font(data.m_font)
    , m_textSize(data.m_textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    : m_font(data.m_font)
    , m_textSize(textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
    : m_font(0)
    , m_textSize(textSize)
    , m_fakeBold(fakeBold)
    , m_fakeItalic(fakeItalic)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(tf)
    , m_isHashTableDeletedValue(false)
{
    // FIXME: This can be removed together with m_font once the last few
    // uses of hfont() has been eliminated.
    LOGFONT logFont;
    SkLOGFONTFromTypeface(m_typeface.get(), &logFont);
    logFont.lfHeight = -textSize;
    HFONT hFont = CreateFontIndirect(&logFont);
    if (hFont)
        m_font = RefCountedHFONT::create(hFont);
    m_paintTextFlags = computePaintTextFlags(logFont);
}

FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
{
    if (this != &data) {
        m_font = data.m_font;
        m_textSize = data.m_textSize;
        m_fakeBold = data.m_fakeBold;
        m_fakeItalic = data.m_fakeItalic;
        m_orientation = data.m_orientation;
        m_typeface = data.m_typeface;
        m_paintTextFlags = data.m_paintTextFlags;

        // The following fields will get re-computed if necessary.
        ScriptFreeCache(&m_scriptCache);
        m_scriptCache = 0;
        m_scriptFontProperties.clear();
    }
    return *this;
}

FontPlatformData::~FontPlatformData()
{
    ScriptFreeCache(&m_scriptCache);
    m_scriptCache = 0;
}

String FontPlatformData::fontFamilyName() const
{
    HWndDC dc(0);
    HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    SelectObject(dc, oldFont);
    return String(name, resultLength);
}

bool FontPlatformData::isFixedPitch() const
{
#if ENABLE(GDI_FONTS_ON_WINDOWS)
    // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    HWndDC dc(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont());

    // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    // is *not* fixed pitch. Unbelievable but true.
    TEXTMETRIC textMetric = { 0 };
    if (!GetTextMetrics(dc, &textMetric)) {
        if (ensureFontLoaded(hfont())) {
            // Retry GetTextMetrics.
            // FIXME: Handle gracefully the error if this call also fails.
            // See http://crbug.com/6401.
            if (!GetTextMetrics(dc, &textMetric))
                LOG_ERROR("Unable to get the text metrics after second attempt");
        }
    }

    bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);

    SelectObject(dc, oldFont);

    return treatAsFixedPitch;
#else
    return typeface() && typeface()->isFixedPitch();
#endif
}

FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
{
    DeleteObject(m_hfont);
}

SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
{
    if (!m_scriptFontProperties) {
        m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
        memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
        m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
        HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
        if (result == E_PENDING) {
            HWndDC dc(0);
            HGDIOBJ oldFont = SelectObject(dc, hfont());
            HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
            if (S_OK != hr) {
                if (FontPlatformData::ensureFontLoaded(hfont())) {
                    // FIXME: Handle gracefully the error if this call also fails.
                    hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
                    if (S_OK != hr) {
                        LOG_ERROR("Unable to get the font properties after second attempt");
                    }
                }
            }

            SelectObject(dc, oldFont);
        }
    }
    return m_scriptFontProperties.get();
}

#ifndef NDEBUG
String FontPlatformData::description() const
{
    return String();
}
#endif

bool FontPlatformData::ensureFontLoaded(HFONT font)
{
    WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport();
    // if there is no sandbox, then we can assume the font
    // was able to be loaded successfully already
    return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
}

}
<commit_msg>Fixing leaked references in FontPlatformData<commit_after>/*
 * Copyright (C) 2006, 2007 Apple Computer, Inc.
 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/platform/graphics/FontPlatformData.h"

#include "RuntimeEnabledFeatures.h"
#include "SkPaint.h"
#include "SkTypeface.h"
#include "SkTypeface_win.h"
#include "core/platform/graphics/FontCache.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/skia/SkiaFontWin.h"
#include "platform/LayoutTestSupport.h"
#include "platform/SharedBuffer.h"
#include "platform/win/HWndDC.h"
#include "public/platform/Platform.h"
#include "public/platform/win/WebSandboxSupport.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"
#include <mlang.h>
#include <objidl.h>
#include <windows.h>

namespace WebCore {

void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
{
    const float ts = m_textSize >= 0 ? m_textSize : 12;
    paint->setTextSize(SkFloatToScalar(m_textSize));
    paint->setTypeface(typeface());
    paint->setFakeBoldText(m_fakeBold);
    paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
    if (RuntimeEnabledFeatures::subpixelFontScalingEnabled())
        paint->setSubpixelText(true);

    // Only set painting flags when we're actually painting.
    if (context) {
        int textFlags = paintTextFlags();
        if (!context->couldUseLCDRenderedText()) {
            textFlags &= ~SkPaint::kLCDRenderText_Flag;
            // If we *just* clear our request for LCD, then GDI seems to
            // sometimes give us AA text, and sometimes give us BW text. Since the
            // original intent was LCD, we want to force AA (rather than BW), so we
            // add a special bit to tell Skia to do its best to avoid the BW: by
            // drawing LCD offscreen and downsampling that to AA.
            textFlags |= SkPaint::kGenA8FromLCD_Flag;
        }

        static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
            SkPaint::kLCDRenderText_Flag |
            SkPaint::kGenA8FromLCD_Flag;

        SkASSERT(!(textFlags & ~textFlagsMask));
        uint32_t flags = paint->getFlags();
        flags &= ~textFlagsMask;
        flags |= textFlags;
        paint->setFlags(flags);
    }
}

// Lookup the current system settings for font smoothing.
// We cache these values for performance, but if the browser has a way to be
// notified when these change, we could re-query them at that time.
static uint32_t getDefaultGDITextFlags()
{
    static bool gInited;
    static uint32_t gFlags;
    if (!gInited) {
        BOOL enabled;
        gFlags = 0;
        if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
            gFlags |= SkPaint::kAntiAlias_Flag;

            UINT smoothType;
            if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
                if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
                    gFlags |= SkPaint::kLCDRenderText_Flag;
            }
        }
        gInited = true;
    }
    return gFlags;
}

static bool isWebFont(const LOGFONT& lf)
{
    // web-fonts have artifical names constructed to always be
    // 1. 24 characters, followed by a '\0'
    // 2. the last two characters are '=='
    return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
}

static int computePaintTextFlags(const LOGFONT& lf)
{
    int textFlags = 0;
    switch (lf.lfQuality) {
    case NONANTIALIASED_QUALITY:
        textFlags = 0;
        break;
    case ANTIALIASED_QUALITY:
        textFlags = SkPaint::kAntiAlias_Flag;
        break;
    case CLEARTYPE_QUALITY:
        textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
        break;
    default:
        textFlags = getDefaultGDITextFlags();
        break;
    }

    // only allow features that SystemParametersInfo allows
    textFlags &= getDefaultGDITextFlags();

    /*
     *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
     *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
     *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
     *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
     *
     *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
     *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
     *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
     */
    if (isWebFont(lf) && !isRunningLayoutTest())
        textFlags |= SkPaint::kAntiAlias_Flag;
    return textFlags;
}

PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
{
    LOGFONT info;
    GetObject(hfont, sizeof(info), &info);
    if (size) {
        int height = info.lfHeight;
        if (height < 0)
            height = -height;
        *size = height;
    }
    if (paintTextFlags)
        *paintTextFlags = computePaintTextFlags(info);
    return adoptRef(SkCreateTypefaceFromLOGFONT(info));
}

FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    : m_font(0)
    , m_textSize(-1)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(adoptRef(SkTypeface::RefDefault()))
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(true)
{
}

FontPlatformData::FontPlatformData()
    : m_font(0)
    , m_textSize(0)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(adoptRef(SkTypeface::RefDefault()))
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

#if ENABLE(GDI_FONTS_ON_WINDOWS)
FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    : m_font(RefCountedHFONT::create(font))
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    , m_isHashTableDeletedValue(false)
{
}
#endif

// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    : m_font(0)
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(adoptRef(SkTypeface::RefDefault()))
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data)
    : m_font(data.m_font)
    , m_textSize(data.m_textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    : m_font(data.m_font)
    , m_textSize(textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
    : m_font(0)
    , m_textSize(textSize)
    , m_fakeBold(fakeBold)
    , m_fakeItalic(fakeItalic)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(tf)
    , m_isHashTableDeletedValue(false)
{
    // FIXME: This can be removed together with m_font once the last few
    // uses of hfont() has been eliminated.
    LOGFONT logFont;
    SkLOGFONTFromTypeface(m_typeface.get(), &logFont);
    logFont.lfHeight = -textSize;
    HFONT hFont = CreateFontIndirect(&logFont);
    if (hFont)
        m_font = RefCountedHFONT::create(hFont);
    m_paintTextFlags = computePaintTextFlags(logFont);
}

FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
{
    if (this != &data) {
        m_font = data.m_font;
        m_textSize = data.m_textSize;
        m_fakeBold = data.m_fakeBold;
        m_fakeItalic = data.m_fakeItalic;
        m_orientation = data.m_orientation;
        m_typeface = data.m_typeface;
        m_paintTextFlags = data.m_paintTextFlags;

        // The following fields will get re-computed if necessary.
        ScriptFreeCache(&m_scriptCache);
        m_scriptCache = 0;
        m_scriptFontProperties.clear();
    }
    return *this;
}

FontPlatformData::~FontPlatformData()
{
    ScriptFreeCache(&m_scriptCache);
    m_scriptCache = 0;
}

String FontPlatformData::fontFamilyName() const
{
    HWndDC dc(0);
    HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    SelectObject(dc, oldFont);
    return String(name, resultLength);
}

bool FontPlatformData::isFixedPitch() const
{
#if ENABLE(GDI_FONTS_ON_WINDOWS)
    // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    HWndDC dc(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont());

    // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    // is *not* fixed pitch. Unbelievable but true.
    TEXTMETRIC textMetric = { 0 };
    if (!GetTextMetrics(dc, &textMetric)) {
        if (ensureFontLoaded(hfont())) {
            // Retry GetTextMetrics.
            // FIXME: Handle gracefully the error if this call also fails.
            // See http://crbug.com/6401.
            if (!GetTextMetrics(dc, &textMetric))
                LOG_ERROR("Unable to get the text metrics after second attempt");
        }
    }

    bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);

    SelectObject(dc, oldFont);

    return treatAsFixedPitch;
#else
    return typeface() && typeface()->isFixedPitch();
#endif
}

FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
{
    DeleteObject(m_hfont);
}

SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
{
    if (!m_scriptFontProperties) {
        m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
        memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
        m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
        HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
        if (result == E_PENDING) {
            HWndDC dc(0);
            HGDIOBJ oldFont = SelectObject(dc, hfont());
            HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
            if (S_OK != hr) {
                if (FontPlatformData::ensureFontLoaded(hfont())) {
                    // FIXME: Handle gracefully the error if this call also fails.
                    hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
                    if (S_OK != hr) {
                        LOG_ERROR("Unable to get the font properties after second attempt");
                    }
                }
            }

            SelectObject(dc, oldFont);
        }
    }
    return m_scriptFontProperties.get();
}

#ifndef NDEBUG
String FontPlatformData::description() const
{
    return String();
}
#endif

bool FontPlatformData::ensureFontLoaded(HFONT font)
{
    WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport();
    // if there is no sandbox, then we can assume the font
    // was able to be loaded successfully already
    return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
}

}
<|endoftext|>