From 33b480fbae8a5ca96420a78a70a5b4212bd71fbe Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 12 Dec 2023 03:14:55 +0000 Subject: [PATCH] Update code style --- .../Database/Connection/ConnectionAbstract.h | 59 +- .../Database/Connection/ConnectionFactory.h | 57 +- .../Database/Connection/DbConnectionConfig.h | 65 +- .../Database/Connection/MysqlConnection.h | 215 ++-- .../Connection/PostgresqlConnection.h | 201 ++-- .../Database/Connection/SQLiteConnection.h | 211 ++-- DataStorage/Database/DatabaseStatus.h | 21 +- DataStorage/Database/DatabaseType.h | 43 +- .../Database/Mapper/DataMapperFactory.h | 55 +- DataStorage/Database/Mapper/DataMapperTypes.h | 327 +++--- DataStorage/Database/Mapper/MapperAbstract.h | 114 +-- DataStorage/Database/Mapper/ReadMapper.h | 79 +- DataStorage/Database/Schema/DbField.h | 69 +- DataStorage/Database/Schema/DbSchema.h | 37 +- Hash/MD5.h | 4 +- Hash/MeowHash.h | 968 +++++++++--------- Hash/SHA256.h | 2 +- Image/BillDetection.h | 101 +- Image/ImageUtils.h | 37 +- Image/Kernel.h | 19 +- Image/Skew.h | 111 +- Image/Thresholding.h | 99 +- Stdlib/HashTable.h | 345 ++++--- Utils/ApplicationUtils.h | 2 - Utils/ArraySort.h | 65 +- Utils/ArrayUtils.h | 309 +++--- Utils/ColorUtils.h | 57 ++ Utils/FileUtils.h | 161 ++- Utils/Rng/StringUtils.h | 40 +- Utils/StringUtils.h | 417 ++++---- Utils/WebUtils.h | 449 ++++---- 31 files changed, 2370 insertions(+), 2369 deletions(-) create mode 100644 Utils/ColorUtils.h diff --git a/DataStorage/Database/Connection/ConnectionAbstract.h b/DataStorage/Database/Connection/ConnectionAbstract.h index cac4e23..ec58d45 100755 --- a/DataStorage/Database/Connection/ConnectionAbstract.h +++ b/DataStorage/Database/Connection/ConnectionAbstract.h @@ -17,46 +17,43 @@ #include "../DatabaseType.h" #include "../DatabaseStatus.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - typedef struct { - size_t rows = 0; - size_t columns = 0; - char **results = NULL; - } QueryResult; + typedef struct { + size_t rows = 0; + size_t columns = 0; + char **results = NULL; + } QueryResult; - struct ConnectionAbstract { - void *con = NULL; + struct ConnectionAbstract { + void *con = NULL; - DbConnectionConfig dbdata; + DbConnectionConfig dbdata; - DatabaseType type = DatabaseType::UNDEFINED; + DatabaseType type = DatabaseType::UNDEFINED; - DatabaseStatus status = DatabaseStatus::CLOSED; + DatabaseStatus status = DatabaseStatus::CLOSED; - virtual void connect(DbConnectionConfig *dbdata = NULL) - { - return; + virtual void connect(DbConnectionConfig *dbdata = NULL) + { + return; + } + + virtual void close() + { + if (this->con != NULL) { + free(con); } - virtual void close() - { - if (this->con != NULL) { - free(con); - } + this->con = NULL; + this->status = DatabaseStatus::CLOSED; + } - this->con = NULL; - this->status = DatabaseStatus::CLOSED; - } - - virtual QueryResult query_execute(char *stmt, char *paramValues = NULL) - { - return QueryResult(); - } - }; - } + virtual QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + return QueryResult(); + } + }; } #endif \ No newline at end of file diff --git a/DataStorage/Database/Connection/ConnectionFactory.h b/DataStorage/Database/Connection/ConnectionFactory.h index 1e3fcdc..b790b97 100755 --- a/DataStorage/Database/Connection/ConnectionFactory.h +++ b/DataStorage/Database/Connection/ConnectionFactory.h @@ -21,40 +21,37 @@ #include "PostgresqlConnection.h" #include "SQLiteConnection.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database + ConnectionAbstract *create_connection(DbConnectionConfig dbdata) { - ConnectionAbstract *create_connection(DbConnectionConfig dbdata) - { - switch (dbdata.db) { - case DatabaseType::MYSQL: - return new MysqlConnection(dbdata); - case DatabaseType::PGSQL: - return new PostgresqlConnection(dbdata); - case DatabaseType::SQLSRV: - return NULL; - case DatabaseType::SQLITE: - return new SQLiteConnection(dbdata); - default: - return NULL; - } + switch (dbdata.db) { + case DatabaseType::MYSQL: + return new MysqlConnection(dbdata); + case DatabaseType::PGSQL: + return new PostgresqlConnection(dbdata); + case DatabaseType::SQLSRV: + return NULL; + case DatabaseType::SQLITE: + return new SQLiteConnection(dbdata); + default: + return NULL; } + } - void close(ConnectionAbstract *db, DbConnectionConfig dbdata) - { - switch (dbdata.db) { - case DatabaseType::MYSQL: - return ((MysqlConnection *) db)->close(); - case DatabaseType::PGSQL: - return ((PostgresqlConnection *) db)->close(); - case DatabaseType::SQLSRV: - return; - case DatabaseType::SQLITE: - return ((SQLiteConnection *) db)->close(); - default: - return; - } + void close(ConnectionAbstract *db, DbConnectionConfig dbdata) + { + switch (dbdata.db) { + case DatabaseType::MYSQL: + return ((MysqlConnection *) db)->close(); + case DatabaseType::PGSQL: + return ((PostgresqlConnection *) db)->close(); + case DatabaseType::SQLSRV: + return; + case DatabaseType::SQLITE: + return ((SQLiteConnection *) db)->close(); + default: + return; } } } diff --git a/DataStorage/Database/Connection/DbConnectionConfig.h b/DataStorage/Database/Connection/DbConnectionConfig.h index 103fbe6..9582d4c 100755 --- a/DataStorage/Database/Connection/DbConnectionConfig.h +++ b/DataStorage/Database/Connection/DbConnectionConfig.h @@ -15,45 +15,42 @@ #include "../DatabaseType.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database + typedef struct { + DatabaseType db = DatabaseType::UNDEFINED; + + const char *database = NULL; + + const char *host = NULL; + + int port = 0; + + const char *login = NULL; + + const char *password = NULL; + } DbConnectionConfig; + + void free_DbConnectionConfig(DbConnectionConfig *dbdata) { - typedef struct { - DatabaseType db = DatabaseType::UNDEFINED; + if (dbdata->database != NULL) { + free((char *) dbdata->database); + dbdata->database = NULL; + } - const char *database = NULL; + if (dbdata->host != NULL) { + free((char *) dbdata->host); + dbdata->host = NULL; + } - const char *host = NULL; + if (dbdata->login != NULL) { + free((char *) dbdata->login); + dbdata->login = NULL; + } - int port = 0; - - const char *login = NULL; - - const char *password = NULL; - } DbConnectionConfig; - - void free_DbConnectionConfig(DbConnectionConfig *dbdata) - { - if (dbdata->database != NULL) { - free((char *) dbdata->database); - dbdata->database = NULL; - } - - if (dbdata->host != NULL) { - free((char *) dbdata->host); - dbdata->host = NULL; - } - - if (dbdata->login != NULL) { - free((char *) dbdata->login); - dbdata->login = NULL; - } - - if (dbdata->password != NULL) { - free((char *) dbdata->password); - dbdata->password = NULL; - } + if (dbdata->password != NULL) { + free((char *) dbdata->password); + dbdata->password = NULL; } } } diff --git a/DataStorage/Database/Connection/MysqlConnection.h b/DataStorage/Database/Connection/MysqlConnection.h index 95c92bc..634e566 100755 --- a/DataStorage/Database/Connection/MysqlConnection.h +++ b/DataStorage/Database/Connection/MysqlConnection.h @@ -20,131 +20,128 @@ #include "../DatabaseType.h" #include "../DatabaseStatus.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - struct MysqlConnection : ConnectionAbstract { - MysqlConnection(DbConnectionConfig dbdata) - { - this->type = DatabaseType::MYSQL; - this->dbdata = dbdata; - } + struct MysqlConnection : ConnectionAbstract { + MysqlConnection(DbConnectionConfig dbdata) + { + this->type = DatabaseType::MYSQL; + this->dbdata = dbdata; + } - void connect(DbConnectionConfig *dbdata = NULL) - { - this->dbdata = dbdata == NULL ? this->dbdata : *dbdata; + void connect(DbConnectionConfig *dbdata = NULL) + { + this->dbdata = dbdata == NULL ? this->dbdata : *dbdata; - if (this->dbdata.db == DatabaseType::UNDEFINED - || this->dbdata.host == NULL - || this->dbdata.port == 0 - || this->dbdata.database == NULL - || this->dbdata.login == NULL - || this->dbdata.password == NULL - ) { - this->status = DatabaseStatus::FAILURE; + if (this->dbdata.db == DatabaseType::UNDEFINED + || this->dbdata.host == NULL + || this->dbdata.port == 0 + || this->dbdata.database == NULL + || this->dbdata.login == NULL + || this->dbdata.password == NULL + ) { + this->status = DatabaseStatus::FAILURE; - if (this->dbdata.password != NULL) { - free((char *) this->dbdata.password); - this->dbdata.password = NULL; - } - } - - this->close(); - - this->con = mysql_init(NULL); - this->con = mysql_real_connect( - (::MYSQL *) this->con, - this->dbdata.host, - this->dbdata.login, - this->dbdata.password, - this->dbdata.database, - this->dbdata.port, - NULL, 0 - ); - - if (!this->con) { - this->status = DatabaseStatus::MISSING_DATABASE; - - mysql_close((::MYSQL *) this->con); - this->con = NULL; - - if (this->dbdata.password != NULL) { - free((char *) this->dbdata.password); - this->dbdata.password = NULL; - } + if (this->dbdata.password != NULL) { + free((char *) this->dbdata.password); + this->dbdata.password = NULL; } } - void close() - { - if (this->con != NULL) { - mysql_close((::MYSQL *) this->con); - } + this->close(); - this->con = NULL; - this->status = DatabaseStatus::CLOSED; + this->con = mysql_init(NULL); + this->con = mysql_real_connect( + (::MYSQL *) this->con, + this->dbdata.host, + this->dbdata.login, + this->dbdata.password, + this->dbdata.database, + this->dbdata.port, + NULL, 0 + ); + + if (!this->con) { + this->status = DatabaseStatus::MISSING_DATABASE; + + mysql_close((::MYSQL *) this->con); + this->con = NULL; + + if (this->dbdata.password != NULL) { + free((char *) this->dbdata.password); + this->dbdata.password = NULL; + } + } + } + + void close() + { + if (this->con != NULL) { + mysql_close((::MYSQL *) this->con); } - QueryResult query_execute(char *stmt, char *paramValues = NULL) - { - QueryResult result; + this->con = NULL; + this->status = DatabaseStatus::CLOSED; + } - MYSQL_RES *res; - int status = 0; + QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + QueryResult result; - if (paramValues != NULL) { - return result; - } else { - status = mysql_query((::MYSQL *) this->con, stmt); - res = mysql_store_result((::MYSQL *) this->con); - } + MYSQL_RES *res; + int status = 0; - if (res == NULL) { - return result; - } - - result.rows = mysql_num_rows(res); - result.columns = mysql_num_fields(res); - - if (result.rows == 0 || result.columns == 0) { - return result; - } - - result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); - - char *temp = NULL; - size_t valLen = 0; - size_t *lengths; - - ::MYSQL_ROW row; - size_t i = 0; - - while ((row = mysql_fetch_row(res)) != NULL) { - lengths = mysql_fetch_lengths(res); - for (int j = 0; j < result.columns; ++j) { - temp = row[j]; - - if (temp == NULL) { - result.results[i * result.columns + j] = NULL; - - continue; - } - - valLen = lengths[j]; - - result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); - memcpy(result.results[i * result.columns + j], temp, valLen); - result.results[i * result.columns + j][valLen] = '\0'; - } - - ++i; - } + if (paramValues != NULL) { + return result; + } else { + status = mysql_query((::MYSQL *) this->con, stmt); + res = mysql_store_result((::MYSQL *) this->con); + } + if (res == NULL) { return result; } - }; - } + + result.rows = mysql_num_rows(res); + result.columns = mysql_num_fields(res); + + if (result.rows == 0 || result.columns == 0) { + return result; + } + + result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); + + char *temp = NULL; + size_t valLen = 0; + size_t *lengths; + + ::MYSQL_ROW row; + size_t i = 0; + + while ((row = mysql_fetch_row(res)) != NULL) { + lengths = mysql_fetch_lengths(res); + for (int j = 0; j < result.columns; ++j) { + temp = row[j]; + + if (temp == NULL) { + result.results[i * result.columns + j] = NULL; + + continue; + } + + valLen = lengths[j]; + + result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); + memcpy(result.results[i * result.columns + j], temp, valLen); + result.results[i * result.columns + j][valLen] = '\0'; + } + + ++i; + } + + return result; + } + }; } #endif \ No newline at end of file diff --git a/DataStorage/Database/Connection/PostgresqlConnection.h b/DataStorage/Database/Connection/PostgresqlConnection.h index 83cbd1e..73c9959 100755 --- a/DataStorage/Database/Connection/PostgresqlConnection.h +++ b/DataStorage/Database/Connection/PostgresqlConnection.h @@ -20,125 +20,122 @@ #include "../DatabaseType.h" #include "../DatabaseStatus.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - struct PostgresqlConnection : ConnectionAbstract { - PostgresqlConnection(DbConnectionConfig dbdata) - { - this->type = DatabaseType::PGSQL; - this->dbdata = dbdata; - } + struct PostgresqlConnection : ConnectionAbstract { + PostgresqlConnection(DbConnectionConfig dbdata) + { + this->type = DatabaseType::PGSQL; + this->dbdata = dbdata; + } - void connect(DbConnectionConfig *dbdata = NULL) - { - this->dbdata = dbdata == NULL ? this->dbdata : *dbdata; + void connect(DbConnectionConfig *dbdata = NULL) + { + this->dbdata = dbdata == NULL ? this->dbdata : *dbdata; - if (this->dbdata.db == DatabaseType::UNDEFINED - || this->dbdata.host == NULL - || this->dbdata.port == 0 - || this->dbdata.database == NULL - || this->dbdata.login == NULL - || this->dbdata.password == NULL - ) { - this->status = DatabaseStatus::FAILURE; + if (this->dbdata.db == DatabaseType::UNDEFINED + || this->dbdata.host == NULL + || this->dbdata.port == 0 + || this->dbdata.database == NULL + || this->dbdata.login == NULL + || this->dbdata.password == NULL + ) { + this->status = DatabaseStatus::FAILURE; - if (this->dbdata.password != NULL) { - free((char *) this->dbdata.password); - this->dbdata.password = NULL; - } - } - - this->close(); - - char port[12]; - sprintf(port, "%d", this->dbdata.port); - - this->con = PQsetdbLogin( - this->dbdata.host, - port, - NULL, - NULL, - this->dbdata.database, - this->dbdata.login, - this->dbdata.password - ); - - ConnStatusType stat = PQstatus((PGconn *) this->con); - - if (stat != ConnStatusType::CONNECTION_OK) { - this->status = DatabaseStatus::MISSING_DATABASE; - - PQfinish((PGconn *) this->con); - this->con = NULL; - - if (this->dbdata.password != NULL) { - free((char *) this->dbdata.password); - this->dbdata.password = NULL; - } + if (this->dbdata.password != NULL) { + free((char *) this->dbdata.password); + this->dbdata.password = NULL; } } - void close() - { - if (this->con != NULL) { - PQfinish((PGconn *) this->con); - } + this->close(); - this->con = NULL; - this->status = DatabaseStatus::CLOSED; + char port[12]; + sprintf(port, "%d", this->dbdata.port); + + this->con = PQsetdbLogin( + this->dbdata.host, + port, + NULL, + NULL, + this->dbdata.database, + this->dbdata.login, + this->dbdata.password + ); + + ConnStatusType stat = PQstatus((PGconn *) this->con); + + if (stat != ConnStatusType::CONNECTION_OK) { + this->status = DatabaseStatus::MISSING_DATABASE; + + PQfinish((PGconn *) this->con); + this->con = NULL; + + if (this->dbdata.password != NULL) { + free((char *) this->dbdata.password); + this->dbdata.password = NULL; + } + } + } + + void close() + { + if (this->con != NULL) { + PQfinish((PGconn *) this->con); } - QueryResult query_execute(char *stmt, char *paramValues = NULL) - { - QueryResult result; + this->con = NULL; + this->status = DatabaseStatus::CLOSED; + } - PGresult *res; - if (paramValues != NULL) { - res = PQexecParams((PGconn *) this->con, stmt, 1, NULL, (const char* const*) paramValues, NULL, NULL, 0); - } else { - res = PQexec((PGconn *) this->con, stmt); - } + QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + QueryResult result; - if (PQresultStatus(res) != PGRES_TUPLES_OK) { - PQclear(res); - - return result; - } - - result.rows = PQntuples(res); - result.columns = PQnfields(res); - - result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); - - char *temp = NULL; - size_t valLen = 0; - - for (size_t i = 0; i < result.rows; ++i) { - for (size_t j = 0; j < result.columns; ++j) { - temp = PQgetvalue(res, i, j); - - if (temp == NULL) { - result.results[i * result.columns + j] = NULL; - - continue; - } - - valLen = strlen(temp); - - result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); - memcpy(result.results[i * result.columns + j], temp, valLen); - result.results[i * result.columns + j][valLen] = '\0'; - } - } + PGresult *res; + if (paramValues != NULL) { + res = PQexecParams((PGconn *) this->con, stmt, 1, NULL, (const char* const*) paramValues, NULL, NULL, 0); + } else { + res = PQexec((PGconn *) this->con, stmt); + } + if (PQresultStatus(res) != PGRES_TUPLES_OK) { PQclear(res); return result; } - }; - } + + result.rows = PQntuples(res); + result.columns = PQnfields(res); + + result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); + + char *temp = NULL; + size_t valLen = 0; + + for (size_t i = 0; i < result.rows; ++i) { + for (size_t j = 0; j < result.columns; ++j) { + temp = PQgetvalue(res, i, j); + + if (temp == NULL) { + result.results[i * result.columns + j] = NULL; + + continue; + } + + valLen = strlen(temp); + + result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); + memcpy(result.results[i * result.columns + j], temp, valLen); + result.results[i * result.columns + j][valLen] = '\0'; + } + } + + PQclear(res); + + return result; + } + }; } #endif \ No newline at end of file diff --git a/DataStorage/Database/Connection/SQLiteConnection.h b/DataStorage/Database/Connection/SQLiteConnection.h index a601c3d..54872ae 100755 --- a/DataStorage/Database/Connection/SQLiteConnection.h +++ b/DataStorage/Database/Connection/SQLiteConnection.h @@ -20,142 +20,139 @@ #include "../DatabaseType.h" #include "../DatabaseStatus.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - struct SQLiteConnection : ConnectionAbstract { - SQLiteConnection(DbConnectionConfig dbdata) - { - this->type = DatabaseType::MYSQL; - this->dbdata = dbdata; - } + struct SQLiteConnection : ConnectionAbstract { + SQLiteConnection(DbConnectionConfig dbdata) + { + this->type = DatabaseType::MYSQL; + this->dbdata = dbdata; + } - void connect(DbConnectionConfig *dbdata = NULL) - { - this->dbdata = dbdata == NULL ? this->dbdata : *dbdata; + void connect(DbConnectionConfig *dbdata = NULL) + { + this->dbdata = dbdata == NULL ? this->dbdata : *dbdata; - if (this->dbdata.db == DatabaseType::UNDEFINED - || this->dbdata.database == NULL - ) { - this->status = DatabaseStatus::FAILURE; + if (this->dbdata.db == DatabaseType::UNDEFINED + || this->dbdata.database == NULL + ) { + this->status = DatabaseStatus::FAILURE; - if (this->dbdata.password != NULL) { - free((char *) this->dbdata.password); - this->dbdata.password = NULL; - } - } - - this->close(); - - int stat = sqlite3_open(this->dbdata.host, (sqlite3 **) &this->con); - if (stat != SQLITE_OK) { - this->status = DatabaseStatus::MISSING_DATABASE; - - sqlite3_close((sqlite3 *) this->con); - this->con = NULL; - - if (this->dbdata.password != NULL) { - free((char *) this->dbdata.password); - this->dbdata.password = NULL; - } + if (this->dbdata.password != NULL) { + free((char *) this->dbdata.password); + this->dbdata.password = NULL; } } - void close() - { - if (this->con != NULL) { - sqlite3_close((sqlite3 *) this->con); - } + this->close(); - this->con = NULL; - this->status = DatabaseStatus::CLOSED; + int stat = sqlite3_open(this->dbdata.host, (sqlite3 **) &this->con); + if (stat != SQLITE_OK) { + this->status = DatabaseStatus::MISSING_DATABASE; + + sqlite3_close((sqlite3 *) this->con); + this->con = NULL; + + if (this->dbdata.password != NULL) { + free((char *) this->dbdata.password); + this->dbdata.password = NULL; + } + } + } + + void close() + { + if (this->con != NULL) { + sqlite3_close((sqlite3 *) this->con); } - QueryResult query_execute(char *stmt, char *paramValues = NULL) - { - QueryResult result; + this->con = NULL; + this->status = DatabaseStatus::CLOSED; + } - sqlite3_stmt *res; - int status = 0; + QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + QueryResult result; - if (paramValues != NULL) { - status = sqlite3_prepare_v2((sqlite3 *) this->con, stmt, -1, &res, 0); + sqlite3_stmt *res; + int status = 0; - // @todo sqlite3_bind_int(res, 1, 3); - } else { - status = sqlite3_prepare_v2((sqlite3 *) this->con, stmt, -1, &res, 0); - } + if (paramValues != NULL) { + status = sqlite3_prepare_v2((sqlite3 *) this->con, stmt, -1, &res, 0); - if (res == NULL) { - return result; - } + // @todo sqlite3_bind_int(res, 1, 3); + } else { + status = sqlite3_prepare_v2((sqlite3 *) this->con, stmt, -1, &res, 0); + } - status = sqlite3_step(res); + if (res == NULL) { + return result; + } - result.rows = 100; - result.columns = sqlite3_column_count(res); + status = sqlite3_step(res); - if (result.rows == 0 || result.columns == 0) { - return result; - } + result.rows = 100; + result.columns = sqlite3_column_count(res); - result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); + if (result.rows == 0 || result.columns == 0) { + return result; + } - char *temp = NULL; - size_t valLen = 0; - char ** tempStorage = NULL; + result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); - size_t i = 0; - while (status == SQLITE_ROW) { - if (i == result.rows) { - tempStorage = (char **) malloc((result.rows + 100) * result.columns * sizeof(char*)); - memcpy(tempStorage, result.results, result.rows * result.columns * sizeof(char*)); + char *temp = NULL; + size_t valLen = 0; + char ** tempStorage = NULL; - free(result.results); - result.results = tempStorage; - - result.rows += 100; - } - - for (int j = 0; j < result.columns; ++j) { - temp = (char *) sqlite3_column_text(res, j); - - if (temp == NULL) { - result.results[i * result.columns + j] = NULL; - - continue; - } - - valLen = strlen(temp); - - result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); - memcpy(result.results[i * result.columns + j], temp, valLen); - result.results[i * result.columns + j][valLen] = '\0'; - } - - status = sqlite3_step(res); - - ++i; - } - - --i; - if (i != result.rows) { - tempStorage = (char **) malloc(i * result.columns * sizeof(char*)); - memcpy(tempStorage, result.results, i * result.columns * sizeof(char*)); + size_t i = 0; + while (status == SQLITE_ROW) { + if (i == result.rows) { + tempStorage = (char **) malloc((result.rows + 100) * result.columns * sizeof(char*)); + memcpy(tempStorage, result.results, result.rows * result.columns * sizeof(char*)); free(result.results); result.results = tempStorage; - result.rows = i; + result.rows += 100; } - sqlite3_finalize(res); + for (int j = 0; j < result.columns; ++j) { + temp = (char *) sqlite3_column_text(res, j); - return result; + if (temp == NULL) { + result.results[i * result.columns + j] = NULL; + + continue; + } + + valLen = strlen(temp); + + result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); + memcpy(result.results[i * result.columns + j], temp, valLen); + result.results[i * result.columns + j][valLen] = '\0'; + } + + status = sqlite3_step(res); + + ++i; } - }; - } + + --i; + if (i != result.rows) { + tempStorage = (char **) malloc(i * result.columns * sizeof(char*)); + memcpy(tempStorage, result.results, i * result.columns * sizeof(char*)); + + free(result.results); + result.results = tempStorage; + + result.rows = i; + } + + sqlite3_finalize(res); + + return result; + } + }; } #endif \ No newline at end of file diff --git a/DataStorage/Database/DatabaseStatus.h b/DataStorage/Database/DatabaseStatus.h index 3353b2f..dfe42a1 100755 --- a/DataStorage/Database/DatabaseStatus.h +++ b/DataStorage/Database/DatabaseStatus.h @@ -10,19 +10,16 @@ #ifndef DATASTORAGE_DATABASE_STATUS_H #define DATASTORAGE_DATABASE_STATUS_H -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - typedef enum { - OK = 0, - MISSING_DATABASE = 1, - MISSING_TABLE = 2, - FAILURE = 3, - READONLY = 4, - CLOSED = 5 - } DatabaseStatus; - } + typedef enum { + OK = 0, + MISSING_DATABASE = 1, + MISSING_TABLE = 2, + FAILURE = 3, + READONLY = 4, + CLOSED = 5 + } DatabaseStatus; } #endif \ No newline at end of file diff --git a/DataStorage/Database/DatabaseType.h b/DataStorage/Database/DatabaseType.h index b2c8531..8de2d13 100755 --- a/DataStorage/Database/DatabaseType.h +++ b/DataStorage/Database/DatabaseType.h @@ -12,32 +12,29 @@ #include -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - typedef enum { - MYSQL = 1, - SQLITE = 2, - PGSQL = 3, - SQLSRV = 4, - UNDEFINED = 5 - } DatabaseType; + typedef enum { + MYSQL = 1, + SQLITE = 2, + PGSQL = 3, + SQLSRV = 4, + UNDEFINED = 5 + } DatabaseType; - DatabaseType database_type_from_str(const char* type) - { - if (strcmp(type, "mysql") == 0) { - return DatabaseType::MYSQL; - } else if (strcmp(type, "sqlite") == 0) { - return DatabaseType::SQLITE; - } else if (strcmp(type, "pqsql") == 0) { - return DatabaseType::PGSQL; - } else if (strcmp(type, "mssql") == 0) { - return DatabaseType::SQLSRV; - } - - return DatabaseType::UNDEFINED; + DatabaseType database_type_from_str(const char* type) + { + if (strcmp(type, "mysql") == 0) { + return DatabaseType::MYSQL; + } else if (strcmp(type, "sqlite") == 0) { + return DatabaseType::SQLITE; + } else if (strcmp(type, "pqsql") == 0) { + return DatabaseType::PGSQL; + } else if (strcmp(type, "mssql") == 0) { + return DatabaseType::SQLSRV; } + + return DatabaseType::UNDEFINED; } } diff --git a/DataStorage/Database/Mapper/DataMapperFactory.h b/DataStorage/Database/Mapper/DataMapperFactory.h index de7adb1..8229585 100755 --- a/DataStorage/Database/Mapper/DataMapperFactory.h +++ b/DataStorage/Database/Mapper/DataMapperFactory.h @@ -18,42 +18,39 @@ #include "ReadMapper.h" #include "MapperAbstract.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - static DataStorage::Database::ConnectionAbstract *db; - static const char *dateTimeFormat = "Y-m-d H:i:s"; + static DataStorage::Database::ConnectionAbstract *db; + static const char *dateTimeFormat = "Y-m-d H:i:s"; - struct DataMapperFactory { - static ReadMapper *reader(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) - { - ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); - readMapper->mapper = mapper; - readMapper->db = db == NULL ? DataStorage::Database::db : db; + struct DataMapperFactory { + static ReadMapper *reader(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) + { + ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); + readMapper->mapper = mapper; + readMapper->db = db == NULL ? DataStorage::Database::db : db; - return readMapper; - } + return readMapper; + } - static ReadMapper *get(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) - { - ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); - readMapper->mapper = mapper; - readMapper->db = db == NULL ? DataStorage::Database::db : db; + static ReadMapper *get(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) + { + ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); + readMapper->mapper = mapper; + readMapper->db = db == NULL ? DataStorage::Database::db : db; - return readMapper->get(); - } + return readMapper->get(); + } - static ReadMapper *getAll(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) - { - ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); - readMapper->mapper = mapper; - readMapper->db = db == NULL ? DataStorage::Database::db : db; + static ReadMapper *getAll(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) + { + ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); + readMapper->mapper = mapper; + readMapper->db = db == NULL ? DataStorage::Database::db : db; - return readMapper->getAll(); - } - }; - } + return readMapper->getAll(); + } + }; } #endif diff --git a/DataStorage/Database/Mapper/DataMapperTypes.h b/DataStorage/Database/Mapper/DataMapperTypes.h index 1643112..afdeb84 100755 --- a/DataStorage/Database/Mapper/DataMapperTypes.h +++ b/DataStorage/Database/Mapper/DataMapperTypes.h @@ -13,208 +13,205 @@ #include #include -namespace DataStorage +namespace DataStorage::Database { - namespace Database + typedef enum { + MAPPER_DEFAULT = 0, + MAPPER_GET = 1, + MAPPER_GET_ALL = 4, + MAPPER_FIND = 7, + MAPPER_GET_RAW = 8, + MAPPER_GET_RANDOM = 11, + MAPPER_COUNT_MODELS = 12, + MAPPER_CREATE = 1001, + MAPPER_UPDATE = 2001, + MAPPER_DELETE = 3001 + } MapperType; + + typedef enum { + FIELD_TYPE_INT = 1, + FIELD_TYPE_FLOAT = 2, + FIELD_TYPE_STRING = 3, + FIELD_TYPE_BOOL = 4 + } FieldType; + + typedef struct { + const char *name = NULL; + size_t size = 0; + } ModelStructure; + + void free_ModelStructure(ModelStructure *data) { - typedef enum { - MAPPER_DEFAULT = 0, - MAPPER_GET = 1, - MAPPER_GET_ALL = 4, - MAPPER_FIND = 7, - MAPPER_GET_RAW = 8, - MAPPER_GET_RANDOM = 11, - MAPPER_COUNT_MODELS = 12, - MAPPER_CREATE = 1001, - MAPPER_UPDATE = 2001, - MAPPER_DELETE = 3001 - } MapperType; + /* Not necessary + if (data->name != NULL) { + free((void *) data->name); + } + */ + } - typedef enum { - FIELD_TYPE_INT = 1, - FIELD_TYPE_FLOAT = 2, - FIELD_TYPE_STRING = 3, - FIELD_TYPE_BOOL = 4 - } FieldType; + typedef struct { + const char *name = NULL; + int type = FieldType::FIELD_TYPE_INT; + const char *internal = NULL; + bool readonly = false; + bool autocomplete = false; + } DataMapperColumn; - typedef struct { - const char *name = NULL; - size_t size = 0; - } ModelStructure; - - void free_ModelStructure(ModelStructure *data) - { - /* Not necessary - if (data->name != NULL) { - free((void *) data->name); - } - */ + void free_DataMapperColumn(DataMapperColumn *data) + { + if (data->name != NULL) { + free((void *) data->name); } - typedef struct { - const char *name = NULL; - int type = FieldType::FIELD_TYPE_INT; - const char *internal = NULL; - bool readonly = false; - bool autocomplete = false; - } DataMapperColumn; + if (data->internal != NULL) { + free((void *) data->internal); + } + } - void free_DataMapperColumn(DataMapperColumn *data) - { - if (data->name != NULL) { - free((void *) data->name); - } + typedef struct { + const char *member = NULL; + const char *mapper = NULL; + const char *external = NULL; + const char *table = NULL; + const char *self = NULL; + const char *column = NULL; + bool conditional = false; + const char *by = NULL; + } TableRelation; - if (data->internal != NULL) { - free((void *) data->internal); - } + void free_TableRelation(TableRelation *data) + { + /* Not necessary + if (data->member != NULL) { + free((void *) data->member); } - typedef struct { - const char *member = NULL; - const char *mapper = NULL; - const char *external = NULL; - const char *table = NULL; - const char *self = NULL; - const char *column = NULL; - bool conditional = false; - const char *by = NULL; - } TableRelation; - - void free_TableRelation(TableRelation *data) - { - /* Not necessary - if (data->member != NULL) { - free((void *) data->member); - } - - if (data->mapper != NULL) { - free((void *) data->mapper); - } - - if (data->external != NULL) { - free((void *) data->external); - } - - if (data->table != NULL) { - free((void *) data->table); - } - - if (data->self != NULL) { - free((void *) data->self); - } - - if (data->column != NULL) { - free((void *) data->column); - } - - if (data->self != NULL) { - free((void *) data->self); - } - - if (data->by != NULL) { - free((void *) data->by); - } - */ + if (data->mapper != NULL) { + free((void *) data->mapper); } - typedef struct { - const char *TABLE = NULL; - const char *PRIMARYFIELD = NULL; - const char *CREATED_AT = NULL; - const char *PARENT = NULL; - void *MODEL = NULL; + if (data->external != NULL) { + free((void *) data->external); + } - int MEMBER_COUNT = 0; - DataStorage::Database::ModelStructure *MODEL_STRUCTURE = NULL; + if (data->table != NULL) { + free((void *) data->table); + } - int COLUMN_COUNT = 0; - DataStorage::Database::DataMapperColumn *COLUMNS = NULL; + if (data->self != NULL) { + free((void *) data->self); + } - int OWNS_ONE_COUNT = 0; - DataStorage::Database::TableRelation *OWNS_ONE = NULL; + if (data->column != NULL) { + free((void *) data->column); + } - int HAS_MANY_COUNT = 0; - DataStorage::Database::TableRelation *HAS_MANY = NULL; + if (data->self != NULL) { + free((void *) data->self); + } - int BELONGS_TO_COUNT = 0; - DataStorage::Database::TableRelation *BELONGS_TO = NULL; - } MapperData; + if (data->by != NULL) { + free((void *) data->by); + } + */ + } - void free_MapperData(DataStorage::Database::MapperData *data) - { - /* Not necessary - if (data->TABLE != NULL) { - free((void *) data->TABLE); - } + typedef struct { + const char *TABLE = NULL; + const char *PRIMARYFIELD = NULL; + const char *CREATED_AT = NULL; + const char *PARENT = NULL; + void *MODEL = NULL; - if (data->PRIMARYFIELD != NULL) { - free((void *) data->PRIMARYFIELD); - } + int MEMBER_COUNT = 0; + DataStorage::Database::ModelStructure *MODEL_STRUCTURE = NULL; - if (data->CREATED_AT != NULL) { - free((void *) data->CREATED_AT); - } + int COLUMN_COUNT = 0; + DataStorage::Database::DataMapperColumn *COLUMNS = NULL; - if (data->PARENT != NULL) { - free((void *) data->PARENT); - } + int OWNS_ONE_COUNT = 0; + DataStorage::Database::TableRelation *OWNS_ONE = NULL; - if (data->MODEL != NULL) { - free(data->MODEL); + int HAS_MANY_COUNT = 0; + DataStorage::Database::TableRelation *HAS_MANY = NULL; + + int BELONGS_TO_COUNT = 0; + DataStorage::Database::TableRelation *BELONGS_TO = NULL; + } MapperData; + + void free_MapperData(DataStorage::Database::MapperData *data) + { + /* Not necessary + if (data->TABLE != NULL) { + free((void *) data->TABLE); + } + + if (data->PRIMARYFIELD != NULL) { + free((void *) data->PRIMARYFIELD); + } + + if (data->CREATED_AT != NULL) { + free((void *) data->CREATED_AT); + } + + if (data->PARENT != NULL) { + free((void *) data->PARENT); + } + + if (data->MODEL != NULL) { + free(data->MODEL); + } + */ + + int i = 0; + if (data->MODEL_STRUCTURE != NULL) { + /* not neccessary + for (i = 0; i < data->MEMBER_COUNT; ++i) { + free_ModelStructure(&data->MODEL_STRUCTURE[i]); } */ - int i = 0; - if (data->MODEL_STRUCTURE != NULL) { - /* not neccessary - for (i = 0; i < data->MEMBER_COUNT; ++i) { - free_ModelStructure(&data->MODEL_STRUCTURE[i]); - } - */ + free(data->MODEL_STRUCTURE); + } - free(data->MODEL_STRUCTURE); + if (data->COLUMNS != NULL) { + /* not neccessary + for (i = 0; i < data->COLUMN_COUNT; ++i) { + free_DataMapperColumn(&data->COLUMNS[i]); } + */ - if (data->COLUMNS != NULL) { - /* not neccessary - for (i = 0; i < data->COLUMN_COUNT; ++i) { - free_DataMapperColumn(&data->COLUMNS[i]); - } - */ + free(data->COLUMNS); + } - free(data->COLUMNS); + if (data->OWNS_ONE != NULL) { + /* not neccessary + for (i = 0; i < data->OWNS_ONE_COUNT; ++i) { + free_TableRelation(&data->OWNS_ONE[i]); } + */ - if (data->OWNS_ONE != NULL) { - /* not neccessary - for (i = 0; i < data->OWNS_ONE_COUNT; ++i) { - free_TableRelation(&data->OWNS_ONE[i]); - } - */ + free(data->OWNS_ONE); + } - free(data->OWNS_ONE); + if (data->HAS_MANY != NULL) { + /* not neccessary + for (i = 0; i < data->HAS_MANY_COUNT; ++i) { + free_TableRelation(&data->HAS_MANY[i]); } + */ - if (data->HAS_MANY != NULL) { - /* not neccessary - for (i = 0; i < data->HAS_MANY_COUNT; ++i) { - free_TableRelation(&data->HAS_MANY[i]); - } - */ + free(data->HAS_MANY); + } - free(data->HAS_MANY); + if (data->BELONGS_TO != NULL) { + /* not neccessary + for (i = 0; i < data->BELONGS_TO_COUNT; ++i) { + free_TableRelation(&data->BELONGS_TO[i]); } + */ - if (data->BELONGS_TO != NULL) { - /* not neccessary - for (i = 0; i < data->BELONGS_TO_COUNT; ++i) { - free_TableRelation(&data->BELONGS_TO[i]); - } - */ - - free(data->BELONGS_TO); - } + free(data->BELONGS_TO); } } } diff --git a/DataStorage/Database/Mapper/MapperAbstract.h b/DataStorage/Database/Mapper/MapperAbstract.h index 443995c..44a6db3 100755 --- a/DataStorage/Database/Mapper/MapperAbstract.h +++ b/DataStorage/Database/Mapper/MapperAbstract.h @@ -12,96 +12,94 @@ #include #include +#include #include "../Connection/ConnectionAbstract.h" #include "DataMapperTypes.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - struct MapperAbstract { - const DataStorage::Database::MapperData *mapper = NULL; + struct MapperAbstract { + const DataStorage::Database::MapperData *mapper = NULL; - const DataStorage::Database::ConnectionAbstract *db = NULL; + const DataStorage::Database::ConnectionAbstract *db = NULL; - DataStorage::Database::MapperType type = DataStorage::Database::MapperType::MAPPER_DEFAULT; + DataStorage::Database::MapperType type = DataStorage::Database::MapperType::MAPPER_DEFAULT; - int MEMBERS = 0; + int MEMBERS = 0; - int COLUMN_COUNT = 0; + int COLUMN_COUNT = 0; - DataStorage::Database::ModelStructure *MODEL_STRUCTURE = NULL; + DataStorage::Database::ModelStructure *MODEL_STRUCTURE = NULL; - char *PRIMARYFIELD = NULL; + char *PRIMARYFIELD = NULL; - bool AUTOINCREMENT = true; + bool AUTOINCREMENT = true; - char *CREATE_AT = NULL; + char *CREATE_AT = NULL; - char *TABLE = NULL; + char *TABLE = NULL; - char *PARENT = NULL; + char *PARENT = NULL; - char *MODEL = NULL; + char *MODEL = NULL; - DataStorage::Database::DataMapperColumn *COLUMNS = NULL; + DataStorage::Database::DataMapperColumn *COLUMNS = NULL; - DataStorage::Database::TableRelation *HAS_MANY = NULL; + DataStorage::Database::TableRelation *HAS_MANY = NULL; - DataStorage::Database::TableRelation *OWNS_ONE = NULL; + DataStorage::Database::TableRelation *OWNS_ONE = NULL; - DataStorage::Database::TableRelation *BELONGS_TO = NULL; + DataStorage::Database::TableRelation *BELONGS_TO = NULL; - void *address(uintptr_t objPos, char *name) - { - uintptr_t pos = objPos; - for (int i = 0; i < this->MEMBERS; ++i) { - if (strcmp(this->MODEL_STRUCTURE[i].name, name) == 0) { - return (void *) pos; - } - - pos += this->MODEL_STRUCTURE[i].size; + void *address(uintptr_t objPos, char *name) + { + uintptr_t pos = objPos; + for (int i = 0; i < this->MEMBERS; ++i) { + if (strcmp(this->MODEL_STRUCTURE[i].name, name) == 0) { + return (void *) pos; } - return NULL; + pos += this->MODEL_STRUCTURE[i].size; } - DataMapperColumn *findByColumnName(char *column) - { - for (int i = 0; i < this->COLUMN_COUNT; ++i) { - if (strcmp(this->COLUMNS[i].name, column) == 0) { - return &this->COLUMNS[i]; - } + return NULL; + } + + DataMapperColumn *findByColumnName(char *column) + { + for (int i = 0; i < this->COLUMN_COUNT; ++i) { + if (strcmp(this->COLUMNS[i].name, column) == 0) { + return &this->COLUMNS[i]; } - - return NULL; } - DataMapperColumn *findByMemberName(char *member) - { - for (int i = 0; i < this->COLUMN_COUNT; ++i) { - if (strcmp(this->COLUMNS[i].internal, member) == 0) { - return &this->COLUMNS[i]; - } + return NULL; + } + + DataMapperColumn *findByMemberName(char *member) + { + for (int i = 0; i < this->COLUMN_COUNT; ++i) { + if (strcmp(this->COLUMNS[i].internal, member) == 0) { + return &this->COLUMNS[i]; } - - return NULL; } - MapperAbstract *where( - char *member, - void *value, - int valueType, - const char *logic = "=", - const char *connector = "AND" - ) { - return this; - } + return NULL; + } - virtual void *execute(void *options = NULL); - }; - } + MapperAbstract *where( + char *member, + void *value, + int valueType, + const char *logic = "=", + const char *connector = "AND" + ) { + return this; + } + + virtual void *execute(void *options = NULL); + }; } #endif diff --git a/DataStorage/Database/Mapper/ReadMapper.h b/DataStorage/Database/Mapper/ReadMapper.h index cf68a09..52baf1c 100755 --- a/DataStorage/Database/Mapper/ReadMapper.h +++ b/DataStorage/Database/Mapper/ReadMapper.h @@ -17,54 +17,51 @@ #include "DataMapperFactory.h" #include "MapperAbstract.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database - { - struct ReadMapper : MapperAbstract { - ReadMapper *get() - { - return this; - } + struct ReadMapper : MapperAbstract { + ReadMapper *get() + { + return this; + } - ReadMapper *getAll() - { - return this; - } + ReadMapper *getAll() + { + return this; + } - void *execute(void *options = NULL) - { - switch(this->type) { - case DataStorage::Database::MapperType::MAPPER_GET: - return this->executeGet(options); - case DataStorage::Database::MapperType::MAPPER_GET_RAW: - return this->executeGetRaw(options); - case DataStorage::Database::MapperType::MAPPER_GET_ALL: - return this->executeGetAll(options); - default: - return NULL; - }; - } + void *execute(void *options = NULL) + { + switch(this->type) { + case DataStorage::Database::MapperType::MAPPER_GET: + return this->executeGet(options); + case DataStorage::Database::MapperType::MAPPER_GET_RAW: + return this->executeGetRaw(options); + case DataStorage::Database::MapperType::MAPPER_GET_ALL: + return this->executeGetAll(options); + default: + return NULL; + }; + } - void *executeGet(void *options) - { - int *primaryKeys = NULL; - const char *memberOfPrimaryField = findByColumnName((char *) this->mapper->PRIMARYFIELD)->internal; + void *executeGet(void *options) + { + int *primaryKeys = NULL; + const char *memberOfPrimaryField = findByColumnName((char *) this->mapper->PRIMARYFIELD)->internal; - return NULL; - } + return NULL; + } - void *executeGetRaw(void *options) - { - return NULL; - } + void *executeGetRaw(void *options) + { + return NULL; + } - void *executeGetAll(void *options) - { - return NULL; - } - }; - } + void *executeGetAll(void *options) + { + return NULL; + } + }; } #endif diff --git a/DataStorage/Database/Schema/DbField.h b/DataStorage/Database/Schema/DbField.h index f72d08e..881bb89 100755 --- a/DataStorage/Database/Schema/DbField.h +++ b/DataStorage/Database/Schema/DbField.h @@ -13,48 +13,45 @@ #include #include -namespace DataStorage +namespace DataStorage::Database { - namespace Database + typedef struct { + char *name; + char *type; + void *def; + bool is_nullable = true; + bool is_primary = false; + bool is_unique = false; + bool autoincrement = false; + char *foreignTable; + char *foreignKey; + } DbField; + + void free_DbField(DbField *field) { - typedef struct { - char *name; - char *type; - void *def; - bool is_nullable = true; - bool is_primary = false; - bool is_unique = false; - bool autoincrement = false; - char *foreignTable; - char *foreignKey; - } DbField; + if (field->name != NULL) { + free(field->name); + field->name = NULL; + } - void free_DbField(DbField *field) - { - if (field->name != NULL) { - free(field->name); - field->name = NULL; - } + if (field->type != NULL) { + free(field->type); + field->type = NULL; + } - if (field->type != NULL) { - free(field->type); - field->type = NULL; - } + if (field->def != NULL) { + free(field->def); + field->def = NULL; + } - if (field->def != NULL) { - free(field->def); - field->def = NULL; - } + if (field->foreignTable != NULL) { + free(field->foreignTable); + field->foreignTable = NULL; + } - if (field->foreignTable != NULL) { - free(field->foreignTable); - field->foreignTable = NULL; - } - - if (field->foreignKey != NULL) { - free(field->foreignKey); - field->foreignKey = NULL; - } + if (field->foreignKey != NULL) { + free(field->foreignKey); + field->foreignKey = NULL; } } } diff --git a/DataStorage/Database/Schema/DbSchema.h b/DataStorage/Database/Schema/DbSchema.h index 24dc25f..3ae2b47 100755 --- a/DataStorage/Database/Schema/DbSchema.h +++ b/DataStorage/Database/Schema/DbSchema.h @@ -15,31 +15,28 @@ #include "DbField.h" -namespace DataStorage +namespace DataStorage::Database { - namespace Database + typedef struct { + char *name; + DbField *fields; + size_t field_size = 0; + } DbSchema; + + void free_DbSchema(DbSchema *schema) { - typedef struct { - char *name; - DbField *fields; - size_t field_size = 0; - } DbSchema; + if (schema->name != NULL) { + free(schema->name); + schema->name = NULL; + } - void free_DbSchema(DbSchema *schema) - { - if (schema->name != NULL) { - free(schema->name); - schema->name = NULL; + if (schema->fields != NULL) { + for (int i = 0; i < schema->field_size; ++i) { + free_DbField(&schema->fields[i]); } - if (schema->fields != NULL) { - for (int i = 0; i < schema->field_size; ++i) { - free_DbField(&schema->fields[i]); - } - - free(schema->fields); - schema->fields = NULL; - } + free(schema->fields); + schema->fields = NULL; } } } diff --git a/Hash/MD5.h b/Hash/MD5.h index 50fc6ea..4b05ab6 100755 --- a/Hash/MD5.h +++ b/Hash/MD5.h @@ -2,6 +2,8 @@ #define HASH_MD5_H #include +#include +#include // https://www.rfc-editor.org/rfc/rfc1321 @@ -37,7 +39,7 @@ namespace Hash { uint32_t a, b, c, d; uint32_t aa, bb, cc, dd; - ptr = data; + ptr = (const unsigned char *) data; a = ctx->a; b = ctx->b; diff --git a/Hash/MeowHash.h b/Hash/MeowHash.h index 100783d..8fa3b3d 100755 --- a/Hash/MeowHash.h +++ b/Hash/MeowHash.h @@ -116,6 +116,7 @@ #define HASH_MEOW_H // #include +#include #if !defined(meow_u8) #define MEOW_HASH_VERSION 5 @@ -199,546 +200,543 @@ pxor(r2, r3) #endif -namespace Hash +namespace Hash::Meow { - namespace Meow - { - #if MEOW_DUMP - struct meow_dump - { - meow_u128 xmm[8]; - void *Ptr; - char const *Title; - }; - extern "C" meow_dump *MeowDumpTo; - meow_dump *MeowDumpTo; - #define MEOW_DUMP_STATE(T, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, ptr) \ - if(MeowDumpTo) \ - { \ - MeowDumpTo->xmm[0] = xmm0; \ - MeowDumpTo->xmm[1] = xmm1; \ - MeowDumpTo->xmm[2] = xmm2; \ - MeowDumpTo->xmm[3] = xmm3; \ - MeowDumpTo->xmm[4] = xmm4; \ - MeowDumpTo->xmm[5] = xmm5; \ - MeowDumpTo->xmm[6] = xmm6; \ - MeowDumpTo->xmm[7] = xmm7; \ - MeowDumpTo->Ptr = ptr; \ - MeowDumpTo->Title = T; \ - ++MeowDumpTo; \ - } - #else - #define MEOW_DUMP_STATE(...) - #endif - - static meow_u8 MeowShiftAdjust[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - static meow_u8 MeowMaskLen[32] = {255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; - - // NOTE(casey): The default seed is now a "nothing-up-our-sleeves" number for good measure. You may verify that it is just an encoding of Pi. - static meow_u8 MeowDefaultSeed[128] = + #if MEOW_DUMP + struct meow_dump { - 0x32, 0x43, 0xF6, 0xA8, 0x88, 0x5A, 0x30, 0x8D, - 0x31, 0x31, 0x98, 0xA2, 0xE0, 0x37, 0x07, 0x34, - 0x4A, 0x40, 0x93, 0x82, 0x22, 0x99, 0xF3, 0x1D, - 0x00, 0x82, 0xEF, 0xA9, 0x8E, 0xC4, 0xE6, 0xC8, - 0x94, 0x52, 0x82, 0x1E, 0x63, 0x8D, 0x01, 0x37, - 0x7B, 0xE5, 0x46, 0x6C, 0xF3, 0x4E, 0x90, 0xC6, - 0xCC, 0x0A, 0xC2, 0x9B, 0x7C, 0x97, 0xC5, 0x0D, - 0xD3, 0xF8, 0x4D, 0x5B, 0x5B, 0x54, 0x70, 0x91, - 0x79, 0x21, 0x6D, 0x5D, 0x98, 0x97, 0x9F, 0xB1, - 0xBD, 0x13, 0x10, 0xBA, 0x69, 0x8D, 0xFB, 0x5A, - 0xC2, 0xFF, 0xD7, 0x2D, 0xBD, 0x01, 0xAD, 0xFB, - 0x7B, 0x8E, 0x1A, 0xFE, 0xD6, 0xA2, 0x67, 0xE9, - 0x6B, 0xA7, 0xC9, 0x04, 0x5F, 0x12, 0xC7, 0xF9, - 0x92, 0x4A, 0x19, 0x94, 0x7B, 0x39, 0x16, 0xCF, - 0x70, 0x80, 0x1F, 0x2E, 0x28, 0x58, 0xEF, 0xC1, - 0x66, 0x36, 0x92, 0x0D, 0x87, 0x15, 0x74, 0xE6 + meow_u128 xmm[8]; + void *Ptr; + char const *Title; }; + extern "C" meow_dump *MeowDumpTo; + meow_dump *MeowDumpTo; + #define MEOW_DUMP_STATE(T, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, ptr) \ + if(MeowDumpTo) \ + { \ + MeowDumpTo->xmm[0] = xmm0; \ + MeowDumpTo->xmm[1] = xmm1; \ + MeowDumpTo->xmm[2] = xmm2; \ + MeowDumpTo->xmm[3] = xmm3; \ + MeowDumpTo->xmm[4] = xmm4; \ + MeowDumpTo->xmm[5] = xmm5; \ + MeowDumpTo->xmm[6] = xmm6; \ + MeowDumpTo->xmm[7] = xmm7; \ + MeowDumpTo->Ptr = ptr; \ + MeowDumpTo->Title = T; \ + ++MeowDumpTo; \ + } + #else + #define MEOW_DUMP_STATE(...) + #endif + + static meow_u8 MeowShiftAdjust[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + static meow_u8 MeowMaskLen[32] = {255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; + + // NOTE(casey): The default seed is now a "nothing-up-our-sleeves" number for good measure. You may verify that it is just an encoding of Pi. + static meow_u8 MeowDefaultSeed[128] = + { + 0x32, 0x43, 0xF6, 0xA8, 0x88, 0x5A, 0x30, 0x8D, + 0x31, 0x31, 0x98, 0xA2, 0xE0, 0x37, 0x07, 0x34, + 0x4A, 0x40, 0x93, 0x82, 0x22, 0x99, 0xF3, 0x1D, + 0x00, 0x82, 0xEF, 0xA9, 0x8E, 0xC4, 0xE6, 0xC8, + 0x94, 0x52, 0x82, 0x1E, 0x63, 0x8D, 0x01, 0x37, + 0x7B, 0xE5, 0x46, 0x6C, 0xF3, 0x4E, 0x90, 0xC6, + 0xCC, 0x0A, 0xC2, 0x9B, 0x7C, 0x97, 0xC5, 0x0D, + 0xD3, 0xF8, 0x4D, 0x5B, 0x5B, 0x54, 0x70, 0x91, + 0x79, 0x21, 0x6D, 0x5D, 0x98, 0x97, 0x9F, 0xB1, + 0xBD, 0x13, 0x10, 0xBA, 0x69, 0x8D, 0xFB, 0x5A, + 0xC2, 0xFF, 0xD7, 0x2D, 0xBD, 0x01, 0xAD, 0xFB, + 0x7B, 0x8E, 0x1A, 0xFE, 0xD6, 0xA2, 0x67, 0xE9, + 0x6B, 0xA7, 0xC9, 0x04, 0x5F, 0x12, 0xC7, 0xF9, + 0x92, 0x4A, 0x19, 0x94, 0x7B, 0x39, 0x16, 0xCF, + 0x70, 0x80, 0x1F, 0x2E, 0x28, 0x58, 0xEF, 0xC1, + 0x66, 0x36, 0x92, 0x0D, 0x87, 0x15, 0x74, 0xE6 + }; + + // + // NOTE(casey): Single block version + // + + static meow_u128 + MeowHash(void *Seed128Init, meow_umm Len, void *SourceInit) + { + meow_u128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // NOTE(casey): xmm0-xmm7 are the hash accumulation lanes + meow_u128 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; // NOTE(casey): xmm8-xmm15 hold values to be appended (residual, length) + + meow_u8 *rax = (meow_u8 *)SourceInit; + meow_u8 *rcx = (meow_u8 *)Seed128Init; // - // NOTE(casey): Single block version + // NOTE(casey): Seed the eight hash registers // - static meow_u128 - MeowHash(void *Seed128Init, meow_umm Len, void *SourceInit) + movdqu(xmm0, rcx + 0x00); + movdqu(xmm1, rcx + 0x10); + movdqu(xmm2, rcx + 0x20); + movdqu(xmm3, rcx + 0x30); + + movdqu(xmm4, rcx + 0x40); + movdqu(xmm5, rcx + 0x50); + movdqu(xmm6, rcx + 0x60); + movdqu(xmm7, rcx + 0x70); + + MEOW_DUMP_STATE("Seed", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + // + // NOTE(casey): Hash all full 256-byte blocks + // + + meow_umm BlockCount = (Len >> 8); + if(BlockCount > MEOW_PREFETCH_LIMIT) { - meow_u128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // NOTE(casey): xmm0-xmm7 are the hash accumulation lanes - meow_u128 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; // NOTE(casey): xmm8-xmm15 hold values to be appended (residual, length) - - meow_u8 *rax = (meow_u8 *)SourceInit; - meow_u8 *rcx = (meow_u8 *)Seed128Init; - - // - // NOTE(casey): Seed the eight hash registers - // - - movdqu(xmm0, rcx + 0x00); - movdqu(xmm1, rcx + 0x10); - movdqu(xmm2, rcx + 0x20); - movdqu(xmm3, rcx + 0x30); - - movdqu(xmm4, rcx + 0x40); - movdqu(xmm5, rcx + 0x50); - movdqu(xmm6, rcx + 0x60); - movdqu(xmm7, rcx + 0x70); - - MEOW_DUMP_STATE("Seed", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - // - // NOTE(casey): Hash all full 256-byte blocks - // - - meow_umm BlockCount = (Len >> 8); - if(BlockCount > MEOW_PREFETCH_LIMIT) + // NOTE(casey): For large input, modern Intel x64's can't hit full speed without prefetching, so we use this loop + while(BlockCount--) { - // NOTE(casey): For large input, modern Intel x64's can't hit full speed without prefetching, so we use this loop - while(BlockCount--) - { - prefetcht0(rax + MEOW_PREFETCH + 0x00); - prefetcht0(rax + MEOW_PREFETCH + 0x40); - prefetcht0(rax + MEOW_PREFETCH + 0x80); - prefetcht0(rax + MEOW_PREFETCH + 0xc0); + prefetcht0(rax + MEOW_PREFETCH + 0x00); + prefetcht0(rax + MEOW_PREFETCH + 0x40); + prefetcht0(rax + MEOW_PREFETCH + 0x80); + prefetcht0(rax + MEOW_PREFETCH + 0xc0); - MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); - MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); - MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); - MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); - MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); - MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); - MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); - MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); + MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); + MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); + MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); + MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); + MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); + MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); + MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); + MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); - rax += 0x100; - } + rax += 0x100; } - else + } + else + { + // NOTE(casey): For small input, modern Intel x64's can't hit full speed _with_ prefetching (because of port pressure), so we use this loop. + while(BlockCount--) { - // NOTE(casey): For small input, modern Intel x64's can't hit full speed _with_ prefetching (because of port pressure), so we use this loop. - while(BlockCount--) - { - MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); - MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); - MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); - MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); - MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); - MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); - MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); - MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); + MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); + MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); + MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); + MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); + MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); + MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); + MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); + MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); - rax += 0x100; - } + rax += 0x100; } + } - MEOW_DUMP_STATE("PostBlocks", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + MEOW_DUMP_STATE("PostBlocks", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - // - // NOTE(casey): Load any less-than-32-byte residual - // + // + // NOTE(casey): Load any less-than-32-byte residual + // - pxor_clear(xmm9, xmm9); - pxor_clear(xmm11, xmm11); + pxor_clear(xmm9, xmm9); + pxor_clear(xmm11, xmm11); - // - // TODO(casey): I need to put more thought into how the end-of-buffer stuff is actually working out here, - // because I _think_ it may be possible to remove the first branch (on Len8) and let the mask zero out the - // result, but it would take a little thought to make sure it couldn't read off the end of the buffer due - // to the & 0xf on the align computation. - // + // + // TODO(casey): I need to put more thought into how the end-of-buffer stuff is actually working out here, + // because I _think_ it may be possible to remove the first branch (on Len8) and let the mask zero out the + // result, but it would take a little thought to make sure it couldn't read off the end of the buffer due + // to the & 0xf on the align computation. + // - // NOTE(casey): First, we have to load the part that is _not_ 16-byte aligned - meow_u8 *Last = (meow_u8 *)SourceInit + (Len & ~0xf); - int unsigned Len8 = (Len & 0xf); - if(Len8) - { - // NOTE(casey): Load the mask early - movdqu(xmm8, &MeowMaskLen[0x10 - Len8]); + // NOTE(casey): First, we have to load the part that is _not_ 16-byte aligned + meow_u8 *Last = (meow_u8 *)SourceInit + (Len & ~0xf); + int unsigned Len8 = (Len & 0xf); + if(Len8) + { + // NOTE(casey): Load the mask early + movdqu(xmm8, &MeowMaskLen[0x10 - Len8]); - meow_u8 *LastOk = (meow_u8*)((((meow_umm)(((meow_u8 *)SourceInit)+Len - 1)) | (MEOW_PAGESIZE - 1)) - 16); - int Align = (Last > LastOk) ? ((int)(meow_umm)Last) & 0xf : 0; - movdqu(xmm10, &MeowShiftAdjust[Align]); - movdqu(xmm9, Last - Align); - pshufb(xmm9, xmm10); + meow_u8 *LastOk = (meow_u8*)((((meow_umm)(((meow_u8 *)SourceInit)+Len - 1)) | (MEOW_PAGESIZE - 1)) - 16); + int Align = (Last > LastOk) ? ((int)(meow_umm)Last) & 0xf : 0; + movdqu(xmm10, &MeowShiftAdjust[Align]); + movdqu(xmm9, Last - Align); + pshufb(xmm9, xmm10); - // NOTE(jeffr): and off the extra bytes - pand(xmm9, xmm8); - } + // NOTE(jeffr): and off the extra bytes + pand(xmm9, xmm8); + } - // NOTE(casey): Next, we have to load the part that _is_ 16-byte aligned - if(Len & 0x10) - { - xmm11 = xmm9; - movdqu(xmm9, Last - 0x10); - } - - // - // NOTE(casey): Construct the residual and length injests - // - - xmm8 = xmm9; - xmm10 = xmm9; - palignr(xmm8, xmm11, 15); - palignr(xmm10, xmm11, 1); - - // NOTE(casey): We have room for a 128-bit nonce and a 64-bit none here, but - // the decision was made to leave them zero'd so as not to confuse people - // about hwo to use them or what security implications they had. - pxor_clear(xmm12, xmm12); - pxor_clear(xmm13, xmm13); - pxor_clear(xmm14, xmm14); - movq(xmm15, Len); - palignr(xmm12, xmm15, 15); - palignr(xmm14, xmm15, 1); - - MEOW_DUMP_STATE("Residuals", xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 0); - - // NOTE(casey): To maintain the mix-down pattern, we always Meow Mix the less-than-32-byte residual, even if it was empty - MEOW_MIX_REG(xmm0, xmm4, xmm6, xmm1, xmm2, xmm8, xmm9, xmm10, xmm11); - - // NOTE(casey): Append the length, to avoid problems with our 32-byte padding - MEOW_MIX_REG(xmm1, xmm5, xmm7, xmm2, xmm3, xmm12, xmm13, xmm14, xmm15); - - MEOW_DUMP_STATE("PostAppend", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - // - // NOTE(casey): Hash all full 32-byte blocks - // - int unsigned LaneCount = (Len >> 5) & 0x7; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x00); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x20); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x40); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0x60); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0x80); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xa0); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0xc0); --LaneCount; - - // - // NOTE(casey): Mix the eight lanes down to one 128-bit hash - // - - MixDown: - - MEOW_DUMP_STATE("PostLanes", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); - MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); - MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); - MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); - MEOW_SHUFFLE(xmm4, xmm5, xmm6, xmm0, xmm1, xmm2); - MEOW_SHUFFLE(xmm5, xmm6, xmm7, xmm1, xmm2, xmm3); - MEOW_SHUFFLE(xmm6, xmm7, xmm0, xmm2, xmm3, xmm4); - MEOW_SHUFFLE(xmm7, xmm0, xmm1, xmm3, xmm4, xmm5); - MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); - MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); - MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); - MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); - - MEOW_DUMP_STATE("PostMix", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - paddq(xmm0, xmm2); - paddq(xmm1, xmm3); - paddq(xmm4, xmm6); - paddq(xmm5, xmm7); - pxor(xmm0, xmm1); - pxor(xmm4, xmm5); - paddq(xmm0, xmm4); - - MEOW_DUMP_STATE("PostFold", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - return(xmm0); + // NOTE(casey): Next, we have to load the part that _is_ 16-byte aligned + if(Len & 0x10) + { + xmm11 = xmm9; + movdqu(xmm9, Last - 0x10); } // - // NOTE(casey): Streaming construction + // NOTE(casey): Construct the residual and length injests // - typedef struct meow_state + xmm8 = xmm9; + xmm10 = xmm9; + palignr(xmm8, xmm11, 15); + palignr(xmm10, xmm11, 1); + + // NOTE(casey): We have room for a 128-bit nonce and a 64-bit none here, but + // the decision was made to leave them zero'd so as not to confuse people + // about hwo to use them or what security implications they had. + pxor_clear(xmm12, xmm12); + pxor_clear(xmm13, xmm13); + pxor_clear(xmm14, xmm14); + movq(xmm15, Len); + palignr(xmm12, xmm15, 15); + palignr(xmm14, xmm15, 1); + + MEOW_DUMP_STATE("Residuals", xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 0); + + // NOTE(casey): To maintain the mix-down pattern, we always Meow Mix the less-than-32-byte residual, even if it was empty + MEOW_MIX_REG(xmm0, xmm4, xmm6, xmm1, xmm2, xmm8, xmm9, xmm10, xmm11); + + // NOTE(casey): Append the length, to avoid problems with our 32-byte padding + MEOW_MIX_REG(xmm1, xmm5, xmm7, xmm2, xmm3, xmm12, xmm13, xmm14, xmm15); + + MEOW_DUMP_STATE("PostAppend", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + // + // NOTE(casey): Hash all full 32-byte blocks + // + int unsigned LaneCount = (Len >> 5) & 0x7; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x00); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x20); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x40); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0x60); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0x80); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xa0); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0xc0); --LaneCount; + + // + // NOTE(casey): Mix the eight lanes down to one 128-bit hash + // + + MixDown: + + MEOW_DUMP_STATE("PostLanes", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); + MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); + MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); + MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); + MEOW_SHUFFLE(xmm4, xmm5, xmm6, xmm0, xmm1, xmm2); + MEOW_SHUFFLE(xmm5, xmm6, xmm7, xmm1, xmm2, xmm3); + MEOW_SHUFFLE(xmm6, xmm7, xmm0, xmm2, xmm3, xmm4); + MEOW_SHUFFLE(xmm7, xmm0, xmm1, xmm3, xmm4, xmm5); + MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); + MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); + MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); + MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); + + MEOW_DUMP_STATE("PostMix", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + paddq(xmm0, xmm2); + paddq(xmm1, xmm3); + paddq(xmm4, xmm6); + paddq(xmm5, xmm7); + pxor(xmm0, xmm1); + pxor(xmm4, xmm5); + paddq(xmm0, xmm4); + + MEOW_DUMP_STATE("PostFold", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + return(xmm0); + } + + // + // NOTE(casey): Streaming construction + // + + typedef struct meow_state + { + meow_u128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + meow_u64 TotalLengthInBytes; + + int unsigned BufferLen; + + meow_u8 Buffer[256]; + meow_u128 Pad[2]; // NOTE(casey): So we know we can over-read Buffer as necessary + } meow_state; + + static void + MeowBegin(meow_state *State, void *Seed128) + { + meow_u8 *rcx = (meow_u8 *)Seed128; + + movdqu(State->xmm0, rcx + 0x00); + movdqu(State->xmm1, rcx + 0x10); + movdqu(State->xmm2, rcx + 0x20); + movdqu(State->xmm3, rcx + 0x30); + movdqu(State->xmm4, rcx + 0x40); + movdqu(State->xmm5, rcx + 0x50); + movdqu(State->xmm6, rcx + 0x60); + movdqu(State->xmm7, rcx + 0x70); + + MEOW_DUMP_STATE("Seed", State->xmm0, State->xmm1, State->xmm2, State->xmm3, State->xmm4, State->xmm5, State->xmm6, State->xmm7, 0); + + State->BufferLen = 0; + State->TotalLengthInBytes = 0; + } + + static void + MeowAbsorbBlocks(meow_state *State, meow_umm BlockCount, meow_u8 *rax) + { + meow_u128 xmm0 = State->xmm0; + meow_u128 xmm1 = State->xmm1; + meow_u128 xmm2 = State->xmm2; + meow_u128 xmm3 = State->xmm3; + meow_u128 xmm4 = State->xmm4; + meow_u128 xmm5 = State->xmm5; + meow_u128 xmm6 = State->xmm6; + meow_u128 xmm7 = State->xmm7; + + if(BlockCount > MEOW_PREFETCH_LIMIT) { - meow_u128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; - meow_u64 TotalLengthInBytes; + while(BlockCount--) + { + prefetcht0(rax + MEOW_PREFETCH + 0x00); + prefetcht0(rax + MEOW_PREFETCH + 0x40); + prefetcht0(rax + MEOW_PREFETCH + 0x80); + prefetcht0(rax + MEOW_PREFETCH + 0xc0); - int unsigned BufferLen; + MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); + MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); + MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); + MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); + MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); + MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); + MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); + MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); - meow_u8 Buffer[256]; - meow_u128 Pad[2]; // NOTE(casey): So we know we can over-read Buffer as necessary - } meow_state; - - static void - MeowBegin(meow_state *State, void *Seed128) + rax += 0x100; + } + } + else { - meow_u8 *rcx = (meow_u8 *)Seed128; + while(BlockCount--) + { + MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); + MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); + MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); + MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); + MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); + MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); + MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); + MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); - movdqu(State->xmm0, rcx + 0x00); - movdqu(State->xmm1, rcx + 0x10); - movdqu(State->xmm2, rcx + 0x20); - movdqu(State->xmm3, rcx + 0x30); - movdqu(State->xmm4, rcx + 0x40); - movdqu(State->xmm5, rcx + 0x50); - movdqu(State->xmm6, rcx + 0x60); - movdqu(State->xmm7, rcx + 0x70); - - MEOW_DUMP_STATE("Seed", State->xmm0, State->xmm1, State->xmm2, State->xmm3, State->xmm4, State->xmm5, State->xmm6, State->xmm7, 0); - - State->BufferLen = 0; - State->TotalLengthInBytes = 0; + rax += 0x100; + } } - static void - MeowAbsorbBlocks(meow_state *State, meow_umm BlockCount, meow_u8 *rax) + State->xmm0 = xmm0; + State->xmm1 = xmm1; + State->xmm2 = xmm2; + State->xmm3 = xmm3; + State->xmm4 = xmm4; + State->xmm5 = xmm5; + State->xmm6 = xmm6; + State->xmm7 = xmm7; + } + + static void + MeowAbsorb(meow_state *State, meow_umm Len, void *SourceInit) + { + State->TotalLengthInBytes += Len; + meow_u8 *Source = (meow_u8 *)SourceInit; + + // NOTE(casey): Handle any buffered residual + if(State->BufferLen) { - meow_u128 xmm0 = State->xmm0; - meow_u128 xmm1 = State->xmm1; - meow_u128 xmm2 = State->xmm2; - meow_u128 xmm3 = State->xmm3; - meow_u128 xmm4 = State->xmm4; - meow_u128 xmm5 = State->xmm5; - meow_u128 xmm6 = State->xmm6; - meow_u128 xmm7 = State->xmm7; - - if(BlockCount > MEOW_PREFETCH_LIMIT) + int unsigned Fill = (sizeof(State->Buffer) - State->BufferLen); + if(Fill > Len) { - while(BlockCount--) - { - prefetcht0(rax + MEOW_PREFETCH + 0x00); - prefetcht0(rax + MEOW_PREFETCH + 0x40); - prefetcht0(rax + MEOW_PREFETCH + 0x80); - prefetcht0(rax + MEOW_PREFETCH + 0xc0); - - MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); - MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); - MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); - MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); - MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); - MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); - MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); - MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); - - rax += 0x100; - } - } - else - { - while(BlockCount--) - { - MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00); - MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20); - MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40); - MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60); - MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80); - MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0); - MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0); - MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0); - - rax += 0x100; - } + Fill = (int unsigned)Len; } - State->xmm0 = xmm0; - State->xmm1 = xmm1; - State->xmm2 = xmm2; - State->xmm3 = xmm3; - State->xmm4 = xmm4; - State->xmm5 = xmm5; - State->xmm6 = xmm6; - State->xmm7 = xmm7; - } - - static void - MeowAbsorb(meow_state *State, meow_umm Len, void *SourceInit) - { - State->TotalLengthInBytes += Len; - meow_u8 *Source = (meow_u8 *)SourceInit; - - // NOTE(casey): Handle any buffered residual - if(State->BufferLen) - { - int unsigned Fill = (sizeof(State->Buffer) - State->BufferLen); - if(Fill > Len) - { - Fill = (int unsigned)Len; - } - - Len -= Fill; - while(Fill--) - { - State->Buffer[State->BufferLen++] = *Source++; - } - - if(State->BufferLen == sizeof(State->Buffer)) - { - MeowAbsorbBlocks(State, 1, State->Buffer); - State->BufferLen = 0; - } - } - - // NOTE(casey): Handle any full blocks - meow_u64 BlockCount = (Len >> 8); - meow_u64 Advance = (BlockCount << 8); - MeowAbsorbBlocks(State, BlockCount, Source); - - Len -= Advance; - Source += Advance; - - // NOTE(casey): Store residual - while(Len--) + Len -= Fill; + while(Fill--) { State->Buffer[State->BufferLen++] = *Source++; } + + if(State->BufferLen == sizeof(State->Buffer)) + { + MeowAbsorbBlocks(State, 1, State->Buffer); + State->BufferLen = 0; + } } - static meow_u128 - MeowEnd(meow_state *State, meow_u8 *Store128) + // NOTE(casey): Handle any full blocks + meow_u64 BlockCount = (Len >> 8); + meow_u64 Advance = (BlockCount << 8); + MeowAbsorbBlocks(State, BlockCount, Source); + + Len -= Advance; + Source += Advance; + + // NOTE(casey): Store residual + while(Len--) { - meow_umm Len = State->TotalLengthInBytes; - - meow_u128 xmm0 = State->xmm0; - meow_u128 xmm1 = State->xmm1; - meow_u128 xmm2 = State->xmm2; - meow_u128 xmm3 = State->xmm3; - meow_u128 xmm4 = State->xmm4; - meow_u128 xmm5 = State->xmm5; - meow_u128 xmm6 = State->xmm6; - meow_u128 xmm7 = State->xmm7; - - meow_u128 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; - - meow_u8 *rax = State->Buffer; - - pxor_clear(xmm9, xmm9); - pxor_clear(xmm11, xmm11); - - meow_u8 *Last = (meow_u8 *)rax + (Len & 0xf0); - int unsigned Len8 = (Len & 0xf); - if(Len8) - { - movdqu(xmm8, &MeowMaskLen[0x10 - Len8]); - movdqu(xmm9, Last); - pand(xmm9, xmm8); - } - - if(Len & 0x10) - { - xmm11 = xmm9; - movdqu(xmm9, Last - 0x10); - } - - xmm8 = xmm9; - xmm10 = xmm9; - palignr(xmm8, xmm11, 15); - palignr(xmm10, xmm11, 1); - - pxor_clear(xmm12, xmm12); - pxor_clear(xmm13, xmm13); - pxor_clear(xmm14, xmm14); - movq(xmm15, Len); - palignr(xmm12, xmm15, 15); - palignr(xmm14, xmm15, 1); - - MEOW_DUMP_STATE("PostBlocks", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - MEOW_DUMP_STATE("Residuals", xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 0); - - // NOTE(casey): To maintain the mix-down pattern, we always Meow Mix the less-than-32-byte residual, even if it was empty - MEOW_MIX_REG(xmm0, xmm4, xmm6, xmm1, xmm2, xmm8, xmm9, xmm10, xmm11); - - // NOTE(casey): Append the length, to avoid problems with our 32-byte padding - MEOW_MIX_REG(xmm1, xmm5, xmm7, xmm2, xmm3, xmm12, xmm13, xmm14, xmm15); - - MEOW_DUMP_STATE("PostAppend", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - // - // NOTE(casey): Hash all full 32-byte blocks - // - int unsigned LaneCount = (Len >> 5) & 0x7; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x00); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x20); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x40); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0x60); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0x80); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xa0); --LaneCount; - if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0xc0); --LaneCount; - - // - // NOTE(casey): Mix the eight lanes down to one 128-bit hash - // - - MixDown: - - MEOW_DUMP_STATE("PostLanes", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); - MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); - MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); - MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); - MEOW_SHUFFLE(xmm4, xmm5, xmm6, xmm0, xmm1, xmm2); - MEOW_SHUFFLE(xmm5, xmm6, xmm7, xmm1, xmm2, xmm3); - MEOW_SHUFFLE(xmm6, xmm7, xmm0, xmm2, xmm3, xmm4); - MEOW_SHUFFLE(xmm7, xmm0, xmm1, xmm3, xmm4, xmm5); - MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); - MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); - MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); - MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); - - MEOW_DUMP_STATE("PostMix", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - if(Store128) - { - movdqu_mem(Store128 + 0x00, xmm0); - movdqu_mem(Store128 + 0x10, xmm1); - movdqu_mem(Store128 + 0x20, xmm2); - movdqu_mem(Store128 + 0x30, xmm3); - movdqu_mem(Store128 + 0x40, xmm4); - movdqu_mem(Store128 + 0x50, xmm5); - movdqu_mem(Store128 + 0x60, xmm6); - movdqu_mem(Store128 + 0x70, xmm7); - } - - paddq(xmm0, xmm2); - paddq(xmm1, xmm3); - paddq(xmm4, xmm6); - paddq(xmm5, xmm7); - pxor(xmm0, xmm1); - pxor(xmm4, xmm5); - paddq(xmm0, xmm4); - - MEOW_DUMP_STATE("PostFold", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); - - return(xmm0); + State->Buffer[State->BufferLen++] = *Source++; } + } + + static meow_u128 + MeowEnd(meow_state *State, meow_u8 *Store128) + { + meow_umm Len = State->TotalLengthInBytes; + + meow_u128 xmm0 = State->xmm0; + meow_u128 xmm1 = State->xmm1; + meow_u128 xmm2 = State->xmm2; + meow_u128 xmm3 = State->xmm3; + meow_u128 xmm4 = State->xmm4; + meow_u128 xmm5 = State->xmm5; + meow_u128 xmm6 = State->xmm6; + meow_u128 xmm7 = State->xmm7; + + meow_u128 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; + + meow_u8 *rax = State->Buffer; + + pxor_clear(xmm9, xmm9); + pxor_clear(xmm11, xmm11); + + meow_u8 *Last = (meow_u8 *)rax + (Len & 0xf0); + int unsigned Len8 = (Len & 0xf); + if(Len8) + { + movdqu(xmm8, &MeowMaskLen[0x10 - Len8]); + movdqu(xmm9, Last); + pand(xmm9, xmm8); + } + + if(Len & 0x10) + { + xmm11 = xmm9; + movdqu(xmm9, Last - 0x10); + } + + xmm8 = xmm9; + xmm10 = xmm9; + palignr(xmm8, xmm11, 15); + palignr(xmm10, xmm11, 1); + + pxor_clear(xmm12, xmm12); + pxor_clear(xmm13, xmm13); + pxor_clear(xmm14, xmm14); + movq(xmm15, Len); + palignr(xmm12, xmm15, 15); + palignr(xmm14, xmm15, 1); + + MEOW_DUMP_STATE("PostBlocks", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + MEOW_DUMP_STATE("Residuals", xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 0); + + // NOTE(casey): To maintain the mix-down pattern, we always Meow Mix the less-than-32-byte residual, even if it was empty + MEOW_MIX_REG(xmm0, xmm4, xmm6, xmm1, xmm2, xmm8, xmm9, xmm10, xmm11); + + // NOTE(casey): Append the length, to avoid problems with our 32-byte padding + MEOW_MIX_REG(xmm1, xmm5, xmm7, xmm2, xmm3, xmm12, xmm13, xmm14, xmm15); + + MEOW_DUMP_STATE("PostAppend", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); // - // NOTE(casey): If you need to create your own seed from non-random data, you can use MeowExpandSeed - // to create a seed which you then store for repeated use. It is _expensive_ to generate the seed, - // so you do not want to do this every time you hash. You _only_ want to do it when you actually - // need to create a new seed. + // NOTE(casey): Hash all full 32-byte blocks + // + int unsigned LaneCount = (Len >> 5) & 0x7; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x00); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x20); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x40); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0x60); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0x80); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xa0); --LaneCount; + if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0xc0); --LaneCount; + + // + // NOTE(casey): Mix the eight lanes down to one 128-bit hash // - static void - MeowExpandSeed(meow_umm InputLen, void *Input, meow_u8 *SeedResult) - { - meow_state State; - meow_u64 LengthTab = (meow_u64)InputLen; // NOTE(casey): We need to always injest 8-byte lengths exactly, even on 32-bit builds, to ensure identical results - meow_umm InjestCount = (256 / InputLen) + 2; + MixDown: - MeowBegin(&State, MeowDefaultSeed); - MeowAbsorb(&State, sizeof(LengthTab), &LengthTab); - while(InjestCount--) - { - MeowAbsorb(&State, InputLen, Input); - } - MeowEnd(&State, SeedResult); + MEOW_DUMP_STATE("PostLanes", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); + MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); + MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); + MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); + MEOW_SHUFFLE(xmm4, xmm5, xmm6, xmm0, xmm1, xmm2); + MEOW_SHUFFLE(xmm5, xmm6, xmm7, xmm1, xmm2, xmm3); + MEOW_SHUFFLE(xmm6, xmm7, xmm0, xmm2, xmm3, xmm4); + MEOW_SHUFFLE(xmm7, xmm0, xmm1, xmm3, xmm4, xmm5); + MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6); + MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7); + MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0); + MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1); + + MEOW_DUMP_STATE("PostMix", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + if(Store128) + { + movdqu_mem(Store128 + 0x00, xmm0); + movdqu_mem(Store128 + 0x10, xmm1); + movdqu_mem(Store128 + 0x20, xmm2); + movdqu_mem(Store128 + 0x30, xmm3); + movdqu_mem(Store128 + 0x40, xmm4); + movdqu_mem(Store128 + 0x50, xmm5); + movdqu_mem(Store128 + 0x60, xmm6); + movdqu_mem(Store128 + 0x70, xmm7); } - const char *MeowStringify(meow_u128 Hash) + paddq(xmm0, xmm2); + paddq(xmm1, xmm3); + paddq(xmm4, xmm6); + paddq(xmm5, xmm7); + pxor(xmm0, xmm1); + pxor(xmm4, xmm5); + paddq(xmm0, xmm4); + + MEOW_DUMP_STATE("PostFold", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0); + + return(xmm0); + } + + // + // NOTE(casey): If you need to create your own seed from non-random data, you can use MeowExpandSeed + // to create a seed which you then store for repeated use. It is _expensive_ to generate the seed, + // so you do not want to do this every time you hash. You _only_ want to do it when you actually + // need to create a new seed. + // + + static void + MeowExpandSeed(meow_umm InputLen, void *Input, meow_u8 *SeedResult) + { + meow_state State; + meow_u64 LengthTab = (meow_u64)InputLen; // NOTE(casey): We need to always injest 8-byte lengths exactly, even on 32-bit builds, to ensure identical results + meow_umm InjestCount = (256 / InputLen) + 2; + + MeowBegin(&State, MeowDefaultSeed); + MeowAbsorb(&State, sizeof(LengthTab), &LengthTab); + while(InjestCount--) { - char *str = (char *) malloc((4 * 8 + 4 + 1) * sizeof(char)); - - sprintf(str, "%08X-%08X-%08X-%08X", - MeowU32From(Hash, 3), - MeowU32From(Hash, 2), - MeowU32From(Hash, 1), - MeowU32From(Hash, 0)); - - return (const char *) str; + MeowAbsorb(&State, InputLen, Input); } + MeowEnd(&State, SeedResult); + } + + const char *MeowStringify(meow_u128 Hash) + { + char *str = (char *) malloc((4 * 8 + 4 + 1) * sizeof(char)); + + sprintf(str, "%08X-%08X-%08X-%08X", + MeowU32From(Hash, 3), + MeowU32From(Hash, 2), + MeowU32From(Hash, 1), + MeowU32From(Hash, 0)); + + return (const char *) str; } } diff --git a/Hash/SHA256.h b/Hash/SHA256.h index e9356c8..4aec83f 100755 --- a/Hash/SHA256.h +++ b/Hash/SHA256.h @@ -200,7 +200,7 @@ void sha_256_write(struct Sha_256 *sha_256, const void *data, size_t len) { sha_256->total_len += len; - const uint8_t *p = data; + const uint8_t *p = (uint8_t *) data; while (len > 0) { /* diff --git a/Image/BillDetection.h b/Image/BillDetection.h index df7ea8a..ae97ab1 100755 --- a/Image/BillDetection.h +++ b/Image/BillDetection.h @@ -14,67 +14,64 @@ #include #include -namespace Image +namespace Image::BillDetection { - namespace BillDetection + cv::Mat highlightBill(cv::Mat in) { - cv::Mat highlightBill(cv::Mat in) - { - cv::Mat gray; - cv::cvtColor(in, gray, cv::COLOR_BGR2GRAY); - cv::GaussianBlur(gray, gray, cv::Size(3, 3), 0); + cv::Mat gray; + cv::cvtColor(in, gray, cv::COLOR_BGR2GRAY); + cv::GaussianBlur(gray, gray, cv::Size(3, 3), 0); - cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Point(9, 9)); + cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Point(9, 9)); - cv::Mat dilated; - cv::dilate(gray, dilated, kernel); + cv::Mat dilated; + cv::dilate(gray, dilated, kernel); - cv::Mat edges; - cv::Canny(dilated, edges, 84, 3); + cv::Mat edges; + cv::Canny(dilated, edges, 84, 3); - std::vector lines; - lines.clear(); + std::vector lines; + lines.clear(); - cv::HoughLinesP(edges, lines, 1, CV_PI/180, 25); + cv::HoughLinesP(edges, lines, 1, CV_PI/180, 25); - std::vector::iterator it = lines.begin(); - for(; it != lines.end(); ++it) { - cv::Vec4i l = *it; - cv::line(edges, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(255,0,0), 2, 8); - } - - std::vector> contours; - cv::findContours(edges, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_TC89_KCOS); - - std::vector> contoursCleaned; - for (int i = 0; i < contours.size(); ++i) { - if (cv::arcLength(contours[i], false) > 100) { - contoursCleaned.push_back(contours[i]); - } - } - std::vector> contoursArea; - for (int i = 0; i < contoursCleaned.size(); ++i) { - if (cv::contourArea(contoursCleaned[i]) > 10000) { - contoursArea.push_back(contoursCleaned[i]); - } - } - - // Approximate polygon - /* Question: we probably don't want a polygon all the time?! */ - // @todo bad implementation, focus on single square - std::vector > contoursDraw (contoursArea.size()); - for (int i = 0; i < contoursArea.size(); ++i){ - cv::approxPolyDP(cv::Mat(contoursArea[i]), contoursDraw[i], 40, true); - } - - cv::Mat mask = cv::Mat(in.size(), CV_8UC3, cv::Scalar(255, 255, 255)); - cv::drawContours(mask, contoursDraw, -1, cv::Scalar(0, 0, 0), cv::FILLED, 1); - - cv::Mat out = cv::Mat::zeros(in.size(), CV_8UC3); - cv::bitwise_or(in, mask, out); - - return out; + std::vector::iterator it = lines.begin(); + for(; it != lines.end(); ++it) { + cv::Vec4i l = *it; + cv::line(edges, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(255,0,0), 2, 8); } + + std::vector> contours; + cv::findContours(edges, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_TC89_KCOS); + + std::vector> contoursCleaned; + for (int i = 0; i < contours.size(); ++i) { + if (cv::arcLength(contours[i], false) > 100) { + contoursCleaned.push_back(contours[i]); + } + } + std::vector> contoursArea; + for (int i = 0; i < contoursCleaned.size(); ++i) { + if (cv::contourArea(contoursCleaned[i]) > 10000) { + contoursArea.push_back(contoursCleaned[i]); + } + } + + // Approximate polygon + /* Question: we probably don't want a polygon all the time?! */ + // @todo bad implementation, focus on single square + std::vector > contoursDraw (contoursArea.size()); + for (int i = 0; i < contoursArea.size(); ++i){ + cv::approxPolyDP(cv::Mat(contoursArea[i]), contoursDraw[i], 40, true); + } + + cv::Mat mask = cv::Mat(in.size(), CV_8UC3, cv::Scalar(255, 255, 255)); + cv::drawContours(mask, contoursDraw, -1, cv::Scalar(0, 0, 0), cv::FILLED, 1); + + cv::Mat out = cv::Mat::zeros(in.size(), CV_8UC3); + cv::bitwise_or(in, mask, out); + + return out; } } diff --git a/Image/ImageUtils.h b/Image/ImageUtils.h index 003ce6d..0200f1b 100755 --- a/Image/ImageUtils.h +++ b/Image/ImageUtils.h @@ -13,36 +13,23 @@ #include #include -namespace Image +namespace Image::ImageUtils { - namespace ImageUtils + inline + float lightnessFromRgb(int r, int g, int b) { - inline - float lightnessFromRgb(int r, int g, int b) - { - float vR = r / 255.0; - float vG = g / 255.0; - float vB = b / 255.0; + float vR = r / 255.0; + float vG = g / 255.0; + float vB = b / 255.0; - float lR = vR <= 0.04045 ? vR / 12.92 : pow(((vR + 0.055) / 1.055), 2.4); - float lG = vG <= 0.04045 ? vG / 12.92 : pow(((vG + 0.055) / 1.055), 2.4); - float lB = vB <= 0.04045 ? vB / 12.92 : pow(((vB + 0.055) / 1.055), 2.4); + float lR = vR <= 0.04045 ? vR / 12.92 : pow(((vR + 0.055) / 1.055), 2.4); + float lG = vG <= 0.04045 ? vG / 12.92 : pow(((vG + 0.055) / 1.055), 2.4); + float lB = vB <= 0.04045 ? vB / 12.92 : pow(((vB + 0.055) / 1.055), 2.4); - float y = 0.2126 * lR + 0.7152 * lG + 0.0722 * lB; - float lStar = y <= 216.0 / 24389.0 ? y * 24389.0 / 27.0 : pow(y, (1.0 / 3.0)) * 116.0 - 16.0; + float y = 0.2126 * lR + 0.7152 * lG + 0.0722 * lB; + float lStar = y <= 216.0 / 24389.0 ? y * 24389.0 / 27.0 : pow(y, (1.0 / 3.0)) * 116.0 - 16.0; - return lStar / 100.0; - } - - inline - int rgbToInt(int r, int g, int b) - { - int rgb = r; - rgb = (rgb << 8) + g; - rgb = (rgb << 8) + b; - - return rgb; - } + return lStar / 100.0; } } diff --git a/Image/Kernel.h b/Image/Kernel.h index a8b088d..ee656bd 100755 --- a/Image/Kernel.h +++ b/Image/Kernel.h @@ -16,7 +16,7 @@ #include "ImageUtils.h" #include "../Utils/MathUtils.h" -namespace Image +namespace Image::Kernel { const float KERNEL_RIDGE_1[3][3] = { {0.0, -1.0, 0.0}, @@ -62,19 +62,16 @@ namespace Image {-1.0 / 256.0, -4.0 / 256.0, -6.0 / 256.0, -4.0 / 256.0, -1.0 / 256.0}, }; - namespace Kernel + inline + cv::Mat convolve(cv::Mat in, const float kernel[][3]) { - inline - cv::Mat convolve(cv::Mat in, const float kernel[][3]) - { - cv::Size dim = in.size(); - cv::Mat out(in.size(), in.type()); + cv::Size dim = in.size(); + cv::Mat out(in.size(), in.type()); - cv::Mat mKernel(3, 3, CV_32F, (float *) kernel); - cv::filter2D(in, out, -1, mKernel); + cv::Mat mKernel(3, 3, CV_32F, (float *) kernel); + cv::filter2D(in, out, -1, mKernel); - return out; - } + return out; } } diff --git a/Image/Skew.h b/Image/Skew.h index 467a488..f7442f9 100755 --- a/Image/Skew.h +++ b/Image/Skew.h @@ -16,77 +16,74 @@ #include "../Utils/MathUtils.h" -namespace Image +namespace Image::Skew { - namespace Skew + cv::Mat deskewHoughLines(cv::Mat in, int maxDegree = 45) { - cv::Mat deskewHoughLines(cv::Mat in, int maxDegree = 45) - { - cv::Size dim = in.size(); + cv::Size dim = in.size(); - cv::Mat inv; - cv::cvtColor(in, inv, cv::COLOR_BGR2GRAY); - cv::threshold(inv, inv, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU); + cv::Mat inv; + cv::cvtColor(in, inv, cv::COLOR_BGR2GRAY); + cv::threshold(inv, inv, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU); - std::vector lines; - cv::HoughLinesP(inv, lines, 1.0, OMS_PI / 180, 200, dim.width / 12, dim.width / 150); + std::vector lines; + cv::HoughLinesP(inv, lines, 1.0, OMS_PI / 180, 200, dim.width / 12, dim.width / 150); - int imageOrientation = 0; // > 0 -> image is horizontal + int imageOrientation = 0; // > 0 -> image is horizontal - std::vector tmpAngles; - for (int i = 0; i < lines.size(); ++i) { - float angle = atan2(lines[i][3] - lines[i][1], lines[i][2] - lines[i][0]); - tmpAngles.push_back(angle); + std::vector tmpAngles; + for (int i = 0; i < lines.size(); ++i) { + float angle = atan2(lines[i][3] - lines[i][1], lines[i][2] - lines[i][0]); + tmpAngles.push_back(angle); - imageOrientation += oms_abs(angle) > OMS_PI / 4 ? 1 : -1; - } + imageOrientation += oms_abs(angle) > OMS_PI / 4 ? 1 : -1; + } - std::vector angles; - for (int i = 0; i < tmpAngles.size(); ++i) { - if (imageOrientation > 0) { - if (oms_deg2rad(90 - maxDegree) < oms_abs(tmpAngles[i]) && oms_abs(tmpAngles[i]) < oms_deg2rad(90 + maxDegree)) { - angles.push_back(tmpAngles[i]); - } - } else { - if (oms_abs(tmpAngles[i]) < oms_deg2rad(maxDegree)) { - angles.push_back(tmpAngles[i]); - } - } - } - - if (angles.size() < 5) { - return in; - } - - float median = 0.0; - for (int i = 0; i < angles.size(); ++i) { - median += angles[i]; - } - - float angleDeg = oms_rad2deg(median / angles.size()); - - cv::Mat orientFix; + std::vector angles; + for (int i = 0; i < tmpAngles.size(); ++i) { if (imageOrientation > 0) { - if (angleDeg < 0) { - cv::rotate(in, orientFix, cv::ROTATE_90_CLOCKWISE); - angleDeg += 90.0; - } else if (angleDeg > 0) { - cv::rotate(in, orientFix, cv::ROTATE_90_COUNTERCLOCKWISE); - angleDeg -= 90.0; - } else { - orientFix = in; + if (oms_deg2rad(90 - maxDegree) < oms_abs(tmpAngles[i]) && oms_abs(tmpAngles[i]) < oms_deg2rad(90 + maxDegree)) { + angles.push_back(tmpAngles[i]); } + } else { + if (oms_abs(tmpAngles[i]) < oms_deg2rad(maxDegree)) { + angles.push_back(tmpAngles[i]); + } + } + } + + if (angles.size() < 5) { + return in; + } + + float median = 0.0; + for (int i = 0; i < angles.size(); ++i) { + median += angles[i]; + } + + float angleDeg = oms_rad2deg(median / angles.size()); + + cv::Mat orientFix; + if (imageOrientation > 0) { + if (angleDeg < 0) { + cv::rotate(in, orientFix, cv::ROTATE_90_CLOCKWISE); + angleDeg += 90.0; + } else if (angleDeg > 0) { + cv::rotate(in, orientFix, cv::ROTATE_90_COUNTERCLOCKWISE); + angleDeg -= 90.0; } else { orientFix = in; } - - cv::Mat rot = cv::getRotationMatrix2D(cv::Point2f(dim.width / 2, dim.height / 2), angleDeg, 1.0); - - cv::Mat out; - cv::warpAffine(orientFix, out, rot, dim, cv::INTER_LINEAR, cv::BORDER_REPLICATE); - - return out; + } else { + orientFix = in; } + + cv::Mat rot = cv::getRotationMatrix2D(cv::Point2f(dim.width / 2, dim.height / 2), angleDeg, 1.0); + + cv::Mat out; + cv::warpAffine(orientFix, out, rot, dim, cv::INTER_LINEAR, cv::BORDER_REPLICATE); + + return out; } } diff --git a/Image/Thresholding.h b/Image/Thresholding.h index e164dad..dad81e6 100755 --- a/Image/Thresholding.h +++ b/Image/Thresholding.h @@ -16,65 +16,62 @@ #include "ImageUtils.h" #include "../Utils/MathUtils.h" -namespace Image +namespace Image::Thresholding { - namespace Thresholding + cv::Mat integralThresholding(cv::Mat in) { - cv::Mat integralThresholding(cv::Mat in) - { - cv::Size dim = in.size(); - cv::Mat out(dim, in.type()); + cv::Size dim = in.size(); + cv::Mat out(dim, in.type()); - float *intImg = (float *) malloc(dim.width * dim.height * sizeof(float)); - float sum; + float *intImg = (float *) malloc(dim.width * dim.height * sizeof(float)); + float sum; - cv::Vec3b bgr; - for (int i = 0; i < dim.width; ++i) { - sum = 0.0; + cv::Vec3b bgr; + for (int i = 0; i < dim.width; ++i) { + sum = 0.0; - for (int j = 0; j < dim.height; ++j) { - bgr = in.at(j, i); - sum += Image::ImageUtils::lightnessFromRgb(bgr[2], bgr[1], bgr[0]); + for (int j = 0; j < dim.height; ++j) { + bgr = in.at(j, i); + sum += Image::ImageUtils::lightnessFromRgb(bgr[2], bgr[1], bgr[0]); - intImg[i * j] = i == 0 ? sum : intImg[(i - 1) * j] + sum; - } + intImg[i * j] = i == 0 ? sum : intImg[(i - 1) * j] + sum; } - - int s = dim.width / 96.0; - int t = 30; - - int x1, x2; - int y1, y2; - int count; - float brightness; - int color; - - for (int i = 0; i < dim.width; ++i) { - for (int j = 0; j < dim.height; ++j) { - x1 = oms_max(1, i - s / 2.0); - x2 = oms_min(i + s / 2.0, dim.width - 1); - - y1 = oms_max(1, j - s / 2.0); - y2 = oms_min(j + s / 2.0, dim.height - 1); - - count = (x2 - x1) * (y2 - y1); - sum = intImg[x2 * y2] - intImg[x2 * (y1 - 1)] - intImg[(x1 - 1) * y2] + intImg[(x1 - 1) * (y1 - 1)]; - - bgr = in.at(j, i); - brightness = Image::ImageUtils::lightnessFromRgb(bgr[2], bgr[1], bgr[0]); - - color = brightness * count <= (sum * (100.0 - t) / 100.0) && brightness < 0.95 ? 0 : 255; - - out.at(j, i)[0] = color; - out.at(j, i)[1] = color; - out.at(j, i)[2] = color; - } - } - - free(intImg); - - return out; } + + int s = dim.width / 96.0; + int t = 30; + + int x1, x2; + int y1, y2; + int count; + float brightness; + int color; + + for (int i = 0; i < dim.width; ++i) { + for (int j = 0; j < dim.height; ++j) { + x1 = oms_max(1, i - s / 2.0); + x2 = oms_min(i + s / 2.0, dim.width - 1); + + y1 = oms_max(1, j - s / 2.0); + y2 = oms_min(j + s / 2.0, dim.height - 1); + + count = (x2 - x1) * (y2 - y1); + sum = intImg[x2 * y2] - intImg[x2 * (y1 - 1)] - intImg[(x1 - 1) * y2] + intImg[(x1 - 1) * (y1 - 1)]; + + bgr = in.at(j, i); + brightness = Image::ImageUtils::lightnessFromRgb(bgr[2], bgr[1], bgr[0]); + + color = brightness * count <= (sum * (100.0 - t) / 100.0) && brightness < 0.95 ? 0 : 255; + + out.at(j, i)[0] = color; + out.at(j, i)[1] = color; + out.at(j, i)[2] = color; + } + } + + free(intImg); + + return out; } } diff --git a/Stdlib/HashTable.h b/Stdlib/HashTable.h index 277c5a8..bcaff42 100755 --- a/Stdlib/HashTable.h +++ b/Stdlib/HashTable.h @@ -16,205 +16,202 @@ #include "../Hash/MeowHash.h" -namespace Stdlib +namespace Stdlib::HashTable { - namespace HashTable + typedef struct { + const char *key; + void *value; + } entry; + + struct ht { + bool is_fixed = false; + entry *entries; + size_t max; + size_t size; + }; + + typedef struct { + const char *key; + void *value; + + ht *table; + size_t index; + } it; + + inline + unsigned long long hash_key(const char *key) { - typedef struct { - const char *key; - void *value; - } entry; - - struct ht { - bool is_fixed = false; - entry *entries; - size_t max; - size_t size; - }; - - typedef struct { - const char *key; - void *value; - - ht *table; - size_t index; - } it; - - inline - unsigned long long hash_key(const char *key) - { - return (unsigned long long) MeowU64From( - Hash::Meow::MeowHash(Hash::Meow::MeowDefaultSeed, - strlen(key), - (void *) key), - 0 - ); - } - - ht *create_table(int max = 0, bool is_fixed = false) - { - ht *table = (ht *) malloc(sizeof(ht)); - if (table == NULL) { - return NULL; - } - - table->size = 0; - table->max = max == 0 ? 16 : max; - table->is_fixed = is_fixed; - - table->entries = (entry *) calloc(table->max, sizeof(entry)); - if (table->entries == NULL) { - free(table); - return NULL; - } - - return table; - } - - void *get_entry(ht *table, const char *key) - { - unsigned long long hash = hash_key(key); - size_t index = (size_t) (hash & (unsigned long long)(table->max - 1)); - - while (table->entries[index].key != NULL) { - if (strcmp(key, table->entries[index].key) == 0) { - return table->entries[index].value; - } - - ++index; - if (index >= table->max) { - index = 0; - } - } + return (unsigned long long) MeowU64From( + Hash::Meow::MeowHash(Hash::Meow::MeowDefaultSeed, + strlen(key), + (void *) key), + 0 + ); + } + ht *create_table(int max = 0, bool is_fixed = false) + { + ht *table = (ht *) malloc(sizeof(ht)); + if (table == NULL) { return NULL; } - const char *_set_entry(entry *entries, size_t max, const char *key, void *value, size_t *size) - { - unsigned long long hash = hash_key(key); - size_t index = (size_t) (hash & (unsigned long long)(max - 1)); + table->size = 0; + table->max = max == 0 ? 16 : max; + table->is_fixed = is_fixed; - while (entries[index].key != NULL) { - if (strcmp(key, entries[index].key) == 0) { - entries[index].value = value; - - return entries[index].key; - } - - ++index; - if (index >= max) { - index = 0; - } - } - - if (size != NULL) { - #ifdef _WIN32 - key = _strdup(key); - #else - key = strdup(key); - #endif - - if (key == NULL) { - return NULL; - } - - ++(*size); - } - - entries[index].key = (char *) key; - entries[index].value = value; - - return key; + table->entries = (entry *) calloc(table->max, sizeof(entry)); + if (table->entries == NULL) { + free(table); + return NULL; } - bool expand_table(ht *table) - { - size_t new_max = table->max * 2; - if (new_max < table->max) { - return false; + return table; + } + + void *get_entry(ht *table, const char *key) + { + unsigned long long hash = hash_key(key); + size_t index = (size_t) (hash & (unsigned long long)(table->max - 1)); + + while (table->entries[index].key != NULL) { + if (strcmp(key, table->entries[index].key) == 0) { + return table->entries[index].value; } - entry *new_entries = (entry *) calloc(new_max, sizeof(entry)); - if (new_entries == NULL) { - return false; + ++index; + if (index >= table->max) { + index = 0; } - - for (size_t i = 0; i < table->max; ++i) { - entry tmp = table->entries[i]; - if (tmp.key != NULL) { - _set_entry(new_entries, new_max, tmp.key, tmp.value, NULL); - } - } - - free(table->entries); - table->entries = new_entries; - table->max = new_max; - - return true; } - const char *set_entry(ht *table, const char *key, void *value) - { - if (value == NULL) { + return NULL; + } + + const char *_set_entry(entry *entries, size_t max, const char *key, void *value, size_t *size) + { + unsigned long long hash = hash_key(key); + size_t index = (size_t) (hash & (unsigned long long)(max - 1)); + + while (entries[index].key != NULL) { + if (strcmp(key, entries[index].key) == 0) { + entries[index].value = value; + + return entries[index].key; + } + + ++index; + if (index >= max) { + index = 0; + } + } + + if (size != NULL) { + #ifdef _WIN32 + key = _strdup(key); + #else + key = strdup(key); + #endif + + if (key == NULL) { return NULL; } - if (table->is_fixed && table->size == table->max) { - return NULL; - } - - if (!table->is_fixed && table->size >= table->max / 2) { - if (!expand_table(table)) { - return NULL; - } - } - - return _set_entry(table->entries, table->max, key, value, &table->size); + ++(*size); } - it table_iterator(ht *table) - { - it it; - it.table = table; - it.index = 0; + entries[index].key = (char *) key; + entries[index].value = value; - return it; - } - - bool next(it *it) - { - ht *table = it->table; - while (it->index < table->max) { - size_t i = it->index; - ++(it->index); - - if (table->entries[i].key != NULL) { - entry tmp = table->entries[i]; - it->key = tmp.key; - it->value = tmp.value; - - return true; - } - } + return key; + } + bool expand_table(ht *table) + { + size_t new_max = table->max * 2; + if (new_max < table->max) { return false; } - void free_table(ht *table) - { - if (!table || !table->entries) { - return; - } - - for (size_t i = 0; i < table->max; ++i) { - if (table->entries[i].key) { - free((void *) table->entries[i].key); - } - } - - free(table->entries); + entry *new_entries = (entry *) calloc(new_max, sizeof(entry)); + if (new_entries == NULL) { + return false; } + + for (size_t i = 0; i < table->max; ++i) { + entry tmp = table->entries[i]; + if (tmp.key != NULL) { + _set_entry(new_entries, new_max, tmp.key, tmp.value, NULL); + } + } + + free(table->entries); + table->entries = new_entries; + table->max = new_max; + + return true; + } + + const char *set_entry(ht *table, const char *key, void *value) + { + if (value == NULL) { + return NULL; + } + + if (table->is_fixed && table->size == table->max) { + return NULL; + } + + if (!table->is_fixed && table->size >= table->max / 2) { + if (!expand_table(table)) { + return NULL; + } + } + + return _set_entry(table->entries, table->max, key, value, &table->size); + } + + it table_iterator(ht *table) + { + it it; + it.table = table; + it.index = 0; + + return it; + } + + bool next(it *it) + { + ht *table = it->table; + while (it->index < table->max) { + size_t i = it->index; + ++(it->index); + + if (table->entries[i].key != NULL) { + entry tmp = table->entries[i]; + it->key = tmp.key; + it->value = tmp.value; + + return true; + } + } + + return false; + } + + void free_table(ht *table) + { + if (!table || !table->entries) { + return; + } + + for (size_t i = 0; i < table->max; ++i) { + if (table->entries[i].key) { + free((void *) table->entries[i].key); + } + } + + free(table->entries); } } diff --git a/Utils/ApplicationUtils.h b/Utils/ApplicationUtils.h index 26e8ee7..5e48ba9 100755 --- a/Utils/ApplicationUtils.h +++ b/Utils/ApplicationUtils.h @@ -48,9 +48,7 @@ namespace Utils if (pos != NULL) { memcpy(dir, arg, (pos - arg) * sizeof(char)); - chdir(dir); - free(dir); } } diff --git a/Utils/ArraySort.h b/Utils/ArraySort.h index 34d3c44..a6b7358 100755 --- a/Utils/ArraySort.h +++ b/Utils/ArraySort.h @@ -13,48 +13,45 @@ #include #include -namespace Utils +namespace Utils::ArraySort { - namespace ArraySort + inline + void reverse_int(int64_t *arr, size_t size) { - inline - void reverse_int(int64_t *arr, size_t size) - { - for (size_t low = 0, high = size - 1; low < high; ++low, --high) { - int64_t tmp = arr[low]; - arr[low] = arr[high]; - arr[high] = tmp; - } + for (size_t low = 0, high = size - 1; low < high; ++low, --high) { + int64_t tmp = arr[low]; + arr[low] = arr[high]; + arr[high] = tmp; } + } - inline - void reverse_float(float *arr, size_t size) - { - for (size_t low = 0, high = size - 1; low < high; ++low, --high) { - float tmp = arr[low]; - arr[low] = arr[high]; - arr[high] = tmp; - } + inline + void reverse_float(float *arr, size_t size) + { + for (size_t low = 0, high = size - 1; low < high; ++low, --high) { + float tmp = arr[low]; + arr[low] = arr[high]; + arr[high] = tmp; } + } - inline - void reverse_double(double *arr, size_t size) - { - for (size_t low = 0, high = size - 1; low < high; ++low, --high) { - double tmp = arr[low]; - arr[low] = arr[high]; - arr[high] = tmp; - } + inline + void reverse_double(double *arr, size_t size) + { + for (size_t low = 0, high = size - 1; low < high; ++low, --high) { + double tmp = arr[low]; + arr[low] = arr[high]; + arr[high] = tmp; } + } - inline - void reverse_char(char **arr, size_t size) - { - for (size_t low = 0, high = size - 1; low < high; ++low, --high) { - char* tmp = arr[low]; - arr[low] = arr[high]; - arr[high] = tmp; - } + inline + void reverse_char(char **arr, size_t size) + { + for (size_t low = 0, high = size - 1; low < high; ++low, --high) { + char* tmp = arr[low]; + arr[low] = arr[high]; + arr[high] = tmp; } } } diff --git a/Utils/ArrayUtils.h b/Utils/ArrayUtils.h index 2a93bcb..fe7c8f7 100755 --- a/Utils/ArrayUtils.h +++ b/Utils/ArrayUtils.h @@ -16,195 +16,192 @@ #include "StringUtils.h" -namespace Utils +namespace Utils::ArrayUtils { - namespace ArrayUtils + inline + char* get_arg(const char *id, char **argv, size_t size) { - inline - char* get_arg(const char *id, char **argv, size_t size) - { - if (Utils::StringUtils::is_number(id)) { - return argv[atoi(id)]; - } + if (Utils::StringUtils::is_number(id)) { + return argv[atoi(id)]; + } - for (size_t i = 0; i < size - 1; ++i) { - if (strcmp(id, argv[i]) == 0) { - return i + 1 >= size ? NULL : argv[i + 1]; - } + for (size_t i = 0; i < size - 1; ++i) { + if (strcmp(id, argv[i]) == 0) { + return i + 1 >= size ? NULL : argv[i + 1]; } + } + return NULL; + } + + inline + bool has_arg(const char *id, char **argv, size_t size) + { + for (size_t i = 0; i < size; ++i) { + if (strcmp(id, argv[i]) == 0) { + return true; + } + } + + return false; + } + + inline + double array_sum_double(double *array, size_t size) + { + double sum = 0.0; + for (size_t i = 0; i < size; ++i) { + sum += array[i]; + } + + return sum; + } + + inline + float array_sum_float(float *array, size_t size) + { + float sum = 0.0; + for (size_t i = 0; i < size; ++i) { + sum += array[i]; + } + + return sum; + } + + inline + int64_t array_sum_int(int64_t *array, size_t size) + { + int64_t sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += array[i]; + } + + return sum; + } + + inline + size_t find_in_array_string(const char *element, const char **array, size_t size) + { + for (size_t i = 0; i < size; ++i) { + if (strcmp(element, array[i]) == 0) { + return i; + } + } + + return -1; + } + + inline + size_t find_in_array_double(double element, double *array, size_t size) + { + for (size_t i = 0; i < size; ++i) { + if (array[i] == element) { + return i; + } + } + + return -1; + } + + inline + size_t find_in_array_float(float element, float *array, size_t size) + { + for (size_t i = 0; i < size; ++i) { + if (array[i] == element) { + return i; + } + } + + return -1; + } + + inline + size_t find_in_array_int(int64_t element, int64_t *array, size_t size) + { + for (size_t i = 0; i < size; ++i) { + if (array[i] == element) { + return i; + } + } + + return -1; + } + + inline + double* merge_arrays_double(double* array1, size_t size1, double* array2, size_t size2) + { + double* merged = (double*) malloc((size1 + size2) * sizeof(double)); + if (merged == NULL) { return NULL; } - inline - bool has_arg(const char *id, char **argv, size_t size) - { - for (size_t i = 0; i < size; ++i) { - if (strcmp(id, argv[i]) == 0) { - return true; - } - } - - return false; + for (size_t i = 0; i < size1; ++i) { + merged[i] = array1[i]; } - inline - double array_sum_double(double *array, size_t size) - { - double sum = 0.0; - for (size_t i = 0; i < size; ++i) { - sum += array[i]; - } - - return sum; + for (size_t i = 0; i < size2; ++i) { + merged[size1 + i] = array2[i]; } - inline - float array_sum_float(float *array, size_t size) - { - float sum = 0.0; - for (size_t i = 0; i < size; ++i) { - sum += array[i]; - } + return merged; + } - return sum; + inline + float* merge_arrays_float(float* array1, size_t size1, float* array2, size_t size2) + { + float* merged = (float*) malloc((size1 + size2) * sizeof(float)); + if (merged == NULL) { + return NULL; } - inline - int64_t array_sum_int(int64_t *array, size_t size) - { - int64_t sum = 0; - for (size_t i = 0; i < size; ++i) { - sum += array[i]; - } - - return sum; + for (size_t i = 0; i < size1; ++i) { + merged[i] = array1[i]; } - inline - size_t find_in_array_string(const char *element, const char **array, size_t size) - { - for (size_t i = 0; i < size; ++i) { - if (strcmp(element, array[i]) == 0) { - return i; - } - } - - return -1; + for (size_t i = 0; i < size2; ++i) { + merged[size1 + i] = array2[i]; } - inline - size_t find_in_array_double(double element, double *array, size_t size) - { - for (size_t i = 0; i < size; ++i) { - if (array[i] == element) { - return i; - } - } + return merged; + } - return -1; + inline + int64_t* merge_arrays_int(int64_t* array1, size_t size1, int64_t* array2, size_t size2) + { + int64_t* merged = (int64_t*) malloc((size1 + size2) * sizeof(int64_t)); + if (merged == NULL) { + return NULL; } - inline - size_t find_in_array_float(float element, float *array, size_t size) - { - for (size_t i = 0; i < size; ++i) { - if (array[i] == element) { - return i; - } - } - - return -1; + for (size_t i = 0; i < size1; ++i) { + merged[i] = array1[i]; } - inline - size_t find_in_array_int(int64_t element, int64_t *array, size_t size) - { - for (size_t i = 0; i < size; ++i) { - if (array[i] == element) { - return i; - } - } - - return -1; + for (size_t i = 0; i < size2; ++i) { + merged[size1 + i] = array2[i]; } - inline - double* merge_arrays_double(double* array1, size_t size1, double* array2, size_t size2) - { - double* merged = (double*) malloc((size1 + size2) * sizeof(double)); - if (merged == NULL) { - return NULL; - } + return merged; + } - for (size_t i = 0; i < size1; ++i) { - merged[i] = array1[i]; - } - - for (size_t i = 0; i < size2; ++i) { - merged[size1 + i] = array2[i]; - } - - return merged; + char** merge_arrays_char(const char** array1, size_t size1, const char** array2, size_t size2) + { + char** merged = (char**) malloc((size1 + size2) * sizeof(char*)); + if (merged == NULL) { + return NULL; } - inline - float* merge_arrays_float(float* array1, size_t size1, float* array2, size_t size2) - { - float* merged = (float*) malloc((size1 + size2) * sizeof(float)); - if (merged == NULL) { - return NULL; - } - - for (size_t i = 0; i < size1; ++i) { - merged[i] = array1[i]; - } - - for (size_t i = 0; i < size2; ++i) { - merged[size1 + i] = array2[i]; - } - - return merged; + for (size_t i = 0; i < size1; ++i) { + merged[i] = (char*) malloc((strlen(array1[i]) + 1) * sizeof(char)); + strcpy(merged[i], array1[i]); } - inline - int64_t* merge_arrays_int(int64_t* array1, size_t size1, int64_t* array2, size_t size2) - { - int64_t* merged = (int64_t*) malloc((size1 + size2) * sizeof(int64_t)); - if (merged == NULL) { - return NULL; - } - - for (size_t i = 0; i < size1; ++i) { - merged[i] = array1[i]; - } - - for (size_t i = 0; i < size2; ++i) { - merged[size1 + i] = array2[i]; - } - - return merged; + for (size_t i = 0; i < size2; ++i) { + merged[i] = (char*) malloc((strlen(array2[i]) + 1) * sizeof(char)); + strcpy(merged[i], array2[i]); } - char** merge_arrays_char(const char** array1, size_t size1, const char** array2, size_t size2) - { - char** merged = (char**) malloc((size1 + size2) * sizeof(char*)); - if (merged == NULL) { - return NULL; - } - - for (size_t i = 0; i < size1; ++i) { - merged[i] = (char*) malloc((strlen(arr1[i]) + 1) * sizeof(char)); - strcpy(merged[i], arr1[i]); - } - - for (size_t i = 0; i < size2; ++i) { - merged[i] = (char*) malloc((strlen(arr2[i]) + 1) * sizeof(char)); - strcpy(merged[i], arr2[i]); - } - - return merged; - } + return merged; } } diff --git a/Utils/ColorUtils.h b/Utils/ColorUtils.h new file mode 100644 index 0000000..8dbe74d --- /dev/null +++ b/Utils/ColorUtils.h @@ -0,0 +1,57 @@ +/** + * Karaka + * + * @package Utils + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef UTILS_STRING_UTILS_H +#define UTILS_STRING_UTILS_H + +#include +#include + +namespace Utils::ColorUtils +{ + typedef struct { + char r = 0; + char g = 0; + char b = 0; + } RGB; + + inline + RGB* int_to_rgb(int rgb) + { + RGB* result = (RGB*) malloc(1 * sizeof(RGB)); + + result->r = rgb & 255; + result->g = (rgb >> 8) & 255; + result->b = (rgb >> 16) & 255; + + return result; + } + + inline + int rgb_to_int(RGB* rgb) + { + int i = (255 & rgb->r) << 16; + i += (255 & rgb->g) << 8; + i += (255 & rgb->b); + + return i; + } + + inline + int rgb_to_int(char r, char g, char b) + { + int i = (255 & r) << 16; + i += (255 & g) << 8; + i += (255 & b); + + return i; + } +} + +#endif \ No newline at end of file diff --git a/Utils/FileUtils.h b/Utils/FileUtils.h index 3463876..f36de2d 100755 --- a/Utils/FileUtils.h +++ b/Utils/FileUtils.h @@ -23,111 +23,108 @@ #include "OSWrapper.h" -namespace Utils +namespace Utils::FileUtils { - namespace FileUtils + inline + bool file_exists (const char *filename) { - inline - bool file_exists (const char *filename) - { - #ifdef _WIN32 - return access(filename, 0) == 0; - #else - struct stat buffer; - return stat(filename, &buffer) == 0; - #endif - } + #ifdef _WIN32 + return access(filename, 0) == 0; + #else + struct stat buffer; + return stat(filename, &buffer) == 0; + #endif + } - inline - time_t last_modification (const char *filename) - { - #ifdef _WIN32 - FILETIME modtime; - HANDLE h; + inline + time_t last_modification (const char *filename) + { + #ifdef _WIN32 + FILETIME modtime; + HANDLE h; - size_t nameLength = strlen(filename); + size_t nameLength = strlen(filename); - wchar_t *wtext = (wchar_t *) calloc(nameLength, sizeof(char)); - mbstowcs_s(NULL, wtext, nameLength, filename, nameLength); - LPWSTR pFilename = wtext; - - if (!pFilename) { - free(wtext); - - return 0; - } - - h = CreateFileW(pFilename, GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, 0, NULL); + wchar_t *wtext = (wchar_t *) calloc(nameLength, sizeof(char)); + mbstowcs_s(NULL, wtext, nameLength, filename, nameLength); + LPWSTR pFilename = wtext; + if (!pFilename) { free(wtext); - free(pFilename); - if (h == INVALID_HANDLE_VALUE) { - return (time_t) 0; - } + return 0; + } - if (GetFileTime(h, NULL, NULL, &modtime) == 0) { - return (time_t) 0; - } + h = CreateFileW(pFilename, GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, 0, NULL); - unsigned long long seconds = ((unsigned long long) (modtime.dwHighDateTime)) << 32; - seconds |= modtime.dwLowDateTime; + free(wtext); + free(pFilename); - return (seconds - 116444736000000000) / 10000000; - #else - struct stat buffer; - stat(filename, &buffer); + if (h == INVALID_HANDLE_VALUE) { + return (time_t) 0; + } - return (time_t) buffer.st_mtim.tv_sec; - #endif + if (GetFileTime(h, NULL, NULL, &modtime) == 0) { + return (time_t) 0; + } - return (time_t) 0; + unsigned long long seconds = ((unsigned long long) (modtime.dwHighDateTime)) << 32; + seconds |= modtime.dwLowDateTime; + + return (seconds - 116444736000000000) / 10000000; + #else + struct stat buffer; + stat(filename, &buffer); + + return (time_t) buffer.st_mtim.tv_sec; + #endif + + return (time_t) 0; + } + + inline + const char* file_extension (const char *filename) + { + char *dot = strrchr((char *) filename, '.'); + + if (!dot || dot == filename) { + return ""; } - inline - const char* file_extension (const char *filename) - { - char *dot = strrchr((char *) filename, '.'); + return dot + 1; + } - if (!dot || dot == filename) { - return ""; - } + typedef struct { + char *content; + int size = 0; // doesn't include null termination (same as strlen) + } file_body; - return dot + 1; + file_body read_file (const char *filename) + { + file_body file = {0}; + + FILE *fp = fopen(filename, "rb"); + if (!fp) { + return file; } - typedef struct { - char *content; - int size = 0; // doesn't include null termination (same as strlen) - } file_body; + fseek(fp, 0, SEEK_END); + file.size = ftell(fp); + fseek(fp, 0, SEEK_SET); - file_body read_file (const char *filename) - { - file_body file = {0}; - - FILE *fp = fopen(filename, "rb"); - if (!fp) { - return file; - } - - fseek(fp, 0, SEEK_END); - file.size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - file.content = (char *) malloc((file.size + 1) * sizeof(char)); - if (!file.content) { - fprintf(stderr, "CRITICAL: malloc failed"); - - return file; - } - - fread(file.content, file.size, 1, fp); - file.content[file.size] = 0; - - fclose(fp); + file.content = (char *) malloc((file.size + 1) * sizeof(char)); + if (!file.content) { + fprintf(stderr, "CRITICAL: malloc failed"); return file; } + + fread(file.content, file.size, 1, fp); + file.content[file.size] = 0; + + fclose(fp); + + return file; } } diff --git a/Utils/Rng/StringUtils.h b/Utils/Rng/StringUtils.h index b5ec8f3..66aecf6 100755 --- a/Utils/Rng/StringUtils.h +++ b/Utils/Rng/StringUtils.h @@ -14,30 +14,26 @@ #include #include -namespace Utils +namespace Utils::Rng::StringUtils { - namespace Rng - { - namespace StringUtils - { - inline - char* generate_string( - size_t min = 10, size_t max = 10, - char *charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", int charsetLength = 62 - ) { - srand(time(0)); + inline + char* generate_string( + size_t min = 10, size_t max = 10, + char *charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", int charsetLength = 62 + ) { + srand(time(0)); - size_t length = (rand() % (max - min + 1)) + min; - char *randomString = (char *) malloc(length + 1); + size_t length = (rand() % (max - min + 1)) + min; + char *randomString = (char *) malloc(length + 1); - for (size_t i = 0; i < length; ++i) { - randomString[i] = charset[rand() % charsetLength]; - } - - randomString[length] = '\0'; - - return randomString; - } + for (size_t i = 0; i < length; ++i) { + randomString[i] = charset[rand() % charsetLength]; } + + randomString[length] = '\0'; + + return randomString; } -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/Utils/StringUtils.h b/Utils/StringUtils.h index 07a55f6..acab707 100755 --- a/Utils/StringUtils.h +++ b/Utils/StringUtils.h @@ -17,212 +17,223 @@ #include "MathUtils.h" #include "ArraySort.h" -namespace Utils +namespace Utils::StringUtils { - namespace StringUtils + inline + char *search_replace(const char *haystack, const char *needle, const char *replace) { - inline - char *search_replace(const char *haystack, const char *needle, const char *replace) - { - const char *haystackT = haystack; + const char *haystackT = haystack; - size_t i; - size_t match = 0; - size_t oldLength = strlen(needle); - size_t newLength = strlen(replace); + size_t i; + size_t match = 0; + size_t oldLength = strlen(needle); + size_t newLength = strlen(replace); - for (i = 0; haystack[i] != '\0'; ++i) { - if (strstr(&haystack[i], needle) == &haystack[i]) { - ++match; + for (i = 0; haystack[i] != '\0'; ++i) { + if (strstr(&haystack[i], needle) == &haystack[i]) { + ++match; - i += oldLength - 1; - } + i += oldLength - 1; } - - char *result = (char *) malloc(i + match * (newLength - oldLength) + 1); - if (!result) { - return NULL; - } - - size_t c = 0; - while (*haystack && c < i + match * (newLength - oldLength)) { - if (strstr(haystack, needle) == haystack) { - strcpy(&result[c], (char *) replace); - - c += newLength; - haystack += oldLength; - } else { - result[c++] = *haystack++; - } - } - - if (c > i + match * (newLength - oldLength)) { - c = i + match * (newLength - oldLength); - } - - result[c] = '\0'; - - return result; } - inline - bool is_number(const char *s) - { - while (*s != '\0') { - if (!isdigit(*s)) { - return false; - } - - ++s; - } - - return true; + char *result = (char *) malloc(i + match * (newLength - oldLength) + 1); + if (!result) { + return NULL; } - inline - size_t str_count(char *str, char *substr) - { - int l1 = strlen(str); - int l2 = strlen(substr); + size_t c = 0; + while (*haystack && c < i + match * (newLength - oldLength)) { + if (strstr(haystack, needle) == haystack) { + strcpy(&result[c], (char *) replace); - if (l2 == 0 || l1 < l2) { - return 0; + c += newLength; + haystack += oldLength; + } else { + result[c++] = *haystack++; } - - int count = 0; - for (str = strstr(str, substr); str; str = strstr(str + l2, substr)) { - ++count; - } - - return count; } - char *strsep(char **sp, char *sep) - { - char *p, *s; - - if (sp == NULL || *sp == NULL || **sp == '\0') { - return(NULL); - } - - s = *sp; - p = s + strcspn(s, sep); - - if (*p != '\0') { - *p++ = '\0'; - } - - *sp = p; - - return(s); + if (c > i + match * (newLength - oldLength)) { + c = i + match * (newLength - oldLength); } - int str_split(char **list, char *str, const char delim) - { - size_t splits = str_count(str, (char *) &delim) + 1; - list = (char **) malloc(splits * sizeof(char *)); + result[c] = '\0'; - char *token; - int i = 0; + return result; + } - while ((token = strsep(&str, (char *) &delim)) != NULL) { - list[i] = (char *) malloc(strlen(token + 1) * sizeof(char)); - memcpy(list[i], token, (strlen(token) + 1) * sizeof(char)); - - ++i; + inline + bool is_number(const char *s) + { + while (*s != '\0') { + if (!isdigit(*s)) { + return false; } - return i; + ++s; } - typedef struct { - char **values; - int *masks; - int size; - } text_diff; + return true; + } - text_diff computeLCSDiff(char **from, int fromSize, char **to, int toSize) - { - char **diffValues = (char **) malloc(fromSize * toSize * sizeof(char *)); - int *diffMasks = (int *) calloc(fromSize * toSize, sizeof(int)); + inline + size_t str_count(char *str, char *substr) + { + int l1 = strlen(str); + int l2 = strlen(substr); - int *dm = (int *) calloc((fromSize + 1) * (toSize + 1), sizeof(int)); + if (l2 == 0 || l1 < l2) { + return 0; + } - if (!diffValues || !diffMasks || !dm) { - fprintf(stderr, "CRITICAL: malloc failed"); + int count = 0; + for (str = strstr(str, substr); str; str = strstr(str + l2, substr)) { + ++count; + } + + return count; + } + + inline + char *strsep(char **sp, char *sep) + { + char *p, *s; + + if (sp == NULL || *sp == NULL || **sp == '\0') { + return(NULL); + } + + s = *sp; + p = s + strcspn(s, sep); + + if (*p != '\0') { + *p++ = '\0'; + } + + *sp = p; + + return(s); + } + + // @todo Implement delim as const char* (also allow \0 length) + inline + int str_split(char **list, char *str, const char delim) + { + size_t splits = str_count(str, (char *) &delim) + 1; + list = (char **) malloc(splits * sizeof(char *)); + + char *token; + int i = 0; + + while ((token = strsep(&str, (char *) &delim)) != NULL) { + list[i] = (char *) malloc(strlen(token + 1) * sizeof(char)); + memcpy(list[i], token, (strlen(token) + 1) * sizeof(char)); + + ++i; + } + + return i; + } + + // @todo Implement delim as const char* (also allow \0 length) + inline + char* str_combine(char **str, size_t size, const char delim) + { + if (size < 1) { + return NULL; + } + + size_t total_size = 0; + for (size_t i = 0; i < size; ++i) { + total_size += strlen(str[i]); + } + + // If delim ever becomes a string replace * 1 with * strlen(delimiter) + total_size += (size - 1) * 1 + 1; + + char *result = (char *) malloc(total_size * sizeof(char)); + if (!result) { + return NULL; + } + + strcpy(result, str[0]); + + for (size_t i = 0; i < size; ++i) { + strcat(result, &delim); + strcat(result, str[i]); + } + + return result; + } + + typedef struct { + char **values; + int64_t *masks; + size_t size; + } text_diff; + + text_diff computeLCSDiff(char **from, int fromSize, char **to, int toSize) + { + char **diffValues = (char **) malloc(fromSize * toSize * sizeof(char *)); + int64_t *diffMasks = (int64_t *) calloc(fromSize * toSize, sizeof(int64_t)); + + int *dm = (int *) calloc((fromSize + 1) * (toSize + 1), sizeof(int)); + + if (!diffValues || !diffMasks || !dm) { + fprintf(stderr, "CRITICAL: malloc failed"); + } + + int i = 0; + int j = 0; + + /* Handled with calloc + for (j = 0; j <= toSize; ++j) { + dm[0 + j] = 0; + } + + for (i = 1; i <= fromSize; ++i) { + dm[i * fromSize + 0] = 0; + } + */ + + for (i = 1; i <= fromSize; ++i) { + for (j = 1; j <= toSize; ++j) { + dm[i * fromSize + j] = strcmp(from[i - 1], to[j - 1]) == 0 + ? dm[(i - 1) * fromSize + (j - 1)] + 1 + : oms_max(dm[(i - 1) * fromSize + j], dm[i * fromSize + (j - 1)]); } + } - int i = 0; - int j = 0; + size_t diffIndex = 0; - /* Handled with calloc - for (j = 0; j <= toSize; ++j) { - dm[0 + j] = 0; - } + i = fromSize; + j = toSize; - for (i = 1; i <= fromSize; ++i) { - dm[i * fromSize + 0] = 0; - } - */ - - for (i = 1; i <= fromSize; ++i) { - for (j = 1; j <= toSize; ++j) { - dm[i * fromSize + j] = strcmp(from[i - 1], to[j - 1]) == 0 - ? dm[(i - 1) * fromSize + (j - 1)] + 1 - : oms_max(dm[(i - 1) * fromSize + j], dm[i * fromSize + (j - 1)]); - } - } - - int diffIndex = 0; - - i = fromSize; - j = toSize; - - while ((i > 0 || j > 0) && diffIndex < fromSize * toSize) { - if (j > 0 && dm[i * fromSize + (j - 1)] == dm[i * fromSize + j]) { - diffValues[diffIndex] = (char *) malloc((strlen(to[j - 1]) + 1) * sizeof(char)); - if (!diffValues[diffIndex]) { - fprintf(stderr, "CRITICAL: malloc failed"); - - continue; - } - - #ifdef _WIN32 - strcpy_s(diffValues[diffIndex], (strlen(to[j - 1]) + 1) * sizeof(char), to[j - 1]); - #else - strcpy(diffValues[diffIndex], to[j - 1]); - #endif - - diffMasks[diffIndex] = 1; - - --j; - ++diffIndex; + while ((i > 0 || j > 0) && diffIndex < fromSize * toSize) { + if (j > 0 && dm[i * fromSize + (j - 1)] == dm[i * fromSize + j]) { + diffValues[diffIndex] = (char *) malloc((strlen(to[j - 1]) + 1) * sizeof(char)); + if (!diffValues[diffIndex]) { + fprintf(stderr, "CRITICAL: malloc failed"); continue; } - if (i > 0 && dm[(i - 1) * fromSize + j] == dm[i * fromSize + j]) { - diffValues[diffIndex] = (char *) malloc((strlen(from[i - 1]) + 1) * sizeof(char)); - if (!diffValues[diffIndex]) { - fprintf(stderr, "CRITICAL: malloc failed"); + #ifdef _WIN32 + strcpy_s(diffValues[diffIndex], (strlen(to[j - 1]) + 1) * sizeof(char), to[j - 1]); + #else + strcpy(diffValues[diffIndex], to[j - 1]); + #endif - continue; - } + diffMasks[diffIndex] = 1; - #ifdef _WIN32 - strcpy_s(diffValues[diffIndex], (strlen(from[i - 1]) + 1) * sizeof(char), from[i - 1]); - #else - strcpy(diffValues[diffIndex], from[i - 1]); - #endif + --j; + ++diffIndex; - diffMasks[diffIndex] = -1; - - --i; - ++diffIndex; - - continue; - } + continue; + } + if (i > 0 && dm[(i - 1) * fromSize + j] == dm[i * fromSize + j]) { diffValues[diffIndex] = (char *) malloc((strlen(from[i - 1]) + 1) * sizeof(char)); if (!diffValues[diffIndex]) { fprintf(stderr, "CRITICAL: malloc failed"); @@ -236,41 +247,61 @@ namespace Utils strcpy(diffValues[diffIndex], from[i - 1]); #endif - /* Handled with calloc - diffMasks[diffIndex] = 0; - */ + diffMasks[diffIndex] = -1; --i; - --j; ++diffIndex; + + continue; } - free(dm); - - // @todo do we even need to realloc? - char **diffValuesT = (char **) realloc(diffValues, diffIndex * sizeof(char *)); - if (!diffValuesT) { - free(diffValues); - } - diffValues = diffValuesT; - - int *diffMasksT = (int *) realloc(diffMasks, diffIndex * sizeof(int)); - if (!diffMasksT) { - free(diffMasks); - } - diffMasks = diffMasksT; - - if (!diffValues || !diffMasks) { + diffValues[diffIndex] = (char *) malloc((strlen(from[i - 1]) + 1) * sizeof(char)); + if (!diffValues[diffIndex]) { fprintf(stderr, "CRITICAL: malloc failed"); - return text_diff{}; + continue; } - ArraySort::reverse_char(diffValues, diffIndex); - ArraySort::reverse_int(diffMasks, diffIndex); + #ifdef _WIN32 + strcpy_s(diffValues[diffIndex], (strlen(from[i - 1]) + 1) * sizeof(char), from[i - 1]); + #else + strcpy(diffValues[diffIndex], from[i - 1]); + #endif - return text_diff{diffValues, diffMasks, diffIndex}; + /* Handled with calloc + diffMasks[diffIndex] = 0; + */ + + --i; + --j; + ++diffIndex; } + + free(dm); + + // @todo do we even need to realloc? + char **diffValuesT = (char **) realloc(diffValues, diffIndex * sizeof(char *)); + if (!diffValuesT) { + free(diffValues); + } + diffValues = diffValuesT; + + int64_t *diffMasksT = (int64_t *) realloc(diffMasks, diffIndex * sizeof(int64_t)); + if (!diffMasksT) { + free(diffMasks); + } + diffMasks = diffMasksT; + + if (!diffValues || !diffMasks) { + fprintf(stderr, "CRITICAL: malloc failed"); + + return text_diff{}; + } + + ArraySort::reverse_char(diffValues, diffIndex); + ArraySort::reverse_int(diffMasks, diffIndex); + + return text_diff{diffValues, diffMasks, diffIndex}; } } diff --git a/Utils/WebUtils.h b/Utils/WebUtils.h index 25f2d72..cfe2811 100755 --- a/Utils/WebUtils.h +++ b/Utils/WebUtils.h @@ -23,276 +23,273 @@ #include "FileUtils.h" -namespace Utils +namespace Utils::WebUtils { - namespace WebUtils + static bool CURL_SETUP = false; + + inline + void setup() { - static bool CURL_SETUP = false; + curl_global_init(CURL_GLOBAL_DEFAULT); + Utils::WebUtils::CURL_SETUP = true; + } - inline - void setup() - { - curl_global_init(CURL_GLOBAL_DEFAULT); - Utils::WebUtils::CURL_SETUP = true; - } + inline + void clean() + { + curl_global_cleanup(); + Utils::WebUtils::CURL_SETUP = false; + } - inline - void clean() - { - curl_global_cleanup(); - Utils::WebUtils::CURL_SETUP = false; - } + int write_download_data (void *ptr, size_t size, size_t nmeb, void *stream) + { + Utils::FileUtils::file_body *out = (Utils::FileUtils::file_body *) stream; + size_t outSize = size * nmeb; - int write_download_data (void *ptr, size_t size, size_t nmeb, void *stream) - { - Utils::FileUtils::file_body *out = (Utils::FileUtils::file_body *) stream; - size_t outSize = size * nmeb; + if (out->size == 0) { + // first time this function is called for a specific resource + out->content = (char *) malloc((outSize + 1) * sizeof(char)); + if (!out->content) { + fprintf(stderr, "CRITICAL: malloc failed"); - if (out->size == 0) { - // first time this function is called for a specific resource - out->content = (char *) malloc((outSize + 1) * sizeof(char)); - if (!out->content) { - fprintf(stderr, "CRITICAL: malloc failed"); - - return 0; - } - - if (out->content) { - memcpy(out->content, ptr, outSize * sizeof(char)); - - out->size = (int) outSize; - out->content[out->size] = 0; - } - } else { - // the max buffer (16384 = 16k) is exceeded, then this is called again and needs to get extended - char *temp = (char *) malloc((outSize + out->size + 1) * sizeof(char)); - - memcpy(temp, out->content, out->size * sizeof(char)); - memcpy(temp + out->size * sizeof(char), ptr, outSize * sizeof(char)); - - free(out->content); - - out->content = temp; - out->size += outSize; - out->content[out->size] = 0; - } - - return out->size; - } - - typedef struct { - size_t size = 0; - const char **resources = NULL; - } ResourceTypes; - - typedef struct { - size_t size = 0; - const char **urls = NULL; - } Urls; - - Utils::FileUtils::file_body download (char *url) - { - Utils::FileUtils::file_body page = {0}; - - if (!Utils::WebUtils::CURL_SETUP) { - Utils::WebUtils::setup(); - } - - CURL *h = curl_easy_init(); - - curl_easy_setopt(h, CURLOPT_URL, url); - curl_easy_setopt(h, CURLOPT_PRIVATE, url); - curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, write_download_data); - curl_easy_setopt(h, CURLOPT_WRITEDATA, &page); - curl_easy_perform(h); - curl_easy_cleanup(h); - - return page; - } - - inline - void add_transfer(CURLM *cm, char *url, int *left) - { - CURL *h = curl_easy_init(); - - Utils::FileUtils::file_body *page = (Utils::FileUtils::file_body *) malloc(sizeof(Utils::FileUtils::file_body)); - page->size = 0; - - curl_easy_setopt(h, CURLOPT_URL, url); - curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, write_download_data); - curl_easy_setopt(h, CURLOPT_WRITEDATA, page); - curl_easy_setopt(h, CURLOPT_PRIVATE, page); - - curl_easy_setopt(h, CURLOPT_ACCEPT_ENCODING, ""); - curl_easy_setopt(h, CURLOPT_TIMEOUT, 5L); - curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(h, CURLOPT_MAXREDIRS, 10L); - curl_easy_setopt(h, CURLOPT_CONNECTTIMEOUT, 2L); - curl_easy_setopt(h, CURLOPT_COOKIEFILE, ""); - curl_easy_setopt(h, CURLOPT_FILETIME, 1L); - curl_easy_setopt(h, CURLOPT_USERAGENT, "firefox"); - curl_easy_setopt(h, CURLOPT_HTTPAUTH, CURLAUTH_ANY); - curl_easy_setopt(h, CURLOPT_UNRESTRICTED_AUTH, 1L); - curl_easy_setopt(h, CURLOPT_PROXYAUTH, CURLAUTH_ANY); - curl_easy_setopt(h, CURLOPT_EXPECT_100_TIMEOUT_MS, 0L); - - curl_multi_add_handle(cm, h); - - ++(*left); - } - - size_t follow_links(CURLM *cm, Utils::FileUtils::file_body *page, char *url, int *left) - { - int opts = HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_NONET; - htmlDocPtr doc = htmlReadMemory(page->content, page->size, url, NULL, opts); - - if(!doc) { return 0; } - xmlChar *xpath = (xmlChar*) "//img/@src"; - xmlXPathContextPtr context = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context); - xmlXPathFreeContext(context); + if (out->content) { + memcpy(out->content, ptr, outSize * sizeof(char)); - if(!result) { - return 0; + out->size = (int) outSize; + out->content[out->size] = 0; } + } else { + // the max buffer (16384 = 16k) is exceeded, then this is called again and needs to get extended + char *temp = (char *) malloc((outSize + out->size + 1) * sizeof(char)); - xmlNodeSetPtr nodeset = result->nodesetval; - if(xmlXPathNodeSetIsEmpty(nodeset)) { - xmlXPathFreeObject(result); - return 0; - } + memcpy(temp, out->content, out->size * sizeof(char)); + memcpy(temp + out->size * sizeof(char), ptr, outSize * sizeof(char)); - size_t count = 0; - int i; + free(out->content); - for(i = 0; i < nodeset->nodeNr; i++) { - double r = rand(); - int x = r * nodeset->nodeNr / RAND_MAX; - const xmlNode *node = nodeset->nodeTab[x]->xmlChildrenNode; - xmlChar *href = xmlNodeListGetString(doc, node, 1); + out->content = temp; + out->size += outSize; + out->content[out->size] = 0; + } - // follow relative link - if(true) { - xmlChar *orig = href; + return out->size; + } - // @todo consider base= tag which has an impact on relative links - href = xmlBuildURI(href, (xmlChar *) url); - xmlFree(orig); - } + typedef struct { + size_t size = 0; + const char **resources = NULL; + } ResourceTypes; - char *link = (char *) href; - if(!link || strlen(link) < 10) { - continue; - } + typedef struct { + size_t size = 0; + const char **urls = NULL; + } Urls; - if(!strncmp(link, "http://", 7) || !strncmp(link, "https://", 8) || !strncmp(link, "www.", 4)) { - Utils::WebUtils::add_transfer(cm, link, left); + Utils::FileUtils::file_body download (char *url) + { + Utils::FileUtils::file_body page = {0}; - // limit to max 1000 links per page to follow - if(count++ == 1000) { - break; - } - } + if (!Utils::WebUtils::CURL_SETUP) { + Utils::WebUtils::setup(); + } - xmlFree(link); - } + CURL *h = curl_easy_init(); + curl_easy_setopt(h, CURLOPT_URL, url); + curl_easy_setopt(h, CURLOPT_PRIVATE, url); + curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, write_download_data); + curl_easy_setopt(h, CURLOPT_WRITEDATA, &page); + curl_easy_perform(h); + curl_easy_cleanup(h); + + return page; + } + + inline + void add_transfer(CURLM *cm, char *url, int *left) + { + CURL *h = curl_easy_init(); + + Utils::FileUtils::file_body *page = (Utils::FileUtils::file_body *) malloc(sizeof(Utils::FileUtils::file_body)); + page->size = 0; + + curl_easy_setopt(h, CURLOPT_URL, url); + curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, write_download_data); + curl_easy_setopt(h, CURLOPT_WRITEDATA, page); + curl_easy_setopt(h, CURLOPT_PRIVATE, page); + + curl_easy_setopt(h, CURLOPT_ACCEPT_ENCODING, ""); + curl_easy_setopt(h, CURLOPT_TIMEOUT, 5L); + curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(h, CURLOPT_MAXREDIRS, 10L); + curl_easy_setopt(h, CURLOPT_CONNECTTIMEOUT, 2L); + curl_easy_setopt(h, CURLOPT_COOKIEFILE, ""); + curl_easy_setopt(h, CURLOPT_FILETIME, 1L); + curl_easy_setopt(h, CURLOPT_USERAGENT, "firefox"); + curl_easy_setopt(h, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_easy_setopt(h, CURLOPT_UNRESTRICTED_AUTH, 1L); + curl_easy_setopt(h, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + curl_easy_setopt(h, CURLOPT_EXPECT_100_TIMEOUT_MS, 0L); + + curl_multi_add_handle(cm, h); + + ++(*left); + } + + size_t follow_links(CURLM *cm, Utils::FileUtils::file_body *page, char *url, int *left) + { + int opts = HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_NONET; + htmlDocPtr doc = htmlReadMemory(page->content, page->size, url, NULL, opts); + + if(!doc) { + return 0; + } + + xmlChar *xpath = (xmlChar*) "//img/@src"; + xmlXPathContextPtr context = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context); + xmlXPathFreeContext(context); + + if(!result) { + return 0; + } + + xmlNodeSetPtr nodeset = result->nodesetval; + if(xmlXPathNodeSetIsEmpty(nodeset)) { xmlXPathFreeObject(result); - - return count; + return 0; } - void *multi_download( - Urls urls, - const char *baseDir, - int max_parrallel = 1, - ResourceTypes *resources = NULL - ) { - if (!Utils::WebUtils::CURL_SETUP) { - Utils::WebUtils::setup(); + size_t count = 0; + int i; + + for(i = 0; i < nodeset->nodeNr; i++) { + double r = rand(); + int x = r * nodeset->nodeNr / RAND_MAX; + const xmlNode *node = nodeset->nodeTab[x]->xmlChildrenNode; + xmlChar *href = xmlNodeListGetString(doc, node, 1); + + // follow relative link + if(true) { + xmlChar *orig = href; + + // @todo consider base= tag which has an impact on relative links + href = xmlBuildURI(href, (xmlChar *) url); + xmlFree(orig); } - CURLM *cm = curl_multi_init(); - curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, max_parrallel); - curl_multi_setopt(cm, CURLMOPT_MAX_TOTAL_CONNECTIONS, max_parrallel); - curl_multi_setopt(cm, CURLMOPT_MAX_HOST_CONNECTIONS, 5); - - #ifdef CURLPIPE_MULTIPLEX - curl_multi_setopt(cm, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); - #endif - - int downloads = 0; - int left = 0; - - for(downloads = 0; downloads < max_parrallel && downloads < urls.size; ++downloads) { - Utils::WebUtils::add_transfer(cm, urls.urls[downloads], &left); + char *link = (char *) href; + if(!link || strlen(link) < 10) { + continue; } - CURLMsg *msg; - int msgs_left = -1; + if(!strncmp(link, "http://", 7) || !strncmp(link, "https://", 8) || !strncmp(link, "www.", 4)) { + Utils::WebUtils::add_transfer(cm, link, left); - do { - int alive = 1; - curl_multi_perform(cm, &alive); + // limit to max 1000 links per page to follow + if(count++ == 1000) { + break; + } + } - while((msg = curl_multi_info_read(cm, &msgs_left))) { - if(msg->msg == CURLMSG_DONE) { - CURL *e = msg->easy_handle; - char *url; - Utils::FileUtils::file_body *page; + xmlFree(link); + } - curl_easy_getinfo(e, CURLINFO_PRIVATE, &page); - curl_easy_getinfo(e, CURLINFO_EFFECTIVE_URL, &url); + xmlXPathFreeObject(result); - if (msg->data.result == CURLE_OK) { - long statusCode = 0; - curl_easy_getinfo(e, CURLINFO_RESPONSE_CDE, &statusCode); + return count; + } - if (statusCode == 200) { - char *ctype; - curl_easy_getinfo(e, CURLINFO_CONTENT_TYPE, &ctype); + void *multi_download( + Urls urls, + const char *baseDir, + int max_parrallel = 1, + ResourceTypes *resources = NULL + ) { + if (!Utils::WebUtils::CURL_SETUP) { + Utils::WebUtils::setup(); + } - // @todo save file (how to handle base resources, either pass base url or save based on url?) + CURLM *cm = curl_multi_init(); + curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, max_parrallel); + curl_multi_setopt(cm, CURLMOPT_MAX_TOTAL_CONNECTIONS, max_parrallel); + curl_multi_setopt(cm, CURLMOPT_MAX_HOST_CONNECTIONS, 5); - if (ctype != NULL && strlen(ctype) > 10 && strstr(ctype, "text/html")) { - // @todo check limits - left += follow_links(cm, page, url, &left); - } + #ifdef CURLPIPE_MULTIPLEX + curl_multi_setopt(cm, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + #endif + + int downloads = 0; + int left = 0; + + for(downloads = 0; downloads < max_parrallel && downloads < urls.size; ++downloads) { + Utils::WebUtils::add_transfer(cm, urls.urls[downloads], &left); + } + + CURLMsg *msg; + int msgs_left = -1; + + do { + int alive = 1; + curl_multi_perform(cm, &alive); + + while((msg = curl_multi_info_read(cm, &msgs_left))) { + if(msg->msg == CURLMSG_DONE) { + CURL *e = msg->easy_handle; + char *url; + Utils::FileUtils::file_body *page; + + curl_easy_getinfo(e, CURLINFO_PRIVATE, &page); + curl_easy_getinfo(e, CURLINFO_EFFECTIVE_URL, &url); + + if (msg->data.result == CURLE_OK) { + long statusCode = 0; + curl_easy_getinfo(e, CURLINFO_RESPONSE_CDE, &statusCode); + + if (statusCode == 200) { + char *ctype; + curl_easy_getinfo(e, CURLINFO_CONTENT_TYPE, &ctype); + + // @todo save file (how to handle base resources, either pass base url or save based on url?) + + if (ctype != NULL && strlen(ctype) > 10 && strstr(ctype, "text/html")) { + // @todo check limits + left += follow_links(cm, page, url, &left); } } - - curl_multi_remove_handle(cm, e); - curl_easy_cleanup(e); - free(page->content); - free(page); - - --left; - } else { - fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg); } - if(downloads < urls.size) { - ++downloads; - Utils::WebUtils::add_transfer(cm, urls.urls[downloads], &left); - } + curl_multi_remove_handle(cm, e); + curl_easy_cleanup(e); + free(page->content); + free(page); + + --left; + } else { + fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg); } - if(left > 0) { - curl_multi_wait(cm, NULL, 0, 1000, NULL); + if(downloads < urls.size) { + ++downloads; + Utils::WebUtils::add_transfer(cm, urls.urls[downloads], &left); } - } while(left > 0); + } - curl_multi_cleanup(cm); + if(left > 0) { + curl_multi_wait(cm, NULL, 0, 1000, NULL); + } + } while(left > 0); - return null; - } + curl_multi_cleanup(cm); + + return null; } }