<commit_before>#include "Ubidots.h"
static const uint16_t TIMEOUT = 2000;
/**
 * Constructor.
 */
ubidots::ubidots(char* token){
    _token = token;
    cache = (UbidotsCollection *) malloc(sizeof(UbidotsCollection));
    cache->first = NULL;
    pch = get_or_create_datasource();
}
Value * ubidots::init_value(char* name, double value, char * id){
   Value * new_value = (Value *)malloc(sizeof(Value));
    new_value->name = name;
    new_value->value = value;
    if (id == NULL){
        char* pch2 = get_or_create_variable(pch, name);
        new_value->id = pch2;

    }else{
        new_value->id = id;
    }

    return new_value;
}
void ubidots::add_value_with_name(UbidotsCollection *collection, char * name, double value){
   /* Si la lista está vacía */
   if(cache->first == NULL){
      /* Añadimos la lista a continuación del nuevo nodo */
      cache->first = init_value(name, value, NULL);
      /* Ahora, el comienzo de nuestra lista es en nuevo nodo */
   }else{
       Value * nod = cache->first;
        while(nod->next || name == nod->name) {
            if (name == nod->name){
                nod->value = value;
                return;
            }
            nod = nod->next;
        }

        nod->next = init_value(name, value, nod->id);

   }
}

void ubidots::add_value(UbidotsCollection *collection, char * variable_id, double value){

   /* Si la lista está vacía */
   if(cache->first == NULL){
      /* Añadimos la lista a continuación del nuevo nodo */
      cache->first = init_value(NULL, value, variable_id);
      /* Ahora, el comienzo de nuestra lista es en nuevo nodo */
   }else{
       Value *nod = cache->first;
        while(nod->next || variable_id == nod->id) {
            if (variable_id == nod->id){
                nod->value = value;
                return;
            }
            nod = nod->next;
        }
        nod->next = init_value(NULL, value, variable_id);

   }
}
/**
 * This function is to save infinite values in the API
 * @arg ID This array contains the datasource ID
 * @arg variableName  This contains the variable name
 * @return variable ID or NULL in bad connection
 */
bool ubidots::send_ubidots( int number, ... ){

   va_list vl;
   int i;
   char * data = (char *) malloc(sizeof(char) * number*50);
   va_start( vl, number );
   sprintf(data, "[");
   for( i = 0; i< number; ++i ){
       char* name = (char *) malloc(sizeof(char) *20);
       name = va_arg( vl, char* );
       float value = va_arg( vl, double );
       add_value_with_name(cache, name, value);

   }
   ubidots_collection_save(cache);
    return true;
}

/**
 * Save a collection.
 * @arg coll Collection to save.
 * @reutrn Zero upon success, non-zero upon error.
 */
int ubidots::ubidots_collection_save(UbidotsCollection *collection){
    char* chain = (char *) malloc(sizeof(char) * 700);
    char* endpoint= (char *) malloc(sizeof(char) * 100);
    char* data = (char *) malloc(sizeof(char) * 100);
    char* status = (char *) malloc(sizeof(char) * 3);
    char* body = (char *) malloc(sizeof(char) * 200);;
    sprintf(endpoint, "collections/values");
    sprintf(data, "[");

    Value *nod = cache->first;
    while(nod->next) {
    sprintf(data, "%s{\"variable\": \"%s\", \"value\":\"%f\"}", data, nod->id , nod->value);
    nod = nod->next;
    sprintf(data, "%s, ",data);
    }
    sprintf(data, "%s, ",data);

  #ifdef DEBUG_UBIDOTS
  Serial.println(data);
  #endif
  assemble_with_data("POST", chain, endpoint, data);
  if(!send_with_reconect(chain, status, body)){
        Serial.print("Connection error");
        return 1;
    }
  return 0;
}
/**
 * Cleanup a collection when after it is no longer being used.
 * @arg coll Pointer to the collection made by ubidots_collection_init().
 */
void ubidots::ubidots_collection_cleanup(UbidotsCollection *coll){
  /*for (i = 0; i < n; i++){
    free(coll->id[i]);
  }
  free(coll->id);
  free(coll->values);
  free(coll);*/
}
/**
 * This function is to assemble the data to send to Ubidots
 * @arg chain This array is to save all data to send to the API
 * @arg method   This array contains GET or POST method
 * @arg endpoint  This array contains the endpoint to send to the API
*/
void ubidots::assemble(char* chain, char* method, char* endpoint){
    sprintf(chain, "%s /api/v1.6/%s HTTP/1.1\nHost: %s\nUser-Agent: %s \nX-Auth-Token: %s", method, endpoint, BASE_URL, USER_AGENT, _token);
    #ifdef DEBUG_UBIDOTS
    Serial.println(chain);
    #endif
}
/**
 * This function is to assemble the data with length and value of variable
 * to send to Ubidots
 * @arg chain This array is to save all data to send to the API
 * @arg method   This array contains GET or POST method
 * @arg endpoint  This array contains the endpoint to send to the API
 * @arg data  This array contains the value to POST to the Ubidots API
*/
void ubidots::assemble_with_data(char* method, char* chain, char* endpoint, char* data){
    assemble(chain, method, endpoint);
    sprintf(chain,"%s\nContent-Type: application/json\nContent-Length:  %d\n\n%s\n", chain, strlen(data), data);
    #ifdef DEBUG_UBIDOTS
    Serial.println(chain);
    #endif
}
/**
 * This function is to get or post datasource
 * @return false when the connection fails
 */
char* ubidots::get_or_create_datasource(){
    char* chain = (char *) malloc(sizeof(char) * 700);
    char* endpoint= (char *) malloc(sizeof(char) * 100);
    char* data = (char *) malloc(sizeof(char) * 100);
    char* status = (char *) malloc(sizeof(char) * 3);
    char* body = (char *) malloc(sizeof(char) * 200);
    char * datasource = (char *) malloc(sizeof(char) * 24);
    char ID[24];
    String particleid = Particle.deviceID();
    particleid.toCharArray(ID, particleid.length());
    sprintf(endpoint, "datasources/?tag=%s", ID);
    assemble((char *) chain, (char *)"GET",(char *) endpoint); // send core id and check if it is living
    if(!send_with_reconect(chain, status, body)){
        Serial.print("Connection error");
        return NULL;
    }
    memset(chain, 0, sizeof(chain));
    datasource = parser_id(status, body);
    if(datasource==NULL && strstr(body,"\"count\": 0")!=NULL){
        memset(data, 0, sizeof(data));
        sprintf(data, "{\"name\": \"Particle\",\"tags\":[\"%s\"]}", ID);
        assemble_with_data("POST", chain, endpoint, data);
        send_with_reconect(chain, status, body);
    }
    return datasource;
}
/**
 * This function is to know the existence of variable
 * in the API
 * @arg ID This array contains the datasource ID
 * @arg variableName  This contains the variable name
 * @return variable ID or NULL in bad connection
 */
char* ubidots::get_or_create_variable(char* ID, char* variableName){
    char* chain = (char *) malloc(sizeof(char) * 700);
    char* endpoint= (char *) malloc(sizeof(char) * 100);
    char* data = (char *) malloc(sizeof(char) * 100);
    char* status = (char *) malloc(sizeof(char) * 3);
    char* body = (char *) malloc(sizeof(char) * 200);
    char* variable = (char *) malloc(sizeof(char) * 24);
    sprintf(endpoint, "datasources/%s/variables/?tag=%s", ID, variableName);
    assemble((char *) chain, (char *)"GET",(char *) endpoint); // send core id and check if it is living
    if(!send_with_reconect(chain, status, body)){
        #ifdef DEBUG_UBIDOTS
        Serial.print("Connection error");
        #endif
        return NULL;
    }
    variable = parser_id(status, body);
    if(variable==NULL && strstr(body,"\"count\": 0")!=NULL){
        memset(data, 0, sizeof(data));
        sprintf(data, "{\"name\": \"%s\",\"tags\":[\"%s\"]}", variableName, variableName);
        assemble_with_data("POST", chain, endpoint, data);
        send_with_reconect(chain, status, body);
    }
    return variable;
}
/**
 * This function is to know if there is spark ID
 * datasource in the API
 * @arg Status This array contains the connection status of
 * the API
 * @arg body   This array contains the body of the API
 * @arg datasource  This array is to save the ID of the API response
 * @return true if there is created ID, false if there is not created ID
 */
char* ubidots::parser_id(char* status, char* body){
    String raw_response(body);
    char* ID = (char *) malloc(sizeof(char) * 24);
    int bodyPos = raw_response.indexOf("\"id\": ");
    if(strstr(status, "200")!=NULL && strstr(body, "\"id\": ")!=NULL && strstr(body,"\"count\": 0")==NULL){
        raw_response.substring(bodyPos+7).toCharArray(ID, 25);
        #ifdef DEBUG_UBIDOTS
        Serial.println(ID);
        #endif
        return ID;
    }else{
        return NULL;
    }
}
/**
 * This function is verify the connection with the Ubidots server
 * @arg chain  This array contain the all data to send to Ubidots
 * @arg status This array is to save the status value of the connection
 * confirm the connection status, example 200, 201 or wathever.
 * @arg body  This array is to save the body that you get.
 * @return true upon success, false upon i>ATTEMPS
 */
bool ubidots::send_with_reconect(char* chain, char* status, char* body){
    int i = 0;
    while(!send(chain, status, body)){
        if(i > ATTEMPS){
            return false;
        }
        i++;
    }
    return true;
}
/* This function is to connect to the Ubidots API, and this one
 * saves the data that the API send you
 * @arg status This array is to save the information to
 * confirm the connection status, example 200, 201 or wathever.
 * @arg body  This array is to save the body that you get.
 * @return true upon success, false upon error
 */
boolean ubidots::send(char* chain, char* status, char* body){
    TCPClient client;
    int len_result = 2048;
    char result[len_result];
    unsigned int bufferPosition = 0;
    unsigned long lastRead = millis();
    bool error = false;
    bool timeout = false;
    memset(&result[0], 0, sizeof(result));
    if (client.connect("things.ubidots.com", 80)){        // Connect to the server
            client.print(chain);
            client.print("\n\n");
            client.flush();
        do {
            while (client.available()){
                char c = client.read();
                lastRead = millis();
                if (c == -1){
                    error = true;
                    Serial.println("HttpClient>\tError: No data available.");
                    break;
                }
                // Check that received character fits in buffer before storing.
                if (bufferPosition < sizeof(result)-1){
                    result[bufferPosition] = c;
                }
                bufferPosition++;
            }
            result[bufferPosition] = '\0'; // Null-terminate buffer
            // Check that there hasn't been more than 5s since last read.
            timeout = millis() - lastRead > TIMEOUT;
            // Unless there has been an error or timeout wait 200ms to allow server
            // to respond or close connection.
            if (!error && !timeout){
                delay(200);
            }
        }
        while (client.connected() && !timeout && !error);
        client.stop();
        // If result doesnt have any thing, return false
        if(result[0]=='\0'){
            #ifdef DEBUG_UBIDOTS
            Serial.println("Error when particle recive the data");
            #endif
            return false;
        }
        String raw_response(result);
        // Not super elegant way of finding the status code, but it works.
        raw_response.substring(9,12).toCharArray(status, 4);
        int bodyPos = raw_response.indexOf("\r\n\r\n");
        raw_response.substring(bodyPos+4).toCharArray(body, sizeof(int[200]));
        #ifdef DEBUG_UBIDOTS
        Serial.println(body);
        Serial.println(status);
        #endif
        return true;
    }

}
<commit_msg>fixed problem with constructor<commit_after>#include "Ubidots.h"
static const uint16_t TIMEOUT = 2000;
/**
 * Constructor.
 */
ubidots::ubidots(char* token){
    _token = token;
    cache = (UbidotsCollection *) malloc(sizeof(UbidotsCollection));
    cache->first = NULL;

}
Value * ubidots::init_value(char* name, double value, char * id){
   Value * new_value = (Value *)malloc(sizeof(Value));
    new_value->name = name;
    new_value->value = value;
    if (id == NULL){
        char* pch2 = get_or_create_variable(pch, name);
        Serial.println(pch2);
        new_value->id = pch2;

    }else{
        new_value->id = id;
    }

    return new_value;
}
void ubidots::add_value_with_name(UbidotsCollection *collection, char * name, double value){
   /* Si la lista está vacía */
   if(cache->first == NULL){
      /* Añadimos la lista a continuación del nuevo nodo */
      cache->first = init_value(name, value, NULL);
      /* Ahora, el comienzo de nuestra lista es en nuevo nodo */
   }else{
       Value * nod = cache->first;
        while(nod->next || name == nod->name) {
            if (name == nod->name){
                nod->value = value;
                return;
            }
            nod = nod->next;
        }

        nod->next = init_value(name, value, nod->id);

   }
}

void ubidots::add_value(UbidotsCollection *collection, char * variable_id, double value){

   /* Si la lista está vacía */
   if(cache->first == NULL){
      /* Añadimos la lista a continuación del nuevo nodo */
      cache->first = init_value(NULL, value, variable_id);
      /* Ahora, el comienzo de nuestra lista es en nuevo nodo */
   }else{
       Value *nod = cache->first;
        while(nod->next || variable_id == nod->id) {
            if (variable_id == nod->id){
                nod->value = value;
                return;
            }
            nod = nod->next;
        }
        nod->next = init_value(NULL, value, variable_id);

   }
}
/**
 * This function is to save infinite values in the API
 * @arg ID This array contains the datasource ID
 * @arg variableName  This contains the variable name
 * @return variable ID or NULL in bad connection
 */
bool ubidots::send_ubidots( int number, ... ){

   pch = get_or_create_datasource();
   Serial.println(pch);
   va_list vl;
   int i;
   char * data = (char *) malloc(sizeof(char) * number*50);
   va_start( vl, number );
   Serial.println("holiiiiiiii");
   sprintf(data, "[");
   for( i = 0; i< number; ++i ){
       char* name = (char *) malloc(sizeof(char) *20);
       name = va_arg( vl, char* );
       float value = va_arg( vl, double );
       add_value_with_name(cache, name, value);

   }
   ubidots_collection_save(cache);
    return true;
}

/**
 * Save a collection.
 * @arg coll Collection to save.
 * @reutrn Zero upon success, non-zero upon error.
 */
int ubidots::ubidots_collection_save(UbidotsCollection *collection){
    char* chain = (char *) malloc(sizeof(char) * 700);
    char* endpoint= (char *) malloc(sizeof(char) * 100);
    char* data = (char *) malloc(sizeof(char) * 100);
    char* status = (char *) malloc(sizeof(char) * 3);
    char* body = (char *) malloc(sizeof(char) * 200);;
    sprintf(endpoint, "collections/values");
    sprintf(data, "[");
    Value *nod = cache->first;
    while(nod->next) {
    sprintf(data, "%s{\"variable\": \"%s\", \"value\":\"%f\"}", data, nod->id , nod->value);
    nod = nod->next;
    sprintf(data, "%s, ",data);
    }
    sprintf(data, "%s, ",data);

  #ifdef DEBUG_UBIDOTS
  Serial.println(data);
  #endif
  assemble_with_data("POST", chain, endpoint, data);
  if(!send_with_reconect(chain, status, body)){
        Serial.print("Connection error");
        return 1;
    }
  return 0;
}
/**
 * Cleanup a collection when after it is no longer being used.
 * @arg coll Pointer to the collection made by ubidots_collection_init().
 */
void ubidots::ubidots_collection_cleanup(UbidotsCollection *coll){
  /*for (i = 0; i < n; i++){
    free(coll->id[i]);
  }
  free(coll->id);
  free(coll->values);
  free(coll);*/
}
/**
 * This function is to assemble the data to send to Ubidots
 * @arg chain This array is to save all data to send to the API
 * @arg method   This array contains GET or POST method
 * @arg endpoint  This array contains the endpoint to send to the API
*/
void ubidots::assemble(char* chain, char* method, char* endpoint){
    sprintf(chain, "%s /api/v1.6/%s HTTP/1.1\nHost: %s\nUser-Agent: %s \nX-Auth-Token: %s", method, endpoint, BASE_URL, USER_AGENT, _token);
    #ifdef DEBUG_UBIDOTS
    Serial.println(chain);
    #endif
}
/**
 * This function is to assemble the data with length and value of variable
 * to send to Ubidots
 * @arg chain This array is to save all data to send to the API
 * @arg method   This array contains GET or POST method
 * @arg endpoint  This array contains the endpoint to send to the API
 * @arg data  This array contains the value to POST to the Ubidots API
*/
void ubidots::assemble_with_data(char* method, char* chain, char* endpoint, char* data){
    assemble(chain, method, endpoint);
    sprintf(chain,"%s\nContent-Type: application/json\nContent-Length:  %d\n\n%s\n", chain, strlen(data), data);
    #ifdef DEBUG_UBIDOTS
    Serial.println(chain);
    #endif
}
/**
 * This function is to get or post datasource
 * @return false when the connection fails
 */
char* ubidots::get_or_create_datasource(){
    char* chain = (char *) malloc(sizeof(char) * 700);
    char* endpoint= (char *) malloc(sizeof(char) * 100);
    char* data = (char *) malloc(sizeof(char) * 100);
    char* status = (char *) malloc(sizeof(char) * 3);
    char* body = (char *) malloc(sizeof(char) * 200);
    char * datasource = (char *) malloc(sizeof(char) * 24);
    char ID[24];
    String particleid = Particle.deviceID();
    particleid.toCharArray(ID, particleid.length());
    sprintf(endpoint, "datasources/?tag=%s", ID);
    assemble((char *) chain, (char *)"GET",(char *) endpoint); // send core id and check if it is living
    if(!send_with_reconect(chain, status, body)){
        Serial.print("Connection error");
        return NULL;
    }
    memset(chain, 0, sizeof(chain));
    datasource = parser_id(status, body);
    if(datasource==NULL && strstr(body,"\"count\": 0")!=NULL){
        memset(data, 0, sizeof(data));
        sprintf(data, "{\"name\": \"Particle\",\"tags\":[\"%s\"]}", ID);
        assemble_with_data("POST", chain, endpoint, data);
        send_with_reconect(chain, status, body);
    }
    return datasource;
}
/**
 * This function is to know the existence of variable
 * in the API
 * @arg ID This array contains the datasource ID
 * @arg variableName  This contains the variable name
 * @return variable ID or NULL in bad connection
 */
char* ubidots::get_or_create_variable(char* ID, char* variableName){
    char* chain = (char *) malloc(sizeof(char) * 700);
    char* endpoint= (char *) malloc(sizeof(char) * 100);
    char* data = (char *) malloc(sizeof(char) * 100);
    char* status = (char *) malloc(sizeof(char) * 3);
    char* body = (char *) malloc(sizeof(char) * 200);
    char* variable = (char *) malloc(sizeof(char) * 24);
    sprintf(endpoint, "datasources/%s/variables/?tag=%s", ID, variableName);
    assemble((char *) chain, (char *)"GET",(char *) endpoint); // send core id and check if it is living
    if(!send_with_reconect(chain, status, body)){
        #ifdef DEBUG_UBIDOTS
        Serial.print("Connection error");
        #endif
        return NULL;
    }
    variable = parser_id(status, body);
    if(variable==NULL && strstr(body,"\"count\": 0")!=NULL){
        memset(data, 0, sizeof(data));
        sprintf(data, "{\"name\": \"%s\",\"tags\":[\"%s\"]}", variableName, variableName);
        assemble_with_data("POST", chain, endpoint, data);
        send_with_reconect(chain, status, body);
    }
    return variable;
}
/**
 * This function is to know if there is spark ID
 * datasource in the API
 * @arg Status This array contains the connection status of
 * the API
 * @arg body   This array contains the body of the API
 * @arg datasource  This array is to save the ID of the API response
 * @return true if there is created ID, false if there is not created ID
 */
char* ubidots::parser_id(char* status, char* body){
    String raw_response(body);
    char* ID = (char *) malloc(sizeof(char) * 24);
    int bodyPos = raw_response.indexOf("\"id\": ");
    if(strstr(status, "200")!=NULL && strstr(body, "\"id\": ")!=NULL && strstr(body,"\"count\": 0")==NULL){
        raw_response.substring(bodyPos+7).toCharArray(ID, 25);
        #ifdef DEBUG_UBIDOTS
        Serial.println(ID);
        #endif
        return ID;
    }else{
        return NULL;
    }
}
/**
 * This function is verify the connection with the Ubidots server
 * @arg chain  This array contain the all data to send to Ubidots
 * @arg status This array is to save the status value of the connection
 * confirm the connection status, example 200, 201 or wathever.
 * @arg body  This array is to save the body that you get.
 * @return true upon success, false upon i>ATTEMPS
 */
bool ubidots::send_with_reconect(char* chain, char* status, char* body){
    int i = 0;
    while(!send(chain, status, body)){
        if(i > ATTEMPS){
            return false;
        }
        i++;
    }
    return true;
}
/* This function is to connect to the Ubidots API, and this one
 * saves the data that the API send you
 * @arg status This array is to save the information to
 * confirm the connection status, example 200, 201 or wathever.
 * @arg body  This array is to save the body that you get.
 * @return true upon success, false upon error
 */
boolean ubidots::send(char* chain, char* status, char* body){
    TCPClient client;
    int len_result = 2048;
    char result[len_result];
    unsigned int bufferPosition = 0;
    unsigned long lastRead = millis();
    bool error = false;
    bool timeout = false;
    memset(&result[0], 0, sizeof(result));
    if (client.connect("things.ubidots.com", 80)){        // Connect to the server
            client.print(chain);
            client.print("\n\n");
            client.flush();
        do {
            while (client.available()){
                char c = client.read();
                lastRead = millis();
                if (c == -1){
                    error = true;
                    Serial.println("HttpClient>\tError: No data available.");
                    break;
                }
                // Check that received character fits in buffer before storing.
                if (bufferPosition < sizeof(result)-1){
                    result[bufferPosition] = c;
                }
                bufferPosition++;
            }
            result[bufferPosition] = '\0'; // Null-terminate buffer
            // Check that there hasn't been more than 5s since last read.
            timeout = millis() - lastRead > TIMEOUT;
            // Unless there has been an error or timeout wait 200ms to allow server
            // to respond or close connection.
            if (!error && !timeout){
                delay(200);
            }
        }
        while (client.connected() && !timeout && !error);
        client.stop();
        // If result doesnt have any thing, return false
        if(result[0]=='\0'){
            #ifdef DEBUG_UBIDOTS
            Serial.println("Error when particle recive the data");
            #endif
            return false;
        }
        String raw_response(result);
        // Not super elegant way of finding the status code, but it works.
        raw_response.substring(9,12).toCharArray(status, 4);
        int bodyPos = raw_response.indexOf("\r\n\r\n");
        raw_response.substring(bodyPos+4).toCharArray(body, sizeof(int[200]));
        #ifdef DEBUG_UBIDOTS
        Serial.println(body);
        Serial.println(status);
        #endif
        return true;
    }

}
<|endoftext|>


<commit_before>/*
* Copyright 2008, 2010, 2014 Free Software Foundation, Inc.
* Copyright 2014 Range Networks, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <config.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <sys/select.h>

#include "Defines.h"
#include "Threads.h"
#include "Sockets.h"
#include "Logger.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#include <string.h>
#include <stdlib.h>

SocketError::SocketError() {
	LOG(DEBUG) << "SocketError";
}

bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
{
	assert(address);
	assert(hostAndPort);
	char *copy = strdup(hostAndPort);
	char *colon = strchr(copy,':');
	if (!colon) {
		LOG(WARNING) << "missing port number in:"<<hostAndPort;
		return false;
	}
	*colon = '\0';
	char *host = copy;
	unsigned port = strtol(colon+1,NULL,10);
	bool retVal = resolveAddress(address,host,port);
	free(copy);
	return retVal;
}

bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
{
	assert(address);
	assert(host);
	// FIXME -- Need to ignore leading/trailing spaces in hostname.
	struct hostent *hp;
	int h_errno_local;
#ifdef HAVE_GETHOSTBYNAME2_R
	struct hostent hostData;
	char tmpBuffer[2048];

	// There are different flavors of gethostbyname_r(), but
	// latest Linux use the following form:
	if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
		LOG(WARNING) << "gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local);
		//CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
		return false;
	}
#else
	static Mutex sGethostbynameMutex;
	// gethostbyname() is NOT thread-safe, so we should use a mutex here.
	// Ideally it should be a global mutex for all non thread-safe socket
	// operations and it should protect access to variables such as
	// global h_errno.
	sGethostbynameMutex.lock();
	hp = gethostbyname(host);
	h_errno_local = h_errno;
	sGethostbynameMutex.unlock();
#endif
 	if (hp==NULL) {
		LOG(WARNING) << "gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local);
		return false;
	}
	if (hp->h_addrtype != AF_INET) {
		LOG(WARNING) << "gethostbyname() resolved " << host << " to something other then AF_INET";
 		return false;
 	}
	address->sin_family = hp->h_addrtype;		// Above guarantees it is AF_INET
	assert(sizeof(address->sin_addr) == hp->h_length);
	memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
	address->sin_port = htons(port);
	return true;
}

DatagramSocket::DatagramSocket()
{
	memset(mDestination, 0, sizeof(mDestination));
}

void DatagramSocket::nonblocking()
{
	fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
}

void DatagramSocket::blocking()
{
	fcntl(mSocketFD,F_SETFL,0);
}

void DatagramSocket::close()
{
	::close(mSocketFD);
}

DatagramSocket::~DatagramSocket()
{
	close();
}

int DatagramSocket::write( const char * message, size_t length )
{
	//assert(length<=MAX_UDP_LENGTH);	// (pat 8-2013) Removed on David's orders.
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mDestination, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::writeBack( const char * message, size_t length )
{
	//assert(length<=MAX_UDP_LENGTH);	// (pat 8-2013) Removed on David's orders.
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mSource, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::write( const char * message)
{
	size_t length=strlen(message)+1;
	return write(message,length);
}

int DatagramSocket::writeBack( const char * message)
{
	size_t length=strlen(message)+1;
	return writeBack(message,length);
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
{
	// (pat 8-2013) Dont assert!
	// assert(length<=MAX_UDP_LENGTH);
	// sendto is supposed to return an error if the packet is too long.
	int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::send() failed");
	return retVal;
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message)
{
	size_t length=strlen(message)+1;
	return send(dest,message,length);
}

int DatagramSocket::read(char* buffer)
{
	socklen_t temp_len = sizeof(mSource);
	int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
	    (struct sockaddr*)&mSource,&temp_len);
	if ((length==-1) && (errno!=EAGAIN)) {
		perror("DatagramSocket::read() failed");
		devassert(0);
		throw SocketError();
	}
	return length;
}

int DatagramSocket::read(char* buffer, unsigned timeout)
{
	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(mSocketFD,&fds);
	struct timeval tv;
	tv.tv_sec = timeout/1000;
	tv.tv_usec = (timeout%1000)*1000;
	int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
	if (sel<0) {
		perror("DatagramSocket::read() select() failed");
		devassert(0);
		throw SocketError();
	}
	if (sel==0) return -1;
	if (FD_ISSET(mSocketFD,&fds)) return read(buffer);
	return -1;
}

UDPSocket::UDPSocket(unsigned short wSrcPort)
	:DatagramSocket()
{
	open(wSrcPort);
}

UDPSocket::UDPSocket(unsigned short wSrcPort,
          	 const char * wDestIP, unsigned short wDestPort )
	:DatagramSocket()
{
	open(wSrcPort);
	destination(wDestPort, wDestIP);
}

void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
{
	resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
}

void UDPSocket::open(unsigned short localPort)
{
	// create
	mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		devassert(0);
		throw SocketError();
	}

	// pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
	int on = 1;
	setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	// bind
	struct sockaddr_in address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sin_family = AF_INET;
	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_port = htons(localPort);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		char buf[100];
		sprintf(buf,"bind(port %d) failed",localPort);
		perror(buf);
		devassert(0);
		throw SocketError();
	}
}

unsigned short UDPSocket::port() const
{
	struct sockaddr_in name;
	socklen_t nameSize = sizeof(name);
	int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
	if (retVal==-1) {
		devassert(0);
		throw SocketError();
	}
	return ntohs(name.sin_port);
}

UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
	:DatagramSocket()
{
	if (localPath!=NULL) open(localPath);
	if (remotePath!=NULL) destination(remotePath);
}

void UDDSocket::open(const char* localPath)
{
	// create
	mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		devassert(0);
		throw SocketError();
	}

	// bind
	struct sockaddr_un address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path,localPath);
	unlink(localPath);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		char buf[1100];
		sprintf(buf,"bind(path %s) failed",localPath);
		perror(buf);
		devassert(0);
		throw SocketError();
	}
}

void UDDSocket::destination(const char* remotePath)
{
	struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
	strcpy(unAddr->sun_path,remotePath);
}

// vim:ts=4:sw=4
<commit_msg>common: Restrict UDP binding to localhost only<commit_after>/*
* Copyright 2008, 2010, 2014 Free Software Foundation, Inc.
* Copyright 2014 Range Networks, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <config.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <sys/select.h>

#include "Defines.h"
#include "Threads.h"
#include "Sockets.h"
#include "Logger.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#include <string.h>
#include <stdlib.h>

SocketError::SocketError() {
	LOG(DEBUG) << "SocketError";
}

bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
{
	assert(address);
	assert(hostAndPort);
	char *copy = strdup(hostAndPort);
	char *colon = strchr(copy,':');
	if (!colon) {
		LOG(WARNING) << "missing port number in:"<<hostAndPort;
		return false;
	}
	*colon = '\0';
	char *host = copy;
	unsigned port = strtol(colon+1,NULL,10);
	bool retVal = resolveAddress(address,host,port);
	free(copy);
	return retVal;
}

bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
{
	assert(address);
	assert(host);
	// FIXME -- Need to ignore leading/trailing spaces in hostname.
	struct hostent *hp;
	int h_errno_local;
#ifdef HAVE_GETHOSTBYNAME2_R
	struct hostent hostData;
	char tmpBuffer[2048];

	// There are different flavors of gethostbyname_r(), but
	// latest Linux use the following form:
	if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
		LOG(WARNING) << "gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local);
		//CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
		return false;
	}
#else
	static Mutex sGethostbynameMutex;
	// gethostbyname() is NOT thread-safe, so we should use a mutex here.
	// Ideally it should be a global mutex for all non thread-safe socket
	// operations and it should protect access to variables such as
	// global h_errno.
	sGethostbynameMutex.lock();
	hp = gethostbyname(host);
	h_errno_local = h_errno;
	sGethostbynameMutex.unlock();
#endif
 	if (hp==NULL) {
		LOG(WARNING) << "gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local);
		return false;
	}
	if (hp->h_addrtype != AF_INET) {
		LOG(WARNING) << "gethostbyname() resolved " << host << " to something other then AF_INET";
 		return false;
 	}
	address->sin_family = hp->h_addrtype;		// Above guarantees it is AF_INET
	assert(sizeof(address->sin_addr) == hp->h_length);
	memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
	address->sin_port = htons(port);
	return true;
}

DatagramSocket::DatagramSocket()
{
	memset(mDestination, 0, sizeof(mDestination));
}

void DatagramSocket::nonblocking()
{
	fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
}

void DatagramSocket::blocking()
{
	fcntl(mSocketFD,F_SETFL,0);
}

void DatagramSocket::close()
{
	::close(mSocketFD);
}

DatagramSocket::~DatagramSocket()
{
	close();
}

int DatagramSocket::write( const char * message, size_t length )
{
	//assert(length<=MAX_UDP_LENGTH);	// (pat 8-2013) Removed on David's orders.
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mDestination, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::writeBack( const char * message, size_t length )
{
	//assert(length<=MAX_UDP_LENGTH);	// (pat 8-2013) Removed on David's orders.
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mSource, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::write( const char * message)
{
	size_t length=strlen(message)+1;
	return write(message,length);
}

int DatagramSocket::writeBack( const char * message)
{
	size_t length=strlen(message)+1;
	return writeBack(message,length);
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
{
	// (pat 8-2013) Dont assert!
	// assert(length<=MAX_UDP_LENGTH);
	// sendto is supposed to return an error if the packet is too long.
	int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::send() failed");
	return retVal;
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message)
{
	size_t length=strlen(message)+1;
	return send(dest,message,length);
}

int DatagramSocket::read(char* buffer)
{
	socklen_t temp_len = sizeof(mSource);
	int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
	    (struct sockaddr*)&mSource,&temp_len);
	if ((length==-1) && (errno!=EAGAIN)) {
		perror("DatagramSocket::read() failed");
		devassert(0);
		throw SocketError();
	}
	return length;
}

int DatagramSocket::read(char* buffer, unsigned timeout)
{
	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(mSocketFD,&fds);
	struct timeval tv;
	tv.tv_sec = timeout/1000;
	tv.tv_usec = (timeout%1000)*1000;
	int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
	if (sel<0) {
		perror("DatagramSocket::read() select() failed");
		devassert(0);
		throw SocketError();
	}
	if (sel==0) return -1;
	if (FD_ISSET(mSocketFD,&fds)) return read(buffer);
	return -1;
}

UDPSocket::UDPSocket(unsigned short wSrcPort)
	:DatagramSocket()
{
	open(wSrcPort);
}

UDPSocket::UDPSocket(unsigned short wSrcPort,
          	 const char * wDestIP, unsigned short wDestPort )
	:DatagramSocket()
{
	open(wSrcPort);
	destination(wDestPort, wDestIP);
}

void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
{
	resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
}

void UDPSocket::open(unsigned short localPort)
{
	// create
	mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		devassert(0);
		throw SocketError();
	}

	// pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
	int on = 1;
	setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	// bind
	struct sockaddr_in address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sin_family = AF_INET;
	address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	address.sin_port = htons(localPort);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		char buf[100];
		sprintf(buf,"bind(port %d) failed",localPort);
		perror(buf);
		devassert(0);
		throw SocketError();
	}
}

unsigned short UDPSocket::port() const
{
	struct sockaddr_in name;
	socklen_t nameSize = sizeof(name);
	int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
	if (retVal==-1) {
		devassert(0);
		throw SocketError();
	}
	return ntohs(name.sin_port);
}

UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
	:DatagramSocket()
{
	if (localPath!=NULL) open(localPath);
	if (remotePath!=NULL) destination(remotePath);
}

void UDDSocket::open(const char* localPath)
{
	// create
	mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		devassert(0);
		throw SocketError();
	}

	// bind
	struct sockaddr_un address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path,localPath);
	unlink(localPath);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		char buf[1100];
		sprintf(buf,"bind(path %s) failed",localPath);
		perror(buf);
		devassert(0);
		throw SocketError();
	}
}

void UDDSocket::destination(const char* remotePath)
{
	struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
	strcpy(unAddr->sun_path,remotePath);
}

// vim:ts=4:sw=4
<|endoftext|>


<commit_before>#ifndef AX_3_DIMENTIONAL_VECTOR_H
#define AX_3_DIMENTIONAL_VECTOR_H
#include "Vector.hpp"

namespace ax
{
    template <>
    class RealVector<3>
    {
        public:
            using value_trait = Vector;
            constexpr static std::size_t size = 3;

        public:

            RealVector()
                : values({{0e0, 0e0, 0e0}})
            {}

            RealVector(double d)
                : values({{d, d, d}})
            {}

            RealVector(double x, double y, double z)
                : values({{x, y, z}})
            {}

            RealVector(const std::array<double, 3>& array)
                : values(array)
            {}

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector(const E& exp)
            {
                (*this)[0] = exp[0];
                (*this)[1] = exp[1];
                (*this)[2] = exp[2];
            }

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector& operator=(const E& exp)
            {
                (*this)[0] = exp[0];
                (*this)[1] = exp[1];
                (*this)[2] = exp[2];
                return *this;
            }

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector& operator+=(const E& exp)
            {
                *this = VectorAdd<RealVector, E>(*this, exp);
                return *this;
            }

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector& operator-=(const E& exp)
            {
                *this = VectorSub<RealVector, E>(*this, exp);
                return *this;
            }

            template<class E, typename std::enable_if<
                         is_ScalarType<E>::value>::type*& = enabler>
            RealVector& operator*=(const E& exp)
            {
                *this = VectorSclMul<RealVector>(*this, exp);
                return *this;
            }

            template<class E, typename std::enable_if<
                         is_ScalarType<E>::value>::type*& = enabler>
            RealVector& operator/=(const E& exp)
            {
                *this = VectorSclDiv<RealVector>(*this, exp);
                return *this;
            }

            double operator[](const std::size_t i) const
            {
                return values[i];
            }

            double& operator[](const std::size_t i)
            {
                return values[i];
            }

        private:
            std::array<double, 3> values;
    };
    using Realvec = RealVector<3>;
}
#endif//AX_VECTOR_H
<commit_msg>fix *= operator in Vector3d<commit_after>#ifndef AX_3_DIMENTIONAL_VECTOR_H
#define AX_3_DIMENTIONAL_VECTOR_H
#include "Vector.hpp"

namespace ax
{
    template <>
    class RealVector<3>
    {
        public:
            using value_trait = Vector;
            constexpr static std::size_t size = 3;

        public:

            RealVector()
                : values({{0e0, 0e0, 0e0}})
            {}

            RealVector(double d)
                : values({{d, d, d}})
            {}

            RealVector(double x, double y, double z)
                : values({{x, y, z}})
            {}

            RealVector(const std::array<double, 3>& array)
                : values(array)
            {}

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector(const E& exp)
            {
                (*this)[0] = exp[0];
                (*this)[1] = exp[1];
                (*this)[2] = exp[2];
            }

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector& operator=(const E& exp)
            {
                (*this)[0] = exp[0];
                (*this)[1] = exp[1];
                (*this)[2] = exp[2];
                return *this;
            }

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector& operator+=(const E& exp)
            {
                *this = VectorAdd<RealVector, E>(*this, exp);
                return *this;
            }

            template<class E,
                     typename std::enable_if<
                         is_VectorExpression<typename E::value_trait>::value&&
                         is_SameSize<E::size, 3>::value
                         >::type*& = enabler>
            RealVector& operator-=(const E& exp)
            {
                *this = VectorSub<RealVector, E>(*this, exp);
                return *this;
            }

            template<class E, typename std::enable_if<
                         is_ScalarType<E>::value>::type*& = enabler>
            RealVector& operator*=(const E& exp)
            {
                *this = VectorSclMul<RealVector>(exp, *this);
                return *this;
            }

            template<class E, typename std::enable_if<
                         is_ScalarType<E>::value>::type*& = enabler>
            RealVector& operator/=(const E& exp)
            {
                *this = VectorSclDiv<RealVector>(*this, exp);
                return *this;
            }

            double operator[](const std::size_t i) const
            {
                return values[i];
            }

            double& operator[](const std::size_t i)
            {
                return values[i];
            }

        private:
            std::array<double, 3> values;
    };
    using Realvec = RealVector<3>;
}
#endif//AX_VECTOR_H
<|endoftext|>


<commit_before>#ifndef _SNARKFRONT_SHA_384_HPP_
#define _SNARKFRONT_SHA_384_HPP_

#include <array>
#include <cstdint>
#include "Alg.hpp"
#include "Alg_uint.hpp"
#include "AST.hpp"
#include "BitwiseOps.hpp"
#include "Lazy.hpp"
#include "SHA_512.hpp"

namespace snarkfront {

////////////////////////////////////////////////////////////////////////////////
// SHA-384
//

template <typename T, typename MSG, typename U, typename F>
class SHA_384 : public SHA_512<T, MSG, U, F>
{
public:
    typedef T WordType;
    typedef U ByteType;

    typedef std::array<T, 16> MsgType;
    typedef std::array<T, 6> DigType;
    typedef std::array<U, 16 * 8> PreType;

    SHA_384()
        : m_setDigest(false)
    {}

    // overrides base class SHA-512
    const std::array<T, 6>& digest() {
        if (m_setDigest) {
            for (std::size_t i = 0; i < 6; ++i) {
                m_Hleft384[i] = this->m_H[i];
            }

            m_setDigest = false;
        }

        return m_Hleft384;
    }

    // overrides base class SHA-512
    virtual void initHashValue() {
        // set initial hash value (NIST FIPS 180-4 section 5.3.4)
        const std::array<uint64_t, 8> a {
            0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
            0x9159015a3070dd17, 0x152fecd8f70e5939,

            0x67332667ffc00b31, 0x8eb44a8768581511,
            0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 };

        for (std::size_t i = 0; i < 8; ++i) {
            this->m_H[i] = F::constant(a[i]);
        }
    }

    virtual void afterHash() {
        m_setDigest = true;
    }

private:
    // truncated 384-bit message digest
    std::array<T, 6> m_Hleft384;

    bool m_setDigest;
};

////////////////////////////////////////////////////////////////////////////////
// typedefs
//

namespace zk {
    template <typename FR> using
    SHA384 = SHA_384<AST_Var<Alg_uint64<FR>>,
                     Lazy<AST_Var<Alg_uint64<FR>>, std::uint64_t>,
                     AST_Var<Alg_uint8<FR>>,
                     SHA_Functions<AST_Node<Alg_uint64<FR>>,
                                   AST_Op<Alg_uint64<FR>>,
                                   BitwiseAST<Alg_uint64<FR>>>>;
} // namespace zk

namespace eval {
typedef SHA_384<std::uint64_t,
                std::uint64_t,
                std::uint8_t,
                SHA_Functions<std::uint64_t,
                              std::uint64_t,
                              BitwiseINT<std::uint64_t>>>
    SHA384;
} // namespace eval

} // namespace snarkfront

#endif
<commit_msg>refactor BitwiseOps.hpp<commit_after>#ifndef _SNARKFRONT_SHA_384_HPP_
#define _SNARKFRONT_SHA_384_HPP_

#include <array>
#include <cstdint>
#include "Alg.hpp"
#include "Alg_uint.hpp"
#include "AST.hpp"
#include "BitwiseAST.hpp"
#include "BitwiseINT.hpp"
#include "Lazy.hpp"
#include "SHA_512.hpp"

namespace snarkfront {

////////////////////////////////////////////////////////////////////////////////
// SHA-384
//

template <typename T, typename MSG, typename U, typename F>
class SHA_384 : public SHA_512<T, MSG, U, F>
{
public:
    typedef T WordType;
    typedef U ByteType;

    typedef std::array<T, 16> MsgType;
    typedef std::array<T, 6> DigType;
    typedef std::array<U, 16 * 8> PreType;

    SHA_384()
        : m_setDigest(false)
    {}

    // overrides base class SHA-512
    const std::array<T, 6>& digest() {
        if (m_setDigest) {
            for (std::size_t i = 0; i < 6; ++i) {
                m_Hleft384[i] = this->m_H[i];
            }

            m_setDigest = false;
        }

        return m_Hleft384;
    }

    // overrides base class SHA-512
    virtual void initHashValue() {
        // set initial hash value (NIST FIPS 180-4 section 5.3.4)
        const std::array<uint64_t, 8> a {
            0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
            0x9159015a3070dd17, 0x152fecd8f70e5939,

            0x67332667ffc00b31, 0x8eb44a8768581511,
            0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 };

        for (std::size_t i = 0; i < 8; ++i) {
            this->m_H[i] = F::constant(a[i]);
        }
    }

    virtual void afterHash() {
        m_setDigest = true;
    }

private:
    // truncated 384-bit message digest
    std::array<T, 6> m_Hleft384;

    bool m_setDigest;
};

////////////////////////////////////////////////////////////////////////////////
// typedefs
//

namespace zk {
    template <typename FR> using
    SHA384 = SHA_384<AST_Var<Alg_uint64<FR>>,
                     Lazy<AST_Var<Alg_uint64<FR>>, std::uint64_t>,
                     AST_Var<Alg_uint8<FR>>,
                     SHA_Functions<AST_Node<Alg_uint64<FR>>,
                                   AST_Op<Alg_uint64<FR>>,
                                   BitwiseAST<Alg_uint64<FR>>>>;
} // namespace zk

namespace eval {
typedef SHA_384<std::uint64_t,
                std::uint64_t,
                std::uint8_t,
                SHA_Functions<std::uint64_t,
                              std::uint64_t,
                              BitwiseINT<std::uint64_t>>>
    SHA384;
} // namespace eval

} // namespace snarkfront

#endif
<|endoftext|>


<commit_before>#include <algorithm>    // for std::sort
#include "ac_slow.hpp"
#include "ac_fast.hpp"

uint32
AC_Converter::Calc_State_Sz(const ACS_State* s) const {
    AC_State dummy;
    uint32 sz = offsetof(AC_State, input_vect);
    sz += s->Get_GotoNum() * sizeof(dummy.input_vect[0]);

    if (sz < sizeof(AC_State))
        sz = sizeof(AC_State);

    uint32 align = __alignof__(dummy);
    sz = (sz + align - 1) & ~(align - 1);
    return sz;
}

AC_Buffer*
AC_Converter::Alloc_Buffer() {
    const vector<ACS_State*>& all_states = _acs.Get_All_States();
    const ACS_State* root_state = _acs.Get_Root_State();
    uint32 root_fanout = root_state->Get_GotoNum();

    // Step 1: Calculate the buffer size
    AC_Ofst root_goto_ofst, states_ofst_ofst, first_state_ofst;

    // part 1 :  buffer header
    uint32 sz = root_goto_ofst = sizeof(AC_Buffer);

    // part 2: Root-node's goto function
    if (likely(root_fanout != 255))
        sz += 256;
    else
        root_goto_ofst = 0;

    // part 3: mapping of state's relative position.
    unsigned align = __alignof__(AC_Ofst);
    sz = (sz + align - 1) & ~(align - 1);
    states_ofst_ofst = sz;

    sz += sizeof(AC_Ofst) * all_states.size();

    // part 4: state's contents
    align = __alignof__(AC_State);
    sz = (sz + align - 1) & ~(align - 1);
    first_state_ofst = sz;

    uint32 state_sz = 0;
    for (vector<ACS_State*>::const_iterator i = all_states.begin(),
            e = all_states.end(); i != e; i++) {
        state_sz += Calc_State_Sz(*i);
    }
    state_sz -= Calc_State_Sz(root_state);

    sz += state_sz;

    // Step 2: Allocate buffer, and populate header.
    AC_Buffer* buf = _buf_alloc.alloc(sz);

    buf->hdr.magic_num = AC_MAGIC_NUM;
    buf->hdr.impl_variant = IMPL_FAST_VARIANT;
    buf->buf_len = sz;
    buf->root_goto_ofst = root_goto_ofst;
    buf->states_ofst_ofst = states_ofst_ofst;
    buf->first_state_ofst = first_state_ofst;
    buf->root_goto_num = root_fanout;
    buf->state_num = _acs.Get_State_Num();
    return buf;
}

void
AC_Converter::Populate_Root_Goto_Func(AC_Buffer* buf,
                                      GotoVect& goto_vect) {
    unsigned char *buf_base = (unsigned char*)(buf);
    InputTy* root_gotos = (InputTy*)(buf_base + buf->root_goto_ofst);
    const ACS_State* root_state = _acs.Get_Root_State();

    root_state->Get_Sorted_Gotos(goto_vect);

    // Renumber the ID of root-node's immediate kids.
    uint32 new_id = 1;
    bool full_fantout = (goto_vect.size() == 255);
    if (likely(!full_fantout))
        bzero(root_gotos, 256*sizeof(InputTy));

    for (GotoVect::iterator i = goto_vect.begin(), e = goto_vect.end();
            i != e; i++, new_id++) {
        InputTy c = i->first;
        ACS_State* s = i->second;
        _id_map[s->Get_ID()] = new_id;

        if (likely(!full_fantout))
            root_gotos[c] = new_id;
    }
}

AC_Buffer*
AC_Converter::Convert() {
    // Step 1: Some preparation stuff.
    GotoVect gotovect;

    _id_map.clear();
    _ofst_map.clear();
    _id_map.resize(_acs.Get_Next_Node_Id());
    _ofst_map.resize(_acs.Get_Next_Node_Id());

    // Step 2: allocate buffer to accommodate the entire AC graph.
    AC_Buffer* buf = Alloc_Buffer();
    unsigned char* buf_base = (unsigned char*)buf;

    // Step 3: Root node need special care.
    Populate_Root_Goto_Func(buf, gotovect);
    buf->root_goto_num = gotovect.size();
    _id_map[_acs.Get_Root_State()->Get_ID()] = 0;

    // Step 4: Converting the remaining states by BFSing the graph.
    // First of all, enter root's immediate kids to the working list.
    vector<const ACS_State*> wl;
    State_ID id = 1;
    for (GotoVect::iterator i = gotovect.begin(), e = gotovect.end();
            i != e; i++, id++) {
        ACS_State* s = i->second;
        wl.push_back(s);
        _id_map[s->Get_ID()] = id;
    }

    AC_Ofst* state_ofst_vect = (AC_Ofst*)(buf_base + buf->states_ofst_ofst);
    AC_Ofst ofst = buf->first_state_ofst;
    for (uint32 idx = 0; idx < wl.size(); idx++) {
        const ACS_State* old_s = wl[idx];
        AC_State* new_s = (AC_State*)(buf_base + ofst);

        // This property should hold as we:
        //  - States are appended to worklist in the BFS order.
        //  - sibiling states are appended to worklist in the order of their
        //    corresponding input.
        //
        State_ID state_id = idx + 1;
        ASSERT(_id_map[old_s->Get_ID()] == state_id);

        state_ofst_vect[state_id] = ofst;

        new_s->first_kid = wl.size() + 1;
        new_s->depth = old_s->Get_Depth();
        new_s->is_term = old_s->is_Terminal() ? 1 : 0;

        uint32 gotonum = old_s->Get_GotoNum();
        new_s->goto_num = gotonum;

        // Populate the "input" field
        old_s->Get_Sorted_Gotos(gotovect);
        uint32 input_idx = 0;
        uint32 id = wl.size() + 1;
        InputTy* input_vect = new_s->input_vect;
        for (GotoVect::iterator i = gotovect.begin(), e = gotovect.end();
             i != e; i++, id++, input_idx++) {
            input_vect[input_idx] = i->first;

            ACS_State* kid = i->second;
            _id_map[kid->Get_ID()] = id;
            wl.push_back(kid);
        }

        _ofst_map[old_s->Get_ID()] = ofst;
        ofst += Calc_State_Sz(old_s);
    }

    // Populate the fail-link field.
    for (vector<const ACS_State*>::iterator i = wl.begin(), e = wl.end();
            i != e; i++) {
        const ACS_State* slow_s = *i;
        State_ID fast_s_id = _id_map[slow_s->Get_ID()];
        AC_State* fast_s = (AC_State*)(buf_base + state_ofst_vect[fast_s_id]);
        if (const ACS_State* fl = slow_s->Get_FailLink()) {
            State_ID id = _id_map[fl->Get_ID()];
            fast_s->fail_link = id;
        } else
            fast_s->fail_link = 0;
    }
#ifdef DEBUG
    //dump_buffer(buf, stderr);
#endif
    return buf;
}

static inline AC_State*
Get_State_Addr(unsigned char* buf_base, AC_Ofst* StateOfstVect, uint32 state_id) {
    ASSERT(state_id != 0 && "root node is handled in speical way");
    ASSERT(state_id < ((AC_Buffer*)buf_base)->state_num);
    return (AC_State*)(buf_base + StateOfstVect[state_id]);
}

#if BS_MULTI_VER
// This function seems to be significantly faster than the variant in
// !BS_MULTI_VER directive.
static bool __attribute__((always_inline))
Binary_Search_Input(InputTy* input_vect, int vect_len, InputTy input, int& idx) {
    if (vect_len <= 4) {
        for (int i = 0; i < vect_len; i++)
            if (input_vect[i] == input) {
                idx = i;
                return true;
            }
        return false;
    }

    int low = 0, high = vect_len - 1;
    int input_s = (unsigned)input;
    while (low <= high) {
        uint32 mid = (low + high)/2;
        int mid_c = (unsigned)(input_vect[mid]);

        int diff = input_s - mid_c;
        if (diff) {
            int if_less = diff >> 8;
            high -= (high - (mid - 1)) & if_less;
            low += (mid + 1 - low) & ~if_less;
        } else {
            idx = mid;
            return true;
        }
    }
    return false;
}

#else
static inline bool
Binary_Search_Input(InputTy* input_vect, int vect_len, InputTy input, int& idx) {
    int low = 0, high = vect_len - 1;
    while (low <= high) {
        uint32 mid = (low + high)/2;
        InputTy mid_c = input_vect[mid];

        if (input < mid_c)
            high = mid - 1;
        else if (input > mid_c)
            low = mid + 1;
        else {
            idx = mid;
            return true;
        }
    }
    return false;
}
#endif

ac_result_t
Match(AC_Buffer* buf, const char* str, uint32 len) {
    unsigned char* buf_base = (unsigned char*)(buf);
    unsigned char* root_goto = buf_base + buf->root_goto_ofst;
    AC_Ofst* states_ofst_vect = (AC_Ofst* )(buf_base + buf->states_ofst_ofst);

    AC_State* state = 0;
    uint32 idx = 0;

    // Skip leading chars that are not valid input of root-nodes.
    if (likely(buf->root_goto_num != 255)) {
        while(idx < len) {
            unsigned char c = str[idx++];
            if (unsigned char kid_id = root_goto[c]) {
                state = Get_State_Addr(buf_base, states_ofst_vect, kid_id);
                break;
            }
        }
    } else {
        idx = 1;
        state = Get_State_Addr(buf_base, states_ofst_vect, *str);
    }

    if (likely(state != 0)) {
        if (unlikely(state->is_term)) {
            /* Dictionary may have string of length 1 */
            ac_result_t r;
            r.match_begin = idx - state->depth;
            r.match_end = idx - 1;
            return r;
        }
    }

    while (idx < len) {
        unsigned char c = str[idx];
        int res;
        bool found;
        found = Binary_Search_Input(state->input_vect, state->goto_num, c, res);
        if (found) {
            // The "t = goto(c, current_state)" is valid, advance to state "t".
            uint32 kid = state->first_kid + res;
            state = Get_State_Addr(buf_base, states_ofst_vect, kid);
            idx++;
        } else {
            // Follow the fail-link.
            State_ID fl = state->fail_link;
            if (fl == 0) {
                // fail-link is root-node, which implies the root-node dosen't
                // have 255 valid transitions (otherwise, the fail-link should
                // points to "goto(root, c)"), so we don't need speical handling
                // as we did before this while-loop is entered.
                //
                while(idx < len) {
                    InputTy c = str[idx++];
                    if (unsigned char kid_id = root_goto[c]) {
                        state =
                            Get_State_Addr(buf_base, states_ofst_vect, kid_id);
                        break;
                    }
                }
            } else {
                state = Get_State_Addr(buf_base, states_ofst_vect, fl);
            }
        }

        // Check to see if the state is terminal state?
        if (state->is_term) {
            ac_result_t r;
            r.match_begin = idx - state->depth;
            r.match_end = idx - 1;
            return r;
        }
    }

    ac_result_t r = {-1, -1};
    return r;
}

#ifdef DEBUG
void
AC_Converter::dump_buffer(AC_Buffer* buf, FILE* f) {
    vector<AC_Ofst> state_ofst;
    state_ofst.resize(_id_map.size());

    fprintf(f, "Id maps between old/slow and new/fast graphs\n");
    int old_id = 0;
    for (vector<uint32>::iterator i = _id_map.begin(), e = _id_map.end();
         i != e; i++, old_id++) {
        State_ID new_id = *i;
        if (new_id != 0) {
            fprintf(f, "%d -> %d, ", old_id, new_id);
        }
    }
    fprintf(f, "\n");

    int idx = 0;
    for (vector<uint32>::iterator i = _id_map.begin(), e = _id_map.end();
         i != e; i++, idx++) {
        uint32 id = *i;
        if (id == 0) continue;
        state_ofst[id] = _ofst_map[idx];
    }

    unsigned char* buf_base = (unsigned char*)buf;

    // dump root goto-function.
    fprintf(f, "root, fanout:%d goto {", buf->root_goto_num);
    if (buf->root_goto_num != 255) {
        unsigned char* root_goto = buf_base + buf->root_goto_ofst;
        for (uint32 i = 0; i < 255; i++) {
            if (root_goto[i] != 0)
                fprintf(f, "%c->S:%d, ", (unsigned char)i, root_goto[i]);
        }
    } else {
        fprintf(f, "full fanout\n");
    }
    fprintf(f, "}\n");

    // dump remaining states.
    AC_Ofst* state_ofst_vect = (AC_Ofst*)(buf_base + buf->states_ofst_ofst);
    for (uint32 i = 1, e = buf->state_num; i < e; i++) {
        AC_Ofst ofst = state_ofst_vect[i];
        ASSERT(ofst == state_ofst[i]);
        fprintf(f, "S:%d, ofst:%d, goto={", i, ofst);

        AC_State* s = (AC_State*)(buf_base + ofst);
        State_ID kid = s->first_kid;
        for (uint32 k = 0, ke = s->goto_num; k < ke; k++, kid++)
            fprintf(f, "%c->S:%d, ", s->input_vect[k], kid);

        fprintf(f, "}, fail-link = S:%d, %s\n", s->fail_link,
                s->is_term ? "terminal" : "");
    }
}
#endif
<commit_msg>Use the new binary-search function after measuring performance about 10 benchmarks.<commit_after>#include <algorithm>    // for std::sort
#include "ac_slow.hpp"
#include "ac_fast.hpp"

uint32
AC_Converter::Calc_State_Sz(const ACS_State* s) const {
    AC_State dummy;
    uint32 sz = offsetof(AC_State, input_vect);
    sz += s->Get_GotoNum() * sizeof(dummy.input_vect[0]);

    if (sz < sizeof(AC_State))
        sz = sizeof(AC_State);

    uint32 align = __alignof__(dummy);
    sz = (sz + align - 1) & ~(align - 1);
    return sz;
}

AC_Buffer*
AC_Converter::Alloc_Buffer() {
    const vector<ACS_State*>& all_states = _acs.Get_All_States();
    const ACS_State* root_state = _acs.Get_Root_State();
    uint32 root_fanout = root_state->Get_GotoNum();

    // Step 1: Calculate the buffer size
    AC_Ofst root_goto_ofst, states_ofst_ofst, first_state_ofst;

    // part 1 :  buffer header
    uint32 sz = root_goto_ofst = sizeof(AC_Buffer);

    // part 2: Root-node's goto function
    if (likely(root_fanout != 255))
        sz += 256;
    else
        root_goto_ofst = 0;

    // part 3: mapping of state's relative position.
    unsigned align = __alignof__(AC_Ofst);
    sz = (sz + align - 1) & ~(align - 1);
    states_ofst_ofst = sz;

    sz += sizeof(AC_Ofst) * all_states.size();

    // part 4: state's contents
    align = __alignof__(AC_State);
    sz = (sz + align - 1) & ~(align - 1);
    first_state_ofst = sz;

    uint32 state_sz = 0;
    for (vector<ACS_State*>::const_iterator i = all_states.begin(),
            e = all_states.end(); i != e; i++) {
        state_sz += Calc_State_Sz(*i);
    }
    state_sz -= Calc_State_Sz(root_state);

    sz += state_sz;

    // Step 2: Allocate buffer, and populate header.
    AC_Buffer* buf = _buf_alloc.alloc(sz);

    buf->hdr.magic_num = AC_MAGIC_NUM;
    buf->hdr.impl_variant = IMPL_FAST_VARIANT;
    buf->buf_len = sz;
    buf->root_goto_ofst = root_goto_ofst;
    buf->states_ofst_ofst = states_ofst_ofst;
    buf->first_state_ofst = first_state_ofst;
    buf->root_goto_num = root_fanout;
    buf->state_num = _acs.Get_State_Num();
    return buf;
}

void
AC_Converter::Populate_Root_Goto_Func(AC_Buffer* buf,
                                      GotoVect& goto_vect) {
    unsigned char *buf_base = (unsigned char*)(buf);
    InputTy* root_gotos = (InputTy*)(buf_base + buf->root_goto_ofst);
    const ACS_State* root_state = _acs.Get_Root_State();

    root_state->Get_Sorted_Gotos(goto_vect);

    // Renumber the ID of root-node's immediate kids.
    uint32 new_id = 1;
    bool full_fantout = (goto_vect.size() == 255);
    if (likely(!full_fantout))
        bzero(root_gotos, 256*sizeof(InputTy));

    for (GotoVect::iterator i = goto_vect.begin(), e = goto_vect.end();
            i != e; i++, new_id++) {
        InputTy c = i->first;
        ACS_State* s = i->second;
        _id_map[s->Get_ID()] = new_id;

        if (likely(!full_fantout))
            root_gotos[c] = new_id;
    }
}

AC_Buffer*
AC_Converter::Convert() {
    // Step 1: Some preparation stuff.
    GotoVect gotovect;

    _id_map.clear();
    _ofst_map.clear();
    _id_map.resize(_acs.Get_Next_Node_Id());
    _ofst_map.resize(_acs.Get_Next_Node_Id());

    // Step 2: allocate buffer to accommodate the entire AC graph.
    AC_Buffer* buf = Alloc_Buffer();
    unsigned char* buf_base = (unsigned char*)buf;

    // Step 3: Root node need special care.
    Populate_Root_Goto_Func(buf, gotovect);
    buf->root_goto_num = gotovect.size();
    _id_map[_acs.Get_Root_State()->Get_ID()] = 0;

    // Step 4: Converting the remaining states by BFSing the graph.
    // First of all, enter root's immediate kids to the working list.
    vector<const ACS_State*> wl;
    State_ID id = 1;
    for (GotoVect::iterator i = gotovect.begin(), e = gotovect.end();
            i != e; i++, id++) {
        ACS_State* s = i->second;
        wl.push_back(s);
        _id_map[s->Get_ID()] = id;
    }

    AC_Ofst* state_ofst_vect = (AC_Ofst*)(buf_base + buf->states_ofst_ofst);
    AC_Ofst ofst = buf->first_state_ofst;
    for (uint32 idx = 0; idx < wl.size(); idx++) {
        const ACS_State* old_s = wl[idx];
        AC_State* new_s = (AC_State*)(buf_base + ofst);

        // This property should hold as we:
        //  - States are appended to worklist in the BFS order.
        //  - sibiling states are appended to worklist in the order of their
        //    corresponding input.
        //
        State_ID state_id = idx + 1;
        ASSERT(_id_map[old_s->Get_ID()] == state_id);

        state_ofst_vect[state_id] = ofst;

        new_s->first_kid = wl.size() + 1;
        new_s->depth = old_s->Get_Depth();
        new_s->is_term = old_s->is_Terminal() ? 1 : 0;

        uint32 gotonum = old_s->Get_GotoNum();
        new_s->goto_num = gotonum;

        // Populate the "input" field
        old_s->Get_Sorted_Gotos(gotovect);
        uint32 input_idx = 0;
        uint32 id = wl.size() + 1;
        InputTy* input_vect = new_s->input_vect;
        for (GotoVect::iterator i = gotovect.begin(), e = gotovect.end();
             i != e; i++, id++, input_idx++) {
            input_vect[input_idx] = i->first;

            ACS_State* kid = i->second;
            _id_map[kid->Get_ID()] = id;
            wl.push_back(kid);
        }

        _ofst_map[old_s->Get_ID()] = ofst;
        ofst += Calc_State_Sz(old_s);
    }

    // Populate the fail-link field.
    for (vector<const ACS_State*>::iterator i = wl.begin(), e = wl.end();
            i != e; i++) {
        const ACS_State* slow_s = *i;
        State_ID fast_s_id = _id_map[slow_s->Get_ID()];
        AC_State* fast_s = (AC_State*)(buf_base + state_ofst_vect[fast_s_id]);
        if (const ACS_State* fl = slow_s->Get_FailLink()) {
            State_ID id = _id_map[fl->Get_ID()];
            fast_s->fail_link = id;
        } else
            fast_s->fail_link = 0;
    }
#ifdef DEBUG
    //dump_buffer(buf, stderr);
#endif
    return buf;
}

static inline AC_State*
Get_State_Addr(unsigned char* buf_base, AC_Ofst* StateOfstVect, uint32 state_id) {
    ASSERT(state_id != 0 && "root node is handled in speical way");
    ASSERT(state_id < ((AC_Buffer*)buf_base)->state_num);
    return (AC_State*)(buf_base + StateOfstVect[state_id]);
}

// The performance of the binary search is critical to this work.
//
// Here we provide two versions of binary-search functions.
// The non-pristine version seems to consistently out-perform "pristine" one on
// bunch of benchmarks we tested.  With the benchmark under tests/testinput/
//
//   The speedup is following on my laptop (core i7, ubuntu):
//
//   benchmark       was                is
//  ----------------------------------------
//  image.bin       2.3s               2.0s
//  test.tar        6.7s               5.7s
//
//  NOTE: As of I write this comment, we only measure the performance on about
// 10+ benchmarks. It's still too early to say which one works better.
//
#if !defined(BS_MULTI_VER)
static bool __attribute__((always_inline))
Binary_Search_Input(InputTy* input_vect, int vect_len, InputTy input, int& idx) {
    if (vect_len <= 8) {
        for (int i = 0; i < vect_len; i++) {
            if (input_vect[i] == input) {
                idx = i;
                return true;
            }
        }
        return false;
    }

    // The "low" and "high" must be signed integers, as they could become -1.
    // Also since they are signed integer, "(low + high)/2" is sightly more
    // expensive than (low+high)>>1 or ((unsigned)(low + high))/2.
    //
    int low = 0, high = vect_len - 1;
    while (low <= high) {
        int mid = (low + high) >> 1;
        InputTy mid_c = input_vect[mid];

        if (input < mid_c)
            high = mid - 1;
        else if (input > mid_c)
            low = mid + 1;
        else {
            idx = mid;
            return true;
        }
    }
    return false;
}

#else

/* Let us call this version "pristine" version. */
static inline bool
Binary_Search_Input(InputTy* input_vect, int vect_len, InputTy input, int& idx) {
    int low = 0, high = vect_len - 1;
    while (low <= high) {
        int mid = (low + high) >> 1;
        InputTy mid_c = input_vect[mid];

        if (input < mid_c)
            high = mid - 1;
        else if (input > mid_c)
            low = mid + 1;
        else {
            idx = mid;
            return true;
        }
    }
    return false;
}
#endif

ac_result_t
Match(AC_Buffer* buf, const char* str, uint32 len) {
    unsigned char* buf_base = (unsigned char*)(buf);
    unsigned char* root_goto = buf_base + buf->root_goto_ofst;
    AC_Ofst* states_ofst_vect = (AC_Ofst* )(buf_base + buf->states_ofst_ofst);

    AC_State* state = 0;
    uint32 idx = 0;

    // Skip leading chars that are not valid input of root-nodes.
    if (likely(buf->root_goto_num != 255)) {
        while(idx < len) {
            unsigned char c = str[idx++];
            if (unsigned char kid_id = root_goto[c]) {
                state = Get_State_Addr(buf_base, states_ofst_vect, kid_id);
                break;
            }
        }
    } else {
        idx = 1;
        state = Get_State_Addr(buf_base, states_ofst_vect, *str);
    }

    if (likely(state != 0)) {
        if (unlikely(state->is_term)) {
            /* Dictionary may have string of length 1 */
            ac_result_t r;
            r.match_begin = idx - state->depth;
            r.match_end = idx - 1;
            return r;
        }
    }

    while (idx < len) {
        unsigned char c = str[idx];
        int res;
        bool found;
        found = Binary_Search_Input(state->input_vect, state->goto_num, c, res);
        if (found) {
            // The "t = goto(c, current_state)" is valid, advance to state "t".
            uint32 kid = state->first_kid + res;
            state = Get_State_Addr(buf_base, states_ofst_vect, kid);
            idx++;
        } else {
            // Follow the fail-link.
            State_ID fl = state->fail_link;
            if (fl == 0) {
                // fail-link is root-node, which implies the root-node dosen't
                // have 255 valid transitions (otherwise, the fail-link should
                // points to "goto(root, c)"), so we don't need speical handling
                // as we did before this while-loop is entered.
                //
                while(idx < len) {
                    InputTy c = str[idx++];
                    if (unsigned char kid_id = root_goto[c]) {
                        state =
                            Get_State_Addr(buf_base, states_ofst_vect, kid_id);
                        break;
                    }
                }
            } else {
                state = Get_State_Addr(buf_base, states_ofst_vect, fl);
            }
        }

        // Check to see if the state is terminal state?
        if (state->is_term) {
            ac_result_t r;
            r.match_begin = idx - state->depth;
            r.match_end = idx - 1;
            return r;
        }
    }

    ac_result_t r = {-1, -1};
    return r;
}

#ifdef DEBUG
void
AC_Converter::dump_buffer(AC_Buffer* buf, FILE* f) {
    vector<AC_Ofst> state_ofst;
    state_ofst.resize(_id_map.size());

    fprintf(f, "Id maps between old/slow and new/fast graphs\n");
    int old_id = 0;
    for (vector<uint32>::iterator i = _id_map.begin(), e = _id_map.end();
         i != e; i++, old_id++) {
        State_ID new_id = *i;
        if (new_id != 0) {
            fprintf(f, "%d -> %d, ", old_id, new_id);
        }
    }
    fprintf(f, "\n");

    int idx = 0;
    for (vector<uint32>::iterator i = _id_map.begin(), e = _id_map.end();
         i != e; i++, idx++) {
        uint32 id = *i;
        if (id == 0) continue;
        state_ofst[id] = _ofst_map[idx];
    }

    unsigned char* buf_base = (unsigned char*)buf;

    // dump root goto-function.
    fprintf(f, "root, fanout:%d goto {", buf->root_goto_num);
    if (buf->root_goto_num != 255) {
        unsigned char* root_goto = buf_base + buf->root_goto_ofst;
        for (uint32 i = 0; i < 255; i++) {
            if (root_goto[i] != 0)
                fprintf(f, "%c->S:%d, ", (unsigned char)i, root_goto[i]);
        }
    } else {
        fprintf(f, "full fanout\n");
    }
    fprintf(f, "}\n");

    // dump remaining states.
    AC_Ofst* state_ofst_vect = (AC_Ofst*)(buf_base + buf->states_ofst_ofst);
    for (uint32 i = 1, e = buf->state_num; i < e; i++) {
        AC_Ofst ofst = state_ofst_vect[i];
        ASSERT(ofst == state_ofst[i]);
        fprintf(f, "S:%d, ofst:%d, goto={", i, ofst);

        AC_State* s = (AC_State*)(buf_base + ofst);
        State_ID kid = s->first_kid;
        for (uint32 k = 0, ke = s->goto_num; k < ke; k++, kid++)
            fprintf(f, "%c->S:%d, ", s->input_vect[k], kid);

        fprintf(f, "}, fail-link = S:%d, %s\n", s->fail_link,
                s->is_term ? "terminal" : "");
    }
}
#endif
<|endoftext|>


<commit_before>#include "Segment.h"

namespace CppJieba
{
	Segment::Segment():_trie()
	{
	}

	Segment::~Segment()
	{
	}

	bool Segment::init(const char* const dictFilePath)
	{
		LogInfo(string_format("_trie.init(%s) start...", dictFilePath));
		_trie.init(dictFilePath);
		LogInfo("_trie.init end.");
	}

	bool Segment::destroy()
	{
		return _trie.destroy();
	}

	bool Segment::cutDAG(const string& chStr, vector<string>& res)
	{
		bool retFlag;
		res.clear();
		string uniStr = _utf8ToUni(chStr);
		if(uniStr.empty())
		{
			LogError("_utf8ToUni failed.");
			return false;
		}

		//calc DAG
		vector<vector<uint> > dag;
		retFlag = _calcDAG(uniStr, dag);
		if(!retFlag)
		{
			LogError("_calcDAG failed.");
			return false;
		}

		//cout<<__FILE__<<__LINE__<<endl;

		vector<pair<int, double> > dp;
		retFlag = _calcDP(uniStr, dag, dp);
		if(!retFlag)
		{
			LogError("_calcDP failed.");
			return false;
		}

		retFlag = _cutDAG(uniStr, dp, res);
		if(!retFlag)
		{
			LogError("_cutDAG failed.");
			return false;
		}

		retFlag = _filter(res);
		if(!retFlag)
		{
			LogError("_cutDAG failed.");
			return false;
		}

		return true;
	}
	bool Segment::extract(const string& utf8Str, vector<string>& keywords)
	{
		bool retFlag;
		vector<string> tmp;
		retFlag = cutDAG(utf8Str, tmp);
		if(!retFlag)
		{
			LogError(string_format("cutDAG(%s) failed.", utf8Str.c_str()));
			return false;
		}

		retFlag = _extract(tmp, keywords, 5);
		if(!retFlag)
		{
			LogError("_extract failed.");
			return false;
		}

		return true;
	}

	double Segment::getUtf8WordWeight(const string& word)
	{
		return _trie.getWeight(utf8ToUnicode(word));
	}

	double Segment::getUniWordWeight(const string& word)
	{
		return _trie.getWeight(word);
	}

	bool Segment::_pair_compare(const pair<string, double>& a, const pair<string, double>& b)
	{
		return a.second < b.second;
	}

	bool Segment::_extract(const vector<string>& words, vector<string>& keywords, uint topN)
	{
		keywords.clear();
		vector<pair<string, double> > tmp;
		for(uint i = 0; i < words.size(); i++)
		{
			double w = getUtf8WordWeight(words[i]);
			tmp.push_back(pair<string, double>(words[i], w));
			LogDebug(string_format("(%s,%lf)", words[i].c_str(), w));
		}

		sort(tmp.begin(), tmp.end(), _pair_compare);
		for(uint i = 0; i < topN && i < tmp.size(); i++)
		{
			keywords.push_back(tmp[i].first);
		}
		return true;
	}

	string Segment::_utf8ToUni(const string& utfStr)
	{
		string uniStr = utf8ToUnicode(utfStr);

		if(uniStr.empty())
		{
			LogError(string_format("utf8ToUnicode [%s] failed!", utfStr.c_str()));
			return "";
		}
		return uniStr;
	}

	bool Segment::_calcDAG(const string& uniStr, vector<vector<uint> >& dag)
	{
		for(uint i = 0; i < uniStr.size(); i+=2)
		{
			vector<uint> vec;
			vec.push_back(i/2);
			for(uint j = i + 4; j <= uniStr.size(); j+=2)
			{
				if(NULL != _trie.find(uniStr.substr(i, j - i)))
				{
					vec.push_back((j - 2)/2);
				}
			}
			dag.push_back(vec);
		}
		return true;
	}

	bool Segment::_calcDP(const string& uniStr, const vector<vector<uint> >& dag, vector<pair<int, double> >& res)
	{
		if(uniStr.size() / 2 != dag.size())
		{
			LogError("dag is illegal!");
			return false;
		}
		if(uniStr.size() < 2)
		{
			LogError("uniStr illegal");
			return false;
		}

		res.clear();
		res.assign(uniStr.size()/2 + 1, pair<int, double>(-1, 0.0));
		res[uniStr.size()/2].first = -1;
		res[uniStr.size()/2].second = 0.0;
		for(int i = uniStr.size() - 2; i >= 0; i-=2)
		{
			// calc max
			res[i/2].first = -1;
			res[i/2].second = -(numeric_limits<double>::max());
			for(int j = 0; j < dag[i/2].size(); j++)
			{
				//cout<<(i/2)<<","<<dag[i/2].size()<<","<<j<<endl;
				//getchar();
				int pos = dag[i/2][j];
				double val = getUniWordWeight(uniStr.substr(i, pos * 2 - i + 2)) + res[pos + 1].second;
				//cout<<pos<<","<<pos * 2 - i + 2<<","<<val<<endl;
				if(val > res[i/2].second)
				{
					res[i/2].first = pos;
					res[i/2].second = val;
				}
			}
		}
		res.pop_back();
		return true;
	}
	bool Segment::_cutDAG(const string& uniStr, const vector<pair<int, double> >& dp, vector<string>& res)
	{
		if(dp.size() != uniStr.size()/2)
		{
			LogError("dp or uniStr illegal!");
			return false;
		}

		res.clear();

		uint begin = 0;
		for(uint i = 0; i < dp.size(); i++)
		{
			//cout<<dp[i].first<<","
			//	<<dp[i].second<<endl;
			uint end = dp[i].first * 2 + 2;
			if(end <= begin)
			{
				continue;
			}
			string tmp = unicodeToUtf8(uniStr.substr(begin, end - begin));
			if(tmp.empty())
			{
				LogError("unicodeToUtf8 failed.");
				return false;
			}
			res.push_back(tmp);
			begin = end;
		}
		return true;
	}

	bool Segment::_filter(vector<string>& utf8Strs)
	{
		for(vector<string>::iterator it = utf8Strs.begin(); it != utf8Strs.end();)
		{
			string uniStr = utf8ToUnicode(*it);
			if(uniStr.empty() || uniStr.size()%2)
			{
				LogError("utf8ToUnicode error");
				return false;
			}

			// filter single word
			if(uniStr.size() == 2)
			{
				it = utf8Strs.erase(it);
			}
			else
			{
				it++;
			}
		}
		return true;
	}

}

#ifdef SEGMENT_UT
using namespace CppJieba;

int main()
{
	Segment segment;
	segment.init("dicts/segdict.utf8.v2.1");
	//segment.init("dicts/jieba.dict.utf8");

	vector<string> res;
	//string title = "我来到北京清华大学";
	string title = "特价！camel骆驼 柔软舒适头层牛皮平底凉鞋女 休闲平跟妈妈鞋夏";
	cout<<title<<endl;
	//segment.cutDAG(title, res);
	segment.extract(title, res);
	for(int i = 0; i < res.size(); i++)
	{
		cout<<res[i]<<endl;
	}

	segment.destroy();
	return 0;
}

#endif
<commit_msg>add some case in ut<commit_after>#include "Segment.h"

namespace CppJieba
{
	Segment::Segment():_trie()
	{
	}

	Segment::~Segment()
	{
	}

	bool Segment::init(const char* const dictFilePath)
	{
		LogInfo(string_format("_trie.init(%s) start...", dictFilePath));
		_trie.init(dictFilePath);
		LogInfo("_trie.init end.");
	}

	bool Segment::destroy()
	{
		return _trie.destroy();
	}

	bool Segment::cutDAG(const string& chStr, vector<string>& res)
	{
		bool retFlag;
		res.clear();
		string uniStr = _utf8ToUni(chStr);
		if(uniStr.empty())
		{
			LogError("_utf8ToUni failed.");
			return false;
		}

		//calc DAG
		vector<vector<uint> > dag;
		retFlag = _calcDAG(uniStr, dag);
		if(!retFlag)
		{
			LogError("_calcDAG failed.");
			return false;
		}

		//cout<<__FILE__<<__LINE__<<endl;

		vector<pair<int, double> > dp;
		retFlag = _calcDP(uniStr, dag, dp);
		if(!retFlag)
		{
			LogError("_calcDP failed.");
			return false;
		}

		retFlag = _cutDAG(uniStr, dp, res);
		if(!retFlag)
		{
			LogError("_cutDAG failed.");
			return false;
		}

		retFlag = _filter(res);
		if(!retFlag)
		{
			LogError("_cutDAG failed.");
			return false;
		}

		return true;
	}
	bool Segment::extract(const string& utf8Str, vector<string>& keywords)
	{
		bool retFlag;
		vector<string> tmp;
		retFlag = cutDAG(utf8Str, tmp);
		if(!retFlag)
		{
			LogError(string_format("cutDAG(%s) failed.", utf8Str.c_str()));
			return false;
		}

		retFlag = _extract(tmp, keywords, 5);
		if(!retFlag)
		{
			LogError("_extract failed.");
			return false;
		}

		return true;
	}

	double Segment::getUtf8WordWeight(const string& word)
	{
		return _trie.getWeight(utf8ToUnicode(word));
	}

	double Segment::getUniWordWeight(const string& word)
	{
		return _trie.getWeight(word);
	}

	bool Segment::_pair_compare(const pair<string, double>& a, const pair<string, double>& b)
	{
		return a.second < b.second;
	}

	bool Segment::_extract(const vector<string>& words, vector<string>& keywords, uint topN)
	{
		keywords.clear();
		vector<pair<string, double> > tmp;
		for(uint i = 0; i < words.size(); i++)
		{
			double w = getUtf8WordWeight(words[i]);
			tmp.push_back(pair<string, double>(words[i], w));
			LogDebug(string_format("(%s,%lf)", words[i].c_str(), w));
		}

		sort(tmp.begin(), tmp.end(), _pair_compare);
		for(uint i = 0; i < topN && i < tmp.size(); i++)
		{
			keywords.push_back(tmp[i].first);
		}
		return true;
	}

	string Segment::_utf8ToUni(const string& utfStr)
	{
		string uniStr = utf8ToUnicode(utfStr);

		if(uniStr.empty())
		{
			LogError(string_format("utf8ToUnicode [%s] failed!", utfStr.c_str()));
			return "";
		}
		return uniStr;
	}

	bool Segment::_calcDAG(const string& uniStr, vector<vector<uint> >& dag)
	{
		for(uint i = 0; i < uniStr.size(); i+=2)
		{
			vector<uint> vec;
			vec.push_back(i/2);
			for(uint j = i + 4; j <= uniStr.size(); j+=2)
			{
				if(NULL != _trie.find(uniStr.substr(i, j - i)))
				{
					vec.push_back((j - 2)/2);
				}
			}
			dag.push_back(vec);
		}
		return true;
	}

	bool Segment::_calcDP(const string& uniStr, const vector<vector<uint> >& dag, vector<pair<int, double> >& res)
	{
		if(uniStr.size() / 2 != dag.size())
		{
			LogError("dag is illegal!");
			return false;
		}
		if(uniStr.size() < 2)
		{
			LogError("uniStr illegal");
			return false;
		}

		res.clear();
		res.assign(uniStr.size()/2 + 1, pair<int, double>(-1, 0.0));
		res[uniStr.size()/2].first = -1;
		res[uniStr.size()/2].second = 0.0;
		for(int i = uniStr.size() - 2; i >= 0; i-=2)
		{
			// calc max
			res[i/2].first = -1;
			res[i/2].second = -(numeric_limits<double>::max());
			for(int j = 0; j < dag[i/2].size(); j++)
			{
				//cout<<(i/2)<<","<<dag[i/2].size()<<","<<j<<endl;
				//getchar();
				int pos = dag[i/2][j];
				double val = getUniWordWeight(uniStr.substr(i, pos * 2 - i + 2)) + res[pos + 1].second;
				//cout<<pos<<","<<pos * 2 - i + 2<<","<<val<<endl;
				if(val > res[i/2].second)
				{
					res[i/2].first = pos;
					res[i/2].second = val;
				}
			}
		}
		res.pop_back();
		return true;
	}
	bool Segment::_cutDAG(const string& uniStr, const vector<pair<int, double> >& dp, vector<string>& res)
	{
		if(dp.size() != uniStr.size()/2)
		{
			LogError("dp or uniStr illegal!");
			return false;
		}

		res.clear();

		uint begin = 0;
		for(uint i = 0; i < dp.size(); i++)
		{
			//cout<<dp[i].first<<","
			//	<<dp[i].second<<endl;
			uint end = dp[i].first * 2 + 2;
			if(end <= begin)
			{
				continue;
			}
			string tmp = unicodeToUtf8(uniStr.substr(begin, end - begin));
			if(tmp.empty())
			{
				LogError("unicodeToUtf8 failed.");
				return false;
			}
			res.push_back(tmp);
			begin = end;
		}
		return true;
	}

	bool Segment::_filter(vector<string>& utf8Strs)
	{
		for(vector<string>::iterator it = utf8Strs.begin(); it != utf8Strs.end();)
		{
			string uniStr = utf8ToUnicode(*it);
			if(uniStr.empty() || uniStr.size()%2)
			{
				LogError("utf8ToUnicode error");
				return false;
			}

			// filter single word
			if(uniStr.size() == 2)
			{
				it = utf8Strs.erase(it);
			}
			else
			{
				it++;
			}
		}
		return true;
	}

}

#ifdef SEGMENT_UT
using namespace CppJieba;

int main()
{
	Segment segment;
	segment.init("dicts/segdict.utf8.v2.1");
	//segment.init("dicts/jieba.dict.utf8");

	vector<string> res;
	//string title = "我来到北京清华大学";
	//string title = "特价！camel骆驼 柔软舒适头层牛皮平底凉鞋女 休闲平跟妈妈鞋夏";
	//string title = "包邮拉菲草18cm大檐进口草帽子超强遮阳防晒欧美日韩新款夏天 女";
	string title = "2013新款19CM超大檐帽 遮阳草帽子 沙滩帽防晒大檐欧美新款夏天女";
	cout<<title<<endl;
	//segment.cutDAG(title, res);
	segment.extract(title, res);
	for(int i = 0; i < res.size(); i++)
	{
		cout<<res[i]<<endl;
	}

	segment.destroy();
	return 0;
}

#endif
<|endoftext|>


<commit_before>#include "includes/SWidgets/SUrlArea.hpp"
#include "includes/SMainWindow.hpp"
#include "includes/SActions.hpp"

#include <QMessageBox>

SUrlArea::SUrlArea(SMainWindow * parent) :
	QProgressBar(parent),
	m_parent(parent)
{
	QHBoxLayout* layout{ new QHBoxLayout(this) };
	layout->setContentsMargins(0, 0, 0, 0);
	layout->setSpacing(0);

	m_champs->setStyleSheet("background: rgba(255, 255, 255, 0); border: none;");
	m_champs->setClearButtonEnabled(true);
	layout->addWidget(m_champs);

	setTextVisible(false);

	connect(m_champs, &QLineEdit::returnPressed, this, &SUrlArea::loadUrl);
}

SUrlArea::~SUrlArea()
{

}

void SUrlArea::setText(const QString& texte)
{
	m_champs->setText(texte);
}

void SUrlArea::loadStarted()
{
	// Change the refresh action to the stop action
	m_parent->getActions()->refreshOrStop->setIcon(QIcon(m_parent->getActions()->themePath + "stop.png"));
	m_parent->getActions()->refreshOrStop->setText(tr("Arrêter le chargement"));
	m_parent->getActions()->refreshOrStop->setShortcut(QKeySequence(""));
	connect(m_parent->getActions()->refreshOrStop, &QAction::triggered, m_parent, &SMainWindow::stop);

	setStyleSheet("QProgressBar::chunk{background-color: rgba(0, 0, 155, 0.2); border: none;}");

	QString url{ m_parent->currentPage()->url().toString() };
	if ((url.left(7) != "http://" && url.left(8) != "https://" && url.left(5) != "html/") && !url.isEmpty()) {
		QMessageBox warningMsgBox{ QMessageBox::Warning, tr("Site non sécurisé"), tr("Attention, le site sur lequel vous entrez n'est pas sécurisé !"), QMessageBox::Ignore | QMessageBox::Cancel, this };

		warningMsgBox.setButtonText(QMessageBox::Ignore, tr("Continuer"));
		warningMsgBox.setButtonText(QMessageBox::Cancel, tr("Retour a la sécurité"));

		if (warningMsgBox.exec() == QMessageBox::Cancel)
			m_parent->back();
	}
}

void SUrlArea::loadInProgress(int percent)
{
	setValue(percent);
}

void SUrlArea::loadFinished()
{
	SWebView* view{ static_cast<SWebView*>(sender()) };

	if (!view)
		return;

	m_parent->getActions()->refreshOrStop->setIcon(QIcon(m_parent->getActions()->themePath + "refresh.png"));
	m_parent->getActions()->refreshOrStop->setText(tr("Rafraîchir la page"));
	m_parent->getActions()->refreshOrStop->setShortcuts(QKeySequence::Refresh);
	setStyleSheet("QProgressBar::chunk{background-color: rgba(200, 200, 200, 0.2); border: none;}");
	connect(m_parent->getActions()->refreshOrStop, &QAction::triggered, m_parent, &SMainWindow::refresh);

	if(!m_parent->privateBrowsing) {
		if (view->url().toString() == "about:blank")
			return;
		else if(SMainWindow::curSessionHistory.size() <= 0)
			SMainWindow::addHistoryItem(view->title(), view->url());
		else if(SMainWindow::getLastHistoryItem().title != view->title())
			SMainWindow::addHistoryItem(view->title(), view->url());
	}
}

void SUrlArea::loadUrl()
{
	QString url{};

//	QRegExp urlReg{ "^(https?\:\/\/)?([a-zA-Z0-9-]+\.)?([a-zA-Z0-9-]+\.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(:[0-9]+)?(\/[a-zA-Z0-9-]*\/?|\/[a-zA-Z0-9]+\.[a-zA-Z0-9]{1,4})?$" };
	QRegExp urlReg{ R"regex((https?\:\/\/)?([a-zA-Z0-9-]+.)?([a-zA-Z0-9-]+.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(:[0-9]+)?(\/[a-zA-Z0-9-]*\/?|\/[a-zA-Z0-9]+\.[a-zA-Z0-9]{1,4})?)regex" };

	if (!m_champs->text().contains(urlReg)) {
		url = "http://www.google.com/search?q=" + m_champs->text();
		url.replace(" ", "+");
	}
	else {
		if (m_champs->text().left(7) != "http://" && m_champs->text().left(8) != "https://")
			url = "https://" + m_champs->text();
		else
			url = m_champs->text();
	}

/*
	if (m_champs->text().left(7) != "http://" && m_champs->text().left(8) != "https://")
		url = "https://" + m_champs->text();
	else
		url = m_champs->text();
*/

	m_parent->currentPage()->load(QUrl(url));
}
<commit_msg>UPDATE the style of the url bar<commit_after>#include "includes/SWidgets/SUrlArea.hpp"
#include "includes/SMainWindow.hpp"
#include "includes/SActions.hpp"

#include <QMessageBox>

SUrlArea::SUrlArea(SMainWindow * parent) :
	QProgressBar(parent),
	m_parent(parent)
{
	QHBoxLayout* layout{ new QHBoxLayout(this) };
	layout->setContentsMargins(0, 0, 0, 0);
	layout->setSpacing(0);

	m_champs->setStyleSheet("background: #00FFFFFF; border: none;");
	setStyleSheet("QProgressBar{ border: none; background-color: #FFFFFF; } QProgressBar::chunk{background-color: #FFFFFF;}");

	m_champs->setClearButtonEnabled(true);
	layout->addWidget(m_champs);

	setTextVisible(false);

	connect(m_champs, &QLineEdit::returnPressed, this, &SUrlArea::loadUrl);
}

SUrlArea::~SUrlArea()
{

}

void SUrlArea::setText(const QString& texte)
{
	m_champs->setText(texte);
}

void SUrlArea::loadStarted()
{
	// Change the refresh action to the stop action
	m_parent->getActions()->refreshOrStop->setIcon(QIcon(m_parent->getActions()->themePath + "stop.png"));
	m_parent->getActions()->refreshOrStop->setText(tr("Arrêter le chargement"));
	m_parent->getActions()->refreshOrStop->setShortcut(QKeySequence(""));
	connect(m_parent->getActions()->refreshOrStop, &QAction::triggered, m_parent, &SMainWindow::stop);

//	setStyleSheet("QProgressBar::chunk{background-color: rgba(0, 0, 155, 0.2); border: none;}");
	setStyleSheet("QProgressBar{ border: none; background-color: #FFFFFF; } QProgressBar::chunk{background-color: #000066FF; border-bottom: 3px solid #000000;}");

	QString url{ m_parent->currentPage()->url().toString() };
	if ((url.left(7) != "http://" && url.left(8) != "https://" && url.left(5) != "html/") && !url.isEmpty()) {
		QMessageBox warningMsgBox{ QMessageBox::Warning, tr("Site non sécurisé"), tr("Attention, le site sur lequel vous entrez n'est pas sécurisé !"), QMessageBox::Ignore | QMessageBox::Cancel, this };

		warningMsgBox.setButtonText(QMessageBox::Ignore, tr("Continuer"));
		warningMsgBox.setButtonText(QMessageBox::Cancel, tr("Retour a la sécurité"));

		if (warningMsgBox.exec() == QMessageBox::Cancel)
			m_parent->back();
	}
}

void SUrlArea::loadInProgress(int percent)
{
	setValue(percent);
}

void SUrlArea::loadFinished()
{
	SWebView* view{ static_cast<SWebView*>(sender()) };

	if (!view)
		return;

	m_parent->getActions()->refreshOrStop->setIcon(QIcon(m_parent->getActions()->themePath + "refresh.png"));
	m_parent->getActions()->refreshOrStop->setText(tr("Rafraîchir la page"));
	m_parent->getActions()->refreshOrStop->setShortcuts(QKeySequence::Refresh);
//	setStyleSheet("QProgressBar::chunk{background-color: rgba(200, 200, 200, 0.2); border: none;}");
	setStyleSheet("QProgressBar{ border: none; background-color: #FFFFFF; } QProgressBar::chunk{background-color: #FFFFFF;}");

	connect(m_parent->getActions()->refreshOrStop, &QAction::triggered, m_parent, &SMainWindow::refresh);

	if(!m_parent->privateBrowsing) {
		if (view->url().toString() == "about:blank")
			return;
		else if(SMainWindow::curSessionHistory.size() <= 0)
			SMainWindow::addHistoryItem(view->title(), view->url());
		else if(SMainWindow::getLastHistoryItem().title != view->title())
			SMainWindow::addHistoryItem(view->title(), view->url());
	}
}

void SUrlArea::loadUrl()
{
	QString url{};

//	QRegExp urlReg{ "^(https?\:\/\/)?([a-zA-Z0-9-]+\.)?([a-zA-Z0-9-]+\.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(:[0-9]+)?(\/[a-zA-Z0-9-]*\/?|\/[a-zA-Z0-9]+\.[a-zA-Z0-9]{1,4})?$" };
	QRegExp urlReg{ R"regex((https?\:\/\/)?([a-zA-Z0-9-]+.)?([a-zA-Z0-9-]+.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(:[0-9]+)?(\/[a-zA-Z0-9-]*\/?|\/[a-zA-Z0-9]+\.[a-zA-Z0-9]{1,4})?)regex" };

	if (!m_champs->text().contains(urlReg)) {
		url = "http://www.google.com/search?q=" + m_champs->text();
		url.replace(" ", "+");
	}
	else {
		if (m_champs->text().left(7) != "http://" && m_champs->text().left(8) != "https://")
			url = "https://" + m_champs->text();
		else
			url = m_champs->text();
	}

/*
	if (m_champs->text().left(7) != "http://" && m_champs->text().left(8) != "https://")
		url = "https://" + m_champs->text();
	else
		url = m_champs->text();
*/

	m_parent->currentPage()->load(QUrl(url));
}
<|endoftext|>