1
0

Compare commits

..

10 Commits

Author SHA1 Message Date
d3fd3c2b0d commit something which idk when i write them 2026-04-21 22:33:21 +08:00
5c18e2ccbc fix: change code to suit for new YYCC library 2024-08-15 16:57:12 +08:00
1dba1e0674 feat: basically finish standalone mode.
- finish standalone mode but only tested on Virtools 2.1 environment.
- add DROP TABLE statement before CREATE TABLE to resolve fail to create table issue when opening an existing database file.
2024-08-11 17:51:48 +08:00
0e08e518c4 fix: fix standalone code but not finished 2024-08-11 00:25:08 +08:00
7d9b7f14e8 fix: finish basic export test on Virtools 5 environment 2024-08-09 16:19:26 +08:00
6943088df1 fix: fix script exporter and some script for database fix 2024-08-09 11:28:44 +08:00
7ffc191f66 feat: continue updating script exporter 2024-08-08 22:02:02 +08:00
46a6222959 feat: finish half of script exporter 2024-08-08 17:47:27 +08:00
7c5bc44724 refactor: refactor project
- finish document export function.
- add lost database validation code in export function.
- add assistant macros for convenient utilize functions located in utilities namespace.
- update sqlite database open function.
2024-08-07 11:40:18 +08:00
c1abf2cdcd refactor: refactor project.
- apply reporter for exporter.
- use utf8 as exported string instead of ordinary string.
- finish environment export check.
2024-08-06 18:06:17 +08:00
20 changed files with 1749 additions and 436 deletions

View File

@@ -1,15 +1,23 @@
if (WIN32) if (WIN32)
# In Windows, we use custom way to import SQLite # In Windows, we use custom way to import SQLite.
# Before using this CMake file in Windows, you should do following steps first.
# 1. Get SQLite SDK (amalgamation) and binaries (sqlite-dll) from http://www.sqlite.org/
# 2. Extract SQLite SDK and binaries to your preferred directory.
# 3. Open Developer Command Prompt for Visual Studio (embedded with Visual Studio installation)
# 4. Use `cd` command to switch work directory to the directory where you extract binaries.
# 5. Execute `lib /DEF:sqlite3.def /OUT:sqlite3.lib /MACHINE:x86` (`x86` is the architecture of your SQLite3, you may change it according to your requirement).
# 6. Now you have a generated LIB file for MSVC linking.
# Check variables# Check YYCC path variable # Check SQLite path variable
if (NOT DEFINED SQLITE_AMALGAMATION_PATH) if (NOT DEFINED SQLITE_AMALGAMATION_PATH)
message(FATAL_ERROR "You must set SQLITE_AMALGAMATION_PATH variable to the header of SQLite library.") message(FATAL_ERROR "You must set SQLITE_AMALGAMATION_PATH to the directory where the SQLite3 header file locate.")
endif() endif()
if (NOT DEFINED SQLITE_DLL_PATH) if (NOT DEFINED SQLITE_DLL_PATH)
message(FATAL_ERROR "You must set SQLITE_DLL_PATH variable the directory containing generated linking LIB file.") message(FATAL_ERROR "You must set SQLITE_DLL_PATH to the directory where the generated SQLite3 LIB file locate for linking.")
endif() endif()
# Add imported library # Add imported library
add_library(SQLite3 INTERFACE IMPORTED) add_library(SQLite3 INTERFACE IMPORTED)
# Add alias for it to let it has the same behavior with CMake imported SQLite3.
add_library(SQLite3::SQLite3 ALIAS SQLite3) add_library(SQLite3::SQLite3 ALIAS SQLite3)
# Setup header files # Setup header files
set_target_properties(SQLite3 PROPERTIES set_target_properties(SQLite3 PROPERTIES
@@ -22,6 +30,6 @@ if (WIN32)
"${SQLITE_DLL_PATH}/sqlite3.lib" "${SQLITE_DLL_PATH}/sqlite3.lib"
) )
else () else ()
# In non-Windows, we import SQLite from CMake # In non-Windows, we simply import SQLite3 from CMake preset.
find_package(SQLite3 REQUIRED) find_package(SQLite3 REQUIRED)
endif () endif ()

View File

@@ -1,9 +1,15 @@
# Check YYCC path variable
# Check YYCC path environment variable
if (NOT DEFINED YYCC_PATH) if (NOT DEFINED YYCC_PATH)
message(FATAL_ERROR "You must set YYCC_PATH variable to one of CMake distribution of YYCC installation path.") message(FATAL_ERROR "You must set YYCC_PATH variable to one of YYCC CMake distribution installation path.")
endif() endif()
# Find YYCC library # Find YYCC library
find_package(YYCCommonplace REQUIRED # It will produce YYCC::YYCCommonplace target for including and linking.
HINTS ${YYCC_PATH} NO_DEFAULT_PATH #
) # Please note we MUST set CMake variable YYCCommonplace_ROOT to make sure CMake can found YYCC in out given path.
# The cache status of YYCCommonplace_ROOT is doesn't matter.
# CMake will throw error if we use HINTS feature in find_package to find YYCC.
set(YYCCommonplace_ROOT ${YYCC_PATH} CACHE PATH
"The path to YYCC CMake distribution installation path.")
find_package(YYCCommonplace REQUIRED)

View File

@@ -17,9 +17,6 @@ FILES
target_include_directories(VSWDecorator target_include_directories(VSWDecorator
PUBLIC PUBLIC
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
YYCC::YYCCommonplace
SQLite3::SQLite3
VSWShared
) )
# Setup linked library # Setup linked library
target_link_libraries(VSWDecorator target_link_libraries(VSWDecorator

View File

@@ -54,10 +54,6 @@ FILES
target_include_directories(VSWMaterializer target_include_directories(VSWMaterializer
PRIVATE PRIVATE
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
YYCC::YYCCommonplace
SQLite3::SQLite3
VirtoolsSDK
VSWShared
) )
# Setup linked library # Setup linked library
target_link_libraries(VSWMaterializer target_link_libraries(VSWMaterializer

View File

@@ -4,33 +4,41 @@
namespace VSW::Materializer::DataTypes { namespace VSW::Materializer::DataTypes {
struct BlobDescriptor {
const void* ptr;
int length;
};
namespace Script { namespace Script {
struct Table_script { struct Table_script {
CK_ID thisobj; CK_ID beobj;
std::string host_name; YYCC::yycc_u8string beobj_name;
int index; int behavior_index;
CK_ID behavior; CK_ID behavior;
}; };
struct Table_behavior { struct Table_behavior {
CK_ID thisobj; CK_ID thisobj;
std::string name; YYCC::yycc_u8string name;
CK_BEHAVIOR_TYPE type; CK_BEHAVIOR_TYPE type;
std::string proto_name; YYCC::yycc_u8string proto_name;
std::string proto_guid; int64_t proto_guid;
CK_BEHAVIOR_FLAGS flags; CK_BEHAVIOR_FLAGS flags;
int priority; int priority;
CKDWORD version; CKDWORD version;
//pTarget, pIn, pOut, bIn, bOut int pin_count_ptarget;
std::string pin_count; int pin_count_pin;
int pin_count_pout;
int pin_count_bin;
int pin_count_bout;
CK_ID parent; CK_ID parent;
}; };
struct Table_bIO { struct Table_bIO {
CK_ID thisobj; CK_ID thisobj;
int index; int index;
std::string name; YYCC::yycc_u8string name;
CK_ID parent; CK_ID parent;
}; };
struct Table_bIn : public Table_bIO {}; struct Table_bIn : public Table_bIO {};
@@ -38,9 +46,8 @@ namespace VSW::Materializer::DataTypes {
struct Table_pTarget { struct Table_pTarget {
CK_ID thisobj; CK_ID thisobj;
std::string name; YYCC::yycc_u8string name;
std::string type; int64_t type;
std::string type_guid;
CK_ID parent; CK_ID parent;
CK_ID direct_source; CK_ID direct_source;
CK_ID shared_source; CK_ID shared_source;
@@ -49,9 +56,8 @@ namespace VSW::Materializer::DataTypes {
struct Table_pIn { struct Table_pIn {
CK_ID thisobj; CK_ID thisobj;
int index; int index;
std::string name; YYCC::yycc_u8string name;
std::string type; int64_t type;
std::string type_guid;
CK_ID parent; CK_ID parent;
CK_ID direct_source; CK_ID direct_source;
CK_ID shared_source; CK_ID shared_source;
@@ -60,9 +66,8 @@ namespace VSW::Materializer::DataTypes {
struct Table_pOut { struct Table_pOut {
CK_ID thisobj; CK_ID thisobj;
int index; int index;
std::string name; YYCC::yycc_u8string name;
std::string type; int64_t type;
std::string type_guid;
CK_ID parent; CK_ID parent;
}; };
@@ -83,54 +88,53 @@ namespace VSW::Materializer::DataTypes {
struct Table_pLocal { struct Table_pLocal {
CK_ID thisobj; CK_ID thisobj;
std::string name; YYCC::yycc_u8string name;
std::string type; int64_t type;
std::string type_guid; bool is_setting;
BOOL is_setting;
CK_ID parent; CK_ID parent;
}; };
struct Table_pAttr { struct Table_pAttr {
CK_ID thisobj; CK_ID thisobj;
std::string name; YYCC::yycc_u8string name;
std::string type; int64_t type;
std::string type_guid; CK_ID owner;
}; };
struct Table_pLink { struct Table_pLink {
CK_ID input; // Basic infos
CK_ID output;
CK_ID parent; CK_ID parent;
// Input infos
//additional field CK_ID input;
CK_ID input_obj; CK_ID input_obj;
VSW::DataTypes::ParameterLinkIOType input_type; VSW::DataTypes::ParameterLinkIOType input_type;
BOOL input_is_bb; bool input_is_bb;
int input_index; int input_index;
// Output infos
CK_ID output;
CK_ID output_obj; CK_ID output_obj;
VSW::DataTypes::ParameterLinkIOType output_type; VSW::DataTypes::ParameterLinkIOType output_type;
BOOL output_is_bb; bool output_is_bb;
int output_index; int output_index;
}; };
struct Table_pOper { struct Table_pOper {
CK_ID thisobj; CK_ID thisobj;
std::string op; int64_t op;
std::string op_guid;
CK_ID parent; CK_ID parent;
}; };
struct Table_eLink { struct Table_eLink {
CK_ID export_obj; CK_ID export_obj;
CK_ID internal_obj; CK_ID internal_obj;
BOOL is_in; bool is_in;
int index; int index;
CK_ID parent; CK_ID parent;
}; };
struct Table_data { struct Table_data {
std::string field; YYCC::yycc_u8string field;
std::string data; BlobDescriptor data;
CK_ID parent; CK_ID parent;
}; };
@@ -168,14 +172,14 @@ namespace VSW::Materializer::DataTypes {
struct Table_msg { struct Table_msg {
CKMessageType index; CKMessageType index;
std::string name; YYCC::yycc_u8string name;
}; };
struct Table_obj { struct Table_obj {
CK_ID id; CK_ID id;
std::string name; YYCC::yycc_u8string name;
CK_CLASSID classid; CK_CLASSID classid;
std::string classtype; YYCC::yycc_u8string classid_name;
}; };
class DataCache { class DataCache {
@@ -193,72 +197,80 @@ namespace VSW::Materializer::DataTypes {
namespace Environment { namespace Environment {
struct Table_op { struct Table_op {
std::string func_ptr; YYCC::yycc_u8string func_ptr;
int64_t in1_guid; int64_t in1_guid;
int64_t in2_guid; int64_t in2_guid;
int64_t out_guid; int64_t out_guid;
int64_t op_guid; int64_t op_guid;
std::string op_name; YYCC::yycc_u8string op_name;
CKOperationType op_code; CKOperationType op_code;
}; };
struct Table_param { struct Table_param {
// Parameter infos
CKParameterType index; CKParameterType index;
int64_t guid; int64_t guid;
int64_t derived_from; int64_t derived_from;
std::string type_name; YYCC::yycc_u8string name;
int default_size; int default_size;
std::string func_CreateDefault; YYCC::yycc_u8string func_CreateDefault;
std::string func_Delete; YYCC::yycc_u8string func_Delete;
std::string func_SaveLoad; YYCC::yycc_u8string func_SaveLoad;
std::string func_Check; YYCC::yycc_u8string func_Check;
std::string func_Copy; YYCC::yycc_u8string func_Copy;
std::string func_String; YYCC::yycc_u8string func_String;
std::string func_UICreator; YYCC::yycc_u8string func_UICreator;
int creator_dll_index; // Dll infos
int creator_plugin_index; YYCC::yycc_u8string dll_name;
int dll_index;
int position_in_dll;
// Misc
CKDWORD flags;
CKDWORD dw_param; CKDWORD dw_param;
CKDWORD dw_flags;
CKDWORD cid; CKDWORD cid;
int64_t saver_manager; int64_t saver_manager;
}; };
struct Table_attr { struct Table_attr {
CKAttributeType index; CKAttributeType index;
std::string name; YYCC::yycc_u8string name;
CKAttributeCategory category_index; CKAttributeCategory category_index;
std::string category_name; YYCC::yycc_u8string category_name;
CK_ATTRIBUT_FLAGS flags; CK_ATTRIBUT_FLAGS flags;
CKParameterType param_index; CKParameterType param_index;
int64_t param_guid;
CK_CLASSID compatible_classid; CK_CLASSID compatible_classid;
std::string default_value; YYCC::yycc_u8string default_value;
}; };
struct Table_plugin { struct Table_plugin {
// Category // Category
std::string category; YYCC::yycc_u8string category_name;
int category_index;
// Dll infos // Dll infos
std::string dll_name; YYCC::yycc_u8string dll_name;
int dll_index;
int position_in_dll; int position_in_dll;
// Plugin infos // Plugin infos
int index;
int64_t guid; int64_t guid;
std::string desc; YYCC::yycc_u8string desc;
std::string author; YYCC::yycc_u8string author;
std::string summary; YYCC::yycc_u8string summary;
DWORD version; DWORD version;
CK_PLUGIN_TYPE type; CK_PLUGIN_TYPE type;
std::string func_init; YYCC::yycc_u8string func_init;
std::string func_exit; YYCC::yycc_u8string func_exit;
// Reader specific // Reader specific
std::string reader_fct; YYCC::yycc_u8string reader_fct;
int reader_opt_count; int reader_opt_count;
CK_DATAREADER_FLAGS reader_flags; CK_DATAREADER_FLAGS reader_flags;
int64_t reader_setting_param_guid; int64_t reader_setting_param_guid;
std::string reader_file_ext; YYCC::yycc_u8string reader_file_ext;
// Manager and Render Engine specific // Manager and Render Engine specific
CKBOOL manager_active; bool manager_active;
// Behavior specific // Behavior specific
std::string behavior_guids; YYCC::yycc_u8string behavior_guids;
}; };
#if defined(VIRTOOLS_21) #if defined(VIRTOOLS_21)
@@ -269,12 +281,12 @@ namespace VSW::Materializer::DataTypes {
using GenericVarType_t = CKVariableManager::Variable::Type; using GenericVarType_t = CKVariableManager::Variable::Type;
#endif #endif
struct Table_variable { struct Table_variable {
std::string name; YYCC::yycc_u8string name;
std::string desciption; YYCC::yycc_u8string desciption;
XWORD flags; XWORD flags;
GenericVarType_t type; GenericVarType_t type;
std::string representation; YYCC::yycc_u8string representation;
std::string data; YYCC::yycc_u8string data;
}; };
class DataCache { class DataCache {

View File

@@ -37,6 +37,9 @@ sqlite3_reset(stmt);
failed: throw std::runtime_error("fail to bind value for prepared statement."); failed: throw std::runtime_error("fail to bind value for prepared statement.");
#define REVEAL_ENUM(enum_val) static_cast<std::underlying_type_t<decltype(enum_val)>>(enum_val) #define REVEAL_ENUM(enum_val) static_cast<std::underlying_type_t<decltype(enum_val)>>(enum_val)
#define REVEAL_U8STR(u8_str) YYCC::EncodingHelper::ToOrdinary((u8_str).c_str()), -1, SQLITE_TRANSIENT
#define REVEAL_BLOB(blob_val) (blob_val).ptr, (blob_val).length, SQLITE_TRANSIENT
#define REVEAL_BOOL(bool_val) ((bool_val) ? 1 : 0)
#pragma endregion #pragma endregion
@@ -47,7 +50,7 @@ failed: throw std::runtime_error("fail to bind value for prepared statement.");
// connect to database (the argument of sqlite3 open function is UTF8) // connect to database (the argument of sqlite3 open function is UTF8)
int errcode; int errcode;
if (file.empty()) goto failed; if (file.empty()) goto failed;
errcode = sqlite3_open(YYCC::EncodingHelper::ToOrdinary(file.data()), &m_Db); errcode = sqlite3_open_v2(YYCC::EncodingHelper::ToOrdinary(file.data()), &m_Db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
if (errcode != SQLITE_OK) goto failed; if (errcode != SQLITE_OK) goto failed;
// disable synchronous to accelerate speed. // disable synchronous to accelerate speed.
@@ -121,27 +124,40 @@ failed: throw std::runtime_error("fail to bind value for prepared statement.");
AbstractDatabase(file) { AbstractDatabase(file) {
// initialize table // initialize table
BEGIN_CTOR; BEGIN_CTOR;
CTOR_SQL_EXEC("CREATE TABLE [script] ([thisobj] INTEGER, [name] TEXT, [index] INTEGER, [behavior] INTEGER);"); CTOR_SQL_EXEC("DROP TABLE IF EXISTS [script];");
CTOR_SQL_EXEC("CREATE TABLE [behavior] ([thisobj] INTEGER, [name] TEXT, [type] INTEGER, [proto_name] TEXT, [proto_guid] TEXT, [flags] INTEGER, [priority] INTEGER, [version] INTEGER, [pin_count] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("DROP TABLE IF EXISTS [behavior];");
CTOR_SQL_EXEC("CREATE TABLE [pTarget] ([thisobj] INTEGER, [name] TEXT, [type] TEXT, [type_guid] TEXT, [parent] INTEGER, [direct_source] INTEGER, [shard_source] INTEGER);"); CTOR_SQL_EXEC("DROP TABLE IF EXISTS [bIO];");
CTOR_SQL_EXEC("CREATE TABLE [pIn] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [type] TEXT, [type_guid] TEXT, [parent] INTEGER, [direct_source] INTEGER, [shared_source] INTEGER);"); CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pTarget];");
CTOR_SQL_EXEC("CREATE TABLE [pOut] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [type] TEXT, [type_guid] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pIn];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pOut];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [bLink];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pLocal];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pAttr];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pLink];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [pOper];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [eLink];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [data];");
CTOR_SQL_EXEC("CREATE TABLE [script] ([beobj] INTEGER, [beobj_name] TEXT, [behavior_index] INTEGER, [behavior] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [behavior] ([thisobj] INTEGER, [name] TEXT, [type] INTEGER, [proto_name] TEXT, [proto_guid] INTEGER, [flags] INTEGER, [priority] INTEGER, [version] INTEGER, [pin_count_ptarget] INTEGER, [pin_count_pin] INTEGER, [pin_count_pout] INTEGER, [pin_count_bin] INTEGER, [pin_count_bout] INTEGER, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pTarget] ([thisobj] INTEGER, [name] TEXT, [type] INTEGER, [parent] INTEGER, [direct_source] INTEGER, [shared_source] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pIn] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [type] INTEGER, [parent] INTEGER, [direct_source] INTEGER, [shared_source] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pOut] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [type] INTEGER, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [bIn] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [bIn] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [bOut] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [bOut] ([thisobj] INTEGER, [index] INTEGER, [name] TEXT, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [bLink] ([input] INTEGER, [output] INTEGER, [delay] INTEGER, [input_obj] INTEGER, [input_type] INTEGER, [input_index] INETEGR, [output_obj] INTEGER, [output_type] INTEGER, [output_index] INETEGR, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [bLink] ([input] INTEGER, [output] INTEGER, [delay] INTEGER, [parent] INTEGER, [input_obj] INTEGER, [input_type] INTEGER, [input_index] INTEGER, [output_obj] INTEGER, [output_type] INTEGER, [output_index] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pLocal] ([thisobj] INTEGER, [name] TEXT, [type] TEXT, [type_guid] TEXT, [is_setting] INTEGER, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [pLocal] ([thisobj] INTEGER, [name] TEXT, [type] INTEGER, [is_setting] INTEGER, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pLink] ([input] INTEGER, [output] INTEGER, [input_obj] INTEGER, [input_type] INTEGER, [input_is_bb] INTEGER, [input_index] INETEGR, [output_obj] INTEGER, [output_type] INTEGER, [output_is_bb] INTEGER, [output_index] INETEGR, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [pLink] ([parent] INTEGER, [input] INTEGER, [input_obj] INTEGER, [input_type] INTEGER, [input_is_bb] INTEGER, [input_index] INTEGER, [output] INTEGER, [output_obj] INTEGER, [output_type] INTEGER, [output_is_bb] INTEGER, [output_index] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pOper] ([thisobj] INTEGER, [op] TEXT, [op_guid] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [pOper] ([thisobj] INTEGER, [op] INTEGER, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [eLink] ([export_obj] INTEGER, [internal_obj] INTEGER, [is_in] INTEGER, [index] INTEGER, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [eLink] ([export_obj] INTEGER, [internal_obj] INTEGER, [is_in] INTEGER, [index] INTEGER, [parent] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [pAttr] ([thisobj] INTEGER, [name] TEXT, [type] TEXT, [type_guid] TEXT);"); CTOR_SQL_EXEC("CREATE TABLE [pAttr] ([thisobj] INTEGER, [name] TEXT, [type] INTEGER, [owner] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [data] ([field] TEXT, [data] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [data] ([field] TEXT, [data] BLOB, [parent] INTEGER);");
END_CTOR; END_CTOR;
} }
ScriptDatabase::~ScriptDatabase() { ScriptDatabase::~ScriptDatabase() {
// create index for quick select in following process // create index for quick select in following process
BEGIN_DTOR; BEGIN_DTOR;
DTOR_SQL_EXEC("begin;");
DTOR_SQL_EXEC("CREATE INDEX [quick_where1] ON [behavior] ([parent])"); DTOR_SQL_EXEC("CREATE INDEX [quick_where1] ON [behavior] ([parent])");
DTOR_SQL_EXEC("CREATE INDEX [quick_where2] ON [pOper] ([parent], [thisobj])"); DTOR_SQL_EXEC("CREATE INDEX [quick_where2] ON [pOper] ([parent], [thisobj])");
DTOR_SQL_EXEC("CREATE INDEX [quick_where3] ON [pTarget] ([parent])"); DTOR_SQL_EXEC("CREATE INDEX [quick_where3] ON [pTarget] ([parent])");
@@ -155,140 +171,138 @@ failed: throw std::runtime_error("fail to bind value for prepared statement.");
DTOR_SQL_EXEC("CREATE INDEX [quick_where11] ON [elink] ([parent])"); DTOR_SQL_EXEC("CREATE INDEX [quick_where11] ON [elink] ([parent])");
DTOR_SQL_EXEC("CREATE INDEX [quick_where12] ON [pAttr] ([thisobj])"); DTOR_SQL_EXEC("CREATE INDEX [quick_where12] ON [pAttr] ([thisobj])");
DTOR_SQL_EXEC("CREATE INDEX [quick_where13] ON [data] ([parent])"); DTOR_SQL_EXEC("CREATE INDEX [quick_where13] ON [data] ([parent])");
DTOR_SQL_EXEC("commit;");
END_DTOR; END_DTOR;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_script& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_script& data) {
BEGIN_WRITER("INSERT INTO [script] VALUES (?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [script] VALUES (?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.beobj));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.host_name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.beobj_name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.behavior_index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.behavior)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.behavior));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_behavior& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_behavior& data) {
BEGIN_WRITER("INSERT INTO [script_behavior] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [behavior] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.proto_name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.proto_name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.proto_guid.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.proto_guid));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.priority)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.priority));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.version)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.version));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.pin_count.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.pin_count_ptarget));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.pin_count_pin));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.pin_count_pout));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.pin_count_bin));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.pin_count_bout));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_bIn& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_bIn& data) {
BEGIN_WRITER("INSERT INTO [script_bIn] VALUES (?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [bIn] VALUES (?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_bOut& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_bOut& data) {
BEGIN_WRITER("INSERT INTO [script_bOut] VALUES (?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [bOut] VALUES (?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pIn& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pIn& data) {
BEGIN_WRITER("INSERT INTO [script_pIn] VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pIn] VALUES (?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type_guid.c_str(), -1, SQLITE_TRANSIENT));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.direct_source)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.direct_source));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.shared_source)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.shared_source));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pOut& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pOut& data) {
BEGIN_WRITER("INSERT INTO [script_pOut] VALUES (?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pOut] VALUES (?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type_guid.c_str(), -1, SQLITE_TRANSIENT));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_bLink& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_bLink& data) {
BEGIN_WRITER("INSERT INTO [script_bLink] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [bLink] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.delay)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.delay));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_obj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_obj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.input_type))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.input_type)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_obj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_obj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.output_type))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.output_type)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pLocal& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pLocal& data) {
BEGIN_WRITER("INSERT INTO [script_pLocal] VALUES (?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pLocal] VALUES (?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type_guid.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_BOOL(data.is_setting)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.is_setting));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pAttr& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pAttr& data) {
BEGIN_WRITER("INSERT INTO [script_pAttr] VALUES (?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pAttr] VALUES (?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type_guid.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.owner));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pLink& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pLink& data) {
BEGIN_WRITER("INSERT INTO [script_pLink] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pLink] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_obj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_obj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.input_type))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.input_type)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_is_bb)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_BOOL(data.input_is_bb)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.input_index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_obj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_obj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.output_type))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.output_type)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_is_bb)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_BOOL(data.output_is_bb)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.output_index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pOper& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pOper& data) {
BEGIN_WRITER("INSERT INTO [script_pOper] VALUES (?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pOper] VALUES (?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.op.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.op));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.op_guid.c_str(), -1, SQLITE_TRANSIENT));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_eLink& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_eLink& data) {
BEGIN_WRITER("INSERT INTO [script_eLink] VALUES (?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [eLink] VALUES (?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.export_obj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.export_obj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.internal_obj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.internal_obj));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.is_in)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_BOOL(data.is_in)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_pTarget& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_pTarget& data) {
BEGIN_WRITER("INSERT INTO [script_pTarget] VALUES (?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [pTarget] VALUES (?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.thisobj));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type_guid.c_str(), -1, SQLITE_TRANSIENT));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.direct_source)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.direct_source));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.shared_source)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.shared_source));
@@ -296,8 +310,8 @@ failed: throw std::runtime_error("fail to bind value for prepared statement.");
} }
void ScriptDatabase::Write(const DataTypes::Script::Table_data& data) { void ScriptDatabase::Write(const DataTypes::Script::Table_data& data) {
BEGIN_WRITER("INSERT INTO [data] VALUES (?, ?, ?);"); BEGIN_WRITER("INSERT INTO [data] VALUES (?, ?, ?);");
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.field.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.field)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.data.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_blob(WRITER_STMT, WRITER_INDEX, REVEAL_BLOB(data.data)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent));
END_WRITER; END_WRITER;
} }
@@ -310,27 +324,34 @@ failed: throw std::runtime_error("fail to bind value for prepared statement.");
AbstractDatabase(file) { AbstractDatabase(file) {
// initialize table // initialize table
BEGIN_CTOR; BEGIN_CTOR;
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [msg];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [obj];");
CTOR_SQL_EXEC("CREATE TABLE [msg] ([index] INTEGER, [name] TEXT);"); CTOR_SQL_EXEC("CREATE TABLE [msg] ([index] INTEGER, [name] TEXT);");
CTOR_SQL_EXEC("CREATE TABLE [obj] ([id] INTEGER, [name] TEXT, [classid] INTEGER, [classtype] TEXT);"); CTOR_SQL_EXEC("CREATE TABLE [obj] ([id] INTEGER, [name] TEXT, [classid] INTEGER, [classid_name] TEXT);");
END_CTOR; END_CTOR;
} }
DocumentDatabase::~DocumentDatabase() { DocumentDatabase::~DocumentDatabase() {
// do nothing // create index for quick select in following process
BEGIN_DTOR;
DTOR_SQL_EXEC("CREATE INDEX [quick_where1] ON [msg] ([index])");
DTOR_SQL_EXEC("CREATE INDEX [quick_where2] ON [obj] ([id])");
END_DTOR;
} }
void DocumentDatabase::Write(const DataTypes::Document::Table_msg& data) { void DocumentDatabase::Write(const DataTypes::Document::Table_msg& data) {
BEGIN_WRITER("INSERT INTO [msg] VALUES (?, ?);"); BEGIN_WRITER("INSERT INTO [msg] VALUES (?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
END_WRITER; END_WRITER;
} }
void DocumentDatabase::Write(const DataTypes::Document::Table_obj& data) { void DocumentDatabase::Write(const DataTypes::Document::Table_obj& data) {
BEGIN_WRITER("INSERT INTO [obj] VALUES (?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [obj] VALUES (?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.id)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.id));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.classid)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.classid));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.classtype.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.classid_name)));
END_WRITER; END_WRITER;
} }
@@ -342,87 +363,106 @@ failed: throw std::runtime_error("fail to bind value for prepared statement.");
AbstractDatabase(file) { AbstractDatabase(file) {
// initialize table // initialize table
BEGIN_CTOR; BEGIN_CTOR;
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [op];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [param];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [attr];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [plugin];");
CTOR_SQL_EXEC("DROP TABLE IF EXISTS [variable];");
CTOR_SQL_EXEC("CREATE TABLE [op] ([func_ptr] TEXT, [in1_guid] INTEGER, [in2_guid] INTEGER, [out_guid] INTEGER, [op_guid] INTEGER, [op_name] TEXT, [op_code] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [op] ([func_ptr] TEXT, [in1_guid] INTEGER, [in2_guid] INTEGER, [out_guid] INTEGER, [op_guid] INTEGER, [op_name] TEXT, [op_code] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [param] ([index] INTEGER, [guid] INTEGER, [derived_from] INTEGER, [type_name] TEXT, [default_size] INTEGER, [func_CreateDefault] TEXT, [func_Delete] TEXT, [func_SaveLoad] TEXT, [func_Check] TEXT, [func_Copy] TEXT, [func_String] TEXT, [func_UICreator] TEXT, [creator_dll_index] INTEGER, [creator_plugin_index] INTEGER, [dw_param] INTEGER, [dw_flags] INTEGER, [cid] INTEGER, [saver_manager] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [param] ([index] INTEGER, [guid] INTEGER, [derived_from] INTEGER, [name] TEXT, [default_size] INTEGER, [func_CreateDefault] TEXT, [func_Delete] TEXT, [func_SaveLoad] TEXT, [func_Check] TEXT, [func_Copy] TEXT, [func_String] TEXT, [func_UICreator] TEXT, [dll_name] TEXT, [dll_index] INTEGER, [position_in_dll] INTEGER, [flags] INTEGER, [dw_param] INTEGER, [cid] INTEGER, [saver_manager] INTEGER);");
CTOR_SQL_EXEC("CREATE TABLE [attr] ([index] INTEGER, [name] TEXT, [category_index] INTEGER, [category_name] TEXT, [flags] INTEGER, [param_index] INTEGER, [compatible_classid] INTEGER, [default_value] TEXT);"); CTOR_SQL_EXEC("CREATE TABLE [attr] ([index] INTEGER, [name] TEXT, [category_index] INTEGER, [category_name] TEXT, [flags] INTEGER, [param_index] INTEGER, [param_guid] INTEGER, [compatible_classid] INTEGER, [default_value] TEXT);");
CTOR_SQL_EXEC("CREATE TABLE [plugin] ([dll_index] INTEGER, [dll_name] TEXT, [plugin_index] INTEGER, [category] TEXT, [active] INTEGER, [guid] INTEGER, [desc] TEXT, [author] TEXT, [summary] TEXT, [version] INTEGER, [func_init] TEXT, [func_exit] TEXT);"); CTOR_SQL_EXEC("CREATE TABLE [plugin] ([category_name] TEXT, [category_index] INTEGER, [dll_name] TEXT, [dll_index] INTEGER, [position_in_dll] INTEGER, [index] INTEGER, [guid] INTEGER, [desc] TEXT, [author] TEXT, [summary] TEXT, [version] INTEGER, [type] INTEGER, [func_init] TEXT, [func_exit] TEXT, [reader_fct] TEXT, [reader_opt_count] INTEGER, [reader_flags] INTEGER, [reader_setting_param_guid] INTEGER, [reader_file_ext] TEXT, [manager_active] INTEGER, [behavior_guids] TEXT);");
CTOR_SQL_EXEC("CREATE TABLE [variable] ([name] TEXT, [description] TEXT, [flags] INTEGER, [type] INTEGER, [representation] TEXT, [data] TEXT);"); CTOR_SQL_EXEC("CREATE TABLE [variable] ([name] TEXT, [desciption] TEXT, [flags] INTEGER, [type] INTEGER, [representation] TEXT, [data] TEXT);");
END_CTOR; END_CTOR;
} }
EnvironmentDatabase::~EnvironmentDatabase() { EnvironmentDatabase::~EnvironmentDatabase() {
// do nothing // create index for quick select in following process
BEGIN_DTOR;
END_DTOR;
} }
void EnvironmentDatabase::Write(const DataTypes::Environment::Table_op& data) { void EnvironmentDatabase::Write(const DataTypes::Environment::Table_op& data) {
BEGIN_WRITER("INSERT INTO [op] VALUES (?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [op] VALUES (?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_ptr.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_ptr)));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.in1_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.in1_guid));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.in2_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.in2_guid));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.out_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.out_guid));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.op_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.op_guid));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.op_name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.op_name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.op_code)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.op_code));
END_WRITER; END_WRITER;
} }
void EnvironmentDatabase::Write(const DataTypes::Environment::Table_param& data) { void EnvironmentDatabase::Write(const DataTypes::Environment::Table_param& data) {
BEGIN_WRITER("INSERT INTO [param] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [param] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.guid));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.derived_from)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.derived_from));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.type_name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.default_size)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.default_size));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_CreateDefault.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_CreateDefault)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_Delete.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Delete)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_SaveLoad.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_SaveLoad)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_Check.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Check)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_Copy.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Copy)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_String.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_String)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_UICreator.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_UICreator)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.creator_dll_index)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.dll_name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.creator_plugin_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dll_index));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.position_in_dll));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dw_param)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dw_param));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dw_flags));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.cid)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.cid));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.saver_manager)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.saver_manager));
END_WRITER; END_WRITER;
} }
void EnvironmentDatabase::Write(const DataTypes::Environment::Table_attr& data) { void EnvironmentDatabase::Write(const DataTypes::Environment::Table_attr& data) {
BEGIN_WRITER("INSERT INTO [attr] VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [attr] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.category_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.category_index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.category_name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.category_name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.param_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.param_index));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.param_guid));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.compatible_classid)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.compatible_classid));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.default_value.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.default_value)));
END_WRITER; END_WRITER;
} }
void EnvironmentDatabase::Write(const DataTypes::Environment::Table_plugin& data) { void EnvironmentDatabase::Write(const DataTypes::Environment::Table_plugin& data) {
BEGIN_WRITER("INSERT INTO [plugin] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [plugin] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.category_name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.category_index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.dll_name)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dll_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dll_index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.dll_name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.position_in_dll));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.plugin_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.category.c_str(), -1, SQLITE_TRANSIENT));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.active));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.guid));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.desc.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.desc)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.author.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.author)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.summary.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.summary)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.version)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.version));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_init.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.func_exit.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_init)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_exit)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.reader_fct)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.reader_opt_count));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.reader_flags));
WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.reader_setting_param_guid));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.reader_file_ext)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_BOOL(data.manager_active)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.behavior_guids)));
END_WRITER; END_WRITER;
} }
void EnvironmentDatabase::Write(const DataTypes::Environment::Table_variable& data) { void EnvironmentDatabase::Write(const DataTypes::Environment::Table_variable& data) {
BEGIN_WRITER("INSERT INTO [variable] VALUES (?, ?, ?, ?, ?, ?);"); BEGIN_WRITER("INSERT INTO [variable] VALUES (?, ?, ?, ?, ?, ?);");
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.name.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.desciption.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.desciption)));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags));
WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.representation.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.representation)));
WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.data.c_str(), -1, SQLITE_TRANSIENT)); WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.data)));
END_WRITER; END_WRITER;
} }

View File

@@ -1,56 +1,16 @@
#if defined(MATERIALIZER_PLUGIN) #if defined(MATERIALIZER_PLUGIN)
#include "ExportDialog.hpp" #include "ExportDialog.hpp"
#include "PluginMain.hpp"
#include <stdexcept> #include <stdexcept>
namespace VSW::Materializer { namespace VSW::Materializer {
class ExportDialogSetting {
public:
static ExportDialogSetting& GetSingleton();
private:
static YYCC::yycc_u8string GetConfigFilePath();
ExportDialogSetting() :
m_LastFilePath(YYCC_U8("last-file-path"), YYCC_U8("")),
m_Encoding(YYCC_U8("encoding"), CP_ACP),
m_Mgr(ExportDialogSetting::GetConfigFilePath(), UINT64_C(0), {
&m_LastFilePath, &m_Encoding
}) {
m_Mgr.Load();
}
~ExportDialogSetting() {
m_Mgr.Save();
}
public:
YYCC::ConfigManager::StringSetting m_LastFilePath;
YYCC::ConfigManager::NumberSetting<UINT> m_Encoding;
YYCC::ConfigManager::CoreManager m_Mgr;
};
ExportDialogSetting& ExportDialogSetting::GetSingleton() {
static ExportDialogSetting g_Singleton;
return g_Singleton;
}
YYCC::yycc_u8string ExportDialogSetting::GetConfigFilePath() {
// get path to executable virtools
YYCC::yycc_u8string u8_virtools_path;
if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_virtools_path))
u8_virtools_path.clear();
// get its parent folder and append with cfg file name
std::filesystem::path virtools_path(YYCC::FsPathPatch::FromUTF8Path(u8_virtools_path.c_str()));
return YYCC::FsPathPatch::ToUTF8Path(virtools_path.parent_path() / YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("vsw_materializer.cfg")));
}
namespace ExportDialogHelper { namespace ExportDialogHelper {
#define RADIOBTN_GETCHECK(instance) (instance.GetCheck() == BST_CHECKED) #define RADIOBTN_GETCHECK(instance) (instance.GetCheck() == BST_CHECKED)
#define RADIOBTN_SETCHECK(instance, stmt) (instance.SetCheck((stmt) ? BST_CHECKED : BST_UNCHECKED)) #define RADIOBTN_SETCHECK(instance, stmt) (instance.SetCheck((stmt) ? BST_CHECKED : BST_UNCHECKED))
static bool ValidateCodePage(UINT code_page) {
CPINFOEXW cpinfo;
return GetCPInfoExW(code_page, 0, &cpinfo);
}
static void SetCWndText(CWnd* ctl, const YYCC::yycc_u8string_view& val) { static void SetCWndText(CWnd* ctl, const YYCC::yycc_u8string_view& val) {
ctl->SetWindowTextA(YYCC::EncodingHelper::UTF8ToChar(val, CP_ACP).c_str()); ctl->SetWindowTextA(YYCC::EncodingHelper::UTF8ToChar(val, CP_ACP).c_str());
} }
@@ -123,24 +83,24 @@ namespace VSW::Materializer {
CDialogEx::OnInitDialog(); CDialogEx::OnInitDialog();
// Read settings from config manager // Read settings from config manager
auto& config_manager = ExportDialogSetting::GetSingleton(); auto& config_manager = PluginMain::ConfigManager::GetSingleton();
auto u8_last_path = config_manager.m_LastFilePath.Get(); auto u8_last_path = config_manager.m_LastFilePath.Get();
if (!u8_last_path.empty()) { if (!u8_last_path.empty()) {
auto last_path = YYCC::FsPathPatch::FromUTF8Path(u8_last_path.c_str()); auto last_path = YYCC::StdPatch::ToStdPath(u8_last_path);
switch (m_InitialDatabaseType) { switch (m_InitialDatabaseType) {
case InitialDatabaseType::Script: case InitialDatabaseType::Script:
last_path.replace_filename(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("script.db"))); last_path.replace_filename(YYCC::StdPatch::ToStdPath(YYCC_U8("script.db")));
break; break;
case InitialDatabaseType::Document: case InitialDatabaseType::Document:
last_path.replace_filename(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("doc.db"))); last_path.replace_filename(YYCC::StdPatch::ToStdPath(YYCC_U8("doc.db")));
break; break;
case InitialDatabaseType::Environment: case InitialDatabaseType::Environment:
last_path.replace_filename(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("env.db"))); last_path.replace_filename(YYCC::StdPatch::ToStdPath(YYCC_U8("env.db")));
break; break;
default: default:
throw std::runtime_error("invalid initial database type"); throw std::runtime_error("invalid initial database type");
} }
u8_last_path = YYCC::FsPathPatch::ToUTF8Path(last_path); u8_last_path = YYCC::StdPatch::ToUTF8Path(last_path);
} }
PushDatabaseFile(u8_last_path); PushDatabaseFile(u8_last_path);
PushEncoding(config_manager.m_Encoding.Get()); PushEncoding(config_manager.m_Encoding.Get());
@@ -157,13 +117,13 @@ namespace VSW::Materializer {
MessageBoxW(m_hWnd, L"Exported database file should not be empty!", L"Setting Error", MB_OK + MB_ICONERROR); MessageBoxW(m_hWnd, L"Exported database file should not be empty!", L"Setting Error", MB_OK + MB_ICONERROR);
return; return;
} }
if (!ExportDialogHelper::ValidateCodePage(m_EncodingResult)) { if (!YYCC::WinFctHelper::IsValidCodePage(m_EncodingResult)) {
MessageBoxW(m_hWnd, L"Invalid encoding!", L"Setting Error", MB_OK + MB_ICONERROR); MessageBoxW(m_hWnd, L"Invalid encoding!", L"Setting Error", MB_OK + MB_ICONERROR);
return; return;
} }
// check done. sync settings to config manager // check done. sync settings to config manager
auto& config_manager = ExportDialogSetting::GetSingleton(); auto& config_manager = PluginMain::ConfigManager::GetSingleton();
config_manager.m_LastFilePath.Set(m_DatabaseFileResult); config_manager.m_LastFilePath.Set(m_DatabaseFileResult);
config_manager.m_Encoding.Set(m_EncodingResult); config_manager.m_Encoding.Set(m_EncodingResult);

View File

@@ -1,12 +1,79 @@
#include "ExportCore.hpp" #include "ExportCore.hpp"
#include "Database.hpp"
#include "DataTypes.hpp"
#include "Utilities.hpp"
#include <set>
namespace VSW::Materializer::ExportDocument { namespace VSW::Materializer::ExportDocument {
struct ExportContext {
ExportContext(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) :
db(db_path), cache(), reporter(ctx), cp(code_page) {}
Database::DocumentDatabase db;
DataTypes::Document::DataCache cache;
Utilities::EnhancedReporter reporter;
UINT cp;
};
static void IterateMessage(ExportContext& expctx, CKMessageManager* msg_mgr) {
int count = msg_mgr->GetMessageTypeCount();
for (int i = 0; i < count; i++) {
expctx.cache.msg.index = i;
CP_CKSTR(expctx.cache.msg.name, msg_mgr->GetMessageTypeName(i));
expctx.db.Write(expctx.cache.msg);
}
}
/// @brief The common parents list which exported objects belong to.
static const std::vector<CK_CLASSID> g_CommonClassIds {
// Export CKSceneObject will export almost objects in scene
// That's enough
CKCID_SCENEOBJECT
};
static void IterateObject(ExportContext& expctx, CKContext* ctx) {
// Get CKParameterManager to resolve Class ID name
CKParameterManager* param_mgr = ctx->GetParameterManager();
// prepare variables
CK_CLASSID classid_cache;
for (const auto& cid : g_CommonClassIds) {
XObjectPointerArray obj_array = ctx->GetObjectListByType(cid, TRUE);
int obj_count = obj_array.Size();
for (int i = 0; i < obj_count; i++) {
CKSceneObject* scene_obj = static_cast<CKSceneObject*>(obj_array.GetObjectA(i));
// basic infos
expctx.cache.obj.id = scene_obj->GetID();
CP_CKSTR(expctx.cache.obj.name, scene_obj->GetName());
classid_cache = scene_obj->GetClassID();
expctx.cache.obj.classid = classid_cache;
// resolve class id name
CP_CKSTR(expctx.cache.obj.classid_name, param_mgr->ParameterGuidToName(param_mgr->ClassIDToGuid(classid_cache)));
expctx.db.Write(expctx.cache.obj);
}
}
}
void Export(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) { void Export(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) {
// create export context
ExportContext expctx(ctx, db_path, code_page);
if (!expctx.db.IsValid()) {
expctx.reporter.Err(YYCC_U8("Fail to open database. Export process aborted."));
return;
}
// export document
IterateMessage(expctx, ctx->GetMessageManager());
IterateObject(expctx, ctx);
// report success
expctx.reporter.EnableBeep();
expctx.reporter.Info(YYCC_U8("Exporting document database done."));
expctx.reporter.DisableBeep();
} }
} }

View File

@@ -7,11 +7,17 @@
namespace VSW::Materializer::ExportEnvironment { namespace VSW::Materializer::ExportEnvironment {
struct ExportContext { struct ExportContext {
ExportContext(CKContext* ctx, const YYCC::yycc_u8string_view& db_path) : ExportContext(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) :
db(db_path), cache(), reporter(ctx) {} db(db_path), cache(), reporter(ctx), cp(code_page), ctx(ctx), plugin_mgr(CKGetPluginManager()) {}
Database::EnvironmentDatabase db; Database::EnvironmentDatabase db;
DataTypes::Environment::DataCache cache; DataTypes::Environment::DataCache cache;
Utilities::EnhancedReporter reporter; Utilities::EnhancedReporter reporter;
UINT cp;
/// @brief Virtools context.
CKContext* ctx;
/// @brief Virtools Plugin Manager
CKPluginManager* plugin_mgr;
}; };
static void IterateParameterOperation(ExportContext& expctx, CKParameterManager* param_mgr) { static void IterateParameterOperation(ExportContext& expctx, CKParameterManager* param_mgr) {
@@ -26,8 +32,8 @@ namespace VSW::Materializer::ExportEnvironment {
// fill the shared data part. // fill the shared data part.
expctx.cache.op.op_code = i; expctx.cache.op.op_code = i;
guid = param_mgr->OperationCodeToGuid(i); guid = param_mgr->OperationCodeToGuid(i);
Utilities::CopyGuid(expctx.cache.op.op_guid, guid); CP_GUID(expctx.cache.op.op_guid, guid);
expctx.cache.op.op_name = param_mgr->OperationCodeToName(i); CP_CKSTR(expctx.cache.op.op_name, param_mgr->OperationCodeToName(i));
// get all sub-operation of this parameter operation. // get all sub-operation of this parameter operation.
// each sub-operation can have different in out parameter type // each sub-operation can have different in out parameter type
@@ -36,10 +42,10 @@ namespace VSW::Materializer::ExportEnvironment {
op_list.resize(static_cast<size_t>(op_list_count)); op_list.resize(static_cast<size_t>(op_list_count));
param_mgr->GetAvailableOperationsDesc(guid, nullptr, nullptr, nullptr, op_list.data()); param_mgr->GetAvailableOperationsDesc(guid, nullptr, nullptr, nullptr, op_list.data());
for (const auto& op : op_list) { for (const auto& op : op_list) {
Utilities::CopyGuid(expctx.cache.op.in1_guid, op.P1Guid); CP_GUID(expctx.cache.op.in1_guid, op.P1Guid);
Utilities::CopyGuid(expctx.cache.op.in2_guid, op.P2Guid); CP_GUID(expctx.cache.op.in2_guid, op.P2Guid);
Utilities::CopyGuid(expctx.cache.op.out_guid, op.ResGuid); CP_GUID(expctx.cache.op.out_guid, op.ResGuid);
expctx.cache.op.func_ptr = Utilities::RelativeAddress(op.Fct); CP_ADDR(expctx.cache.op.func_ptr, op.Fct);
expctx.db.Write(expctx.cache.op); expctx.db.Write(expctx.cache.op);
} }
@@ -55,30 +61,40 @@ namespace VSW::Materializer::ExportEnvironment {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
desc = param_mgr->GetParameterTypeDescription(i); desc = param_mgr->GetParameterTypeDescription(i);
// Parameter basic infos
expctx.cache.param.index = desc->Index; expctx.cache.param.index = desc->Index;
Utilities::CopyGuid(expctx.cache.param.guid, desc->Guid); CP_GUID(expctx.cache.param.guid, desc->Guid);
Utilities::CopyGuid(expctx.cache.param.derived_from, desc->DerivedFrom); CP_GUID(expctx.cache.param.derived_from, desc->DerivedFrom);
expctx.cache.param.type_name = desc->TypeName.CStr(); CP_CKSTR(expctx.cache.param.name, desc->TypeName.CStr());
expctx.cache.param.default_size = desc->DefaultSize; expctx.cache.param.default_size = desc->DefaultSize;
expctx.cache.param.func_CreateDefault = Utilities::RelativeAddress(desc->CreateDefaultFunction); CP_ADDR(expctx.cache.param.func_CreateDefault, desc->CreateDefaultFunction);
expctx.cache.param.func_Delete = Utilities::RelativeAddress(desc->DeleteFunction); CP_ADDR(expctx.cache.param.func_Delete, desc->DeleteFunction);
expctx.cache.param.func_SaveLoad = Utilities::RelativeAddress(desc->SaveLoadFunction); CP_ADDR(expctx.cache.param.func_SaveLoad, desc->SaveLoadFunction);
expctx.cache.param.func_Check = Utilities::RelativeAddress(desc->CheckFunction); CP_ADDR(expctx.cache.param.func_Check, desc->CheckFunction);
expctx.cache.param.func_Copy = Utilities::RelativeAddress(desc->CopyFunction); CP_ADDR(expctx.cache.param.func_Copy, desc->CopyFunction);
expctx.cache.param.func_String = Utilities::RelativeAddress(desc->StringFunction); CP_ADDR(expctx.cache.param.func_String, desc->StringFunction);
expctx.cache.param.func_UICreator = Utilities::RelativeAddress(desc->UICreatorFunction); CP_ADDR(expctx.cache.param.func_UICreator, desc->UICreatorFunction);
// Creator dll infos
// This is different with plugin.
// Because some parameters are provided by Virtools self.
CKPluginEntry* plugin_entry = desc->CreatorDll; CKPluginEntry* plugin_entry = desc->CreatorDll;
if (plugin_entry != nullptr) { if (plugin_entry != nullptr) {
expctx.cache.param.creator_dll_index = plugin_entry->m_PluginDllIndex; CKPluginDll* plugin_dll = expctx.plugin_mgr->GetPluginDllInfo(plugin_entry->m_PluginDllIndex);
expctx.cache.param.creator_plugin_index = plugin_entry->m_PositionInDll; CP_CKSTR(expctx.cache.param.dll_name, plugin_dll->m_DllFileName.CStr());
expctx.cache.param.dll_index = plugin_entry->m_PluginDllIndex;
expctx.cache.param.position_in_dll = plugin_entry->m_PositionInDll;
} else { } else {
expctx.cache.param.creator_dll_index = -1; expctx.cache.param.dll_name = YYCC_U8("<embedded>");
expctx.cache.param.creator_plugin_index = -1; expctx.cache.param.dll_index = -1;
expctx.cache.param.position_in_dll = -1;
} }
// Misc
expctx.cache.param.flags = desc->dwFlags;
expctx.cache.param.dw_param = desc->dwParam; expctx.cache.param.dw_param = desc->dwParam;
expctx.cache.param.dw_flags = desc->dwFlags;
expctx.cache.param.cid = desc->Cid; expctx.cache.param.cid = desc->Cid;
Utilities::CopyGuid(expctx.cache.param.saver_manager, desc->Saver_Manager); CP_GUID(expctx.cache.param.saver_manager, desc->Saver_Manager);
expctx.db.Write(expctx.cache.param); expctx.db.Write(expctx.cache.param);
} }
@@ -89,13 +105,14 @@ namespace VSW::Materializer::ExportEnvironment {
int count = attr_mgr->GetAttributeCount(); int count = attr_mgr->GetAttributeCount();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
expctx.cache.attr.index = i; expctx.cache.attr.index = i;
expctx.cache.attr.name = attr_mgr->GetAttributeNameByType(i); CP_CKSTR(expctx.cache.attr.name, attr_mgr->GetAttributeNameByType(i));
expctx.cache.attr.category_index = attr_mgr->GetAttributeCategoryIndex(i); expctx.cache.attr.category_index = attr_mgr->GetAttributeCategoryIndex(i);
Utilities::CopyCKString(expctx.cache.attr.category_name, attr_mgr->GetAttributeCategory(i)); CP_CKSTR(expctx.cache.attr.category_name, attr_mgr->GetAttributeCategory(i));
expctx.cache.attr.flags = attr_mgr->GetAttributeFlags(i); expctx.cache.attr.flags = attr_mgr->GetAttributeFlags(i);
expctx.cache.attr.param_index = attr_mgr->GetAttributeParameterType(i); expctx.cache.attr.param_index = attr_mgr->GetAttributeParameterType(i);
CP_GUID(expctx.cache.attr.param_guid, attr_mgr->GetAttributeParameterGUID(i));
expctx.cache.attr.compatible_classid = attr_mgr->GetAttributeCompatibleClassId(i); expctx.cache.attr.compatible_classid = attr_mgr->GetAttributeCompatibleClassId(i);
Utilities::CopyCKString(expctx.cache.attr.default_value, attr_mgr->GetAttributeDefaultValue(i)); CP_CKSTR(expctx.cache.attr.default_value, attr_mgr->GetAttributeDefaultValue(i));
expctx.db.Write(expctx.cache.attr); expctx.db.Write(expctx.cache.attr);
} }
@@ -108,8 +125,9 @@ namespace VSW::Materializer::ExportEnvironment {
// get category count and iterate them // get category count and iterate them
int category_count = plugin_mgr->GetCategoryCount(); int category_count = plugin_mgr->GetCategoryCount();
for (int i = 0; i < category_count; ++i) { for (int i = 0; i < category_count; ++i) {
// get category name and set it // category name and its index
expctx.cache.plugin.category = plugin_mgr->GetCategoryName(i); CP_CKSTR(expctx.cache.plugin.category_name, plugin_mgr->GetCategoryName(i));
expctx.cache.plugin.category_index = i;
// iterate plugin within this category // iterate plugin within this category
int plugin_count = plugin_mgr->GetPluginCount(i); int plugin_count = plugin_mgr->GetPluginCount(i);
@@ -118,25 +136,32 @@ namespace VSW::Materializer::ExportEnvironment {
CKPluginInfo* plugin_info = &(plugin_entry->m_PluginInfo); CKPluginInfo* plugin_info = &(plugin_entry->m_PluginInfo);
CKPluginDll* plugin_dll = plugin_mgr->GetPluginDllInfo(plugin_entry->m_PluginDllIndex); CKPluginDll* plugin_dll = plugin_mgr->GetPluginDllInfo(plugin_entry->m_PluginDllIndex);
// dll infomation (name + position in dll) // dll infomation (name + index + position in dll)
expctx.cache.plugin.dll_name = plugin_dll->m_DllFileName.CStr(); CP_CKSTR(expctx.cache.plugin.dll_name, plugin_dll->m_DllFileName.CStr());
expctx.cache.plugin.dll_index = plugin_entry->m_PluginDllIndex;
expctx.cache.plugin.position_in_dll = plugin_entry->m_PositionInDll; expctx.cache.plugin.position_in_dll = plugin_entry->m_PositionInDll;
// plugin info // plugin info
Utilities::CopyGuid(expctx.cache.plugin.guid, plugin_info->m_GUID); expctx.cache.plugin.index = j;
expctx.cache.plugin.desc = plugin_info->m_Description.CStr(); CP_GUID(expctx.cache.plugin.guid, plugin_info->m_GUID);
expctx.cache.plugin.author = plugin_info->m_Author.CStr(); CP_CKSTR(expctx.cache.plugin.desc, plugin_info->m_Description.CStr());
expctx.cache.plugin.summary = plugin_info->m_Summary.CStr(); CP_CKSTR(expctx.cache.plugin.author, plugin_info->m_Author.CStr());
CP_CKSTR(expctx.cache.plugin.summary, plugin_info->m_Summary.CStr());
expctx.cache.plugin.version = plugin_info->m_Version; expctx.cache.plugin.version = plugin_info->m_Version;
plugin_type = plugin_info->m_Type; plugin_type = plugin_info->m_Type;
expctx.cache.plugin.type = plugin_type; expctx.cache.plugin.type = plugin_type;
expctx.cache.plugin.func_init = Utilities::RelativeAddress(plugin_info->m_InitInstanceFct); CP_ADDR(expctx.cache.plugin.func_init, plugin_info->m_InitInstanceFct);
expctx.cache.plugin.func_exit = Utilities::RelativeAddress(plugin_info->m_ExitInstanceFct); CP_ADDR(expctx.cache.plugin.func_exit, plugin_info->m_ExitInstanceFct);
// extra fields according to plugin type // extra fields according to plugin type
// first reset these specific fields // first reset these specific fields
expctx.cache.plugin.reader_fct.clear(); expctx.cache.plugin.reader_fct.clear();
expctx.cache.plugin.reader_opt_count = 0;
expctx.cache.plugin.reader_flags = static_cast<CK_DATAREADER_FLAGS>(0);
expctx.cache.plugin.reader_setting_param_guid = INT64_C(0);
expctx.cache.plugin.reader_file_ext.clear();
expctx.cache.plugin.behavior_guids.clear();
expctx.cache.plugin.manager_active = false;
// then try to fetch these specific fields // then try to fetch these specific fields
switch (plugin_type) { switch (plugin_type) {
case CKPLUGIN_BITMAP_READER: case CKPLUGIN_BITMAP_READER:
@@ -145,25 +170,23 @@ namespace VSW::Materializer::ExportEnvironment {
case CKPLUGIN_MOVIE_READER: case CKPLUGIN_MOVIE_READER:
{ {
// Reader specific // Reader specific
expctx.cache.plugin.reader_fct = Utilities::RelativeAddress(plugin_entry->m_ReadersInfo->m_GetReaderFct); CP_ADDR(expctx.cache.plugin.reader_fct, plugin_entry->m_ReadersInfo->m_GetReaderFct);
expctx.cache.plugin.reader_opt_count = plugin_entry->m_ReadersInfo->m_OptionCount; expctx.cache.plugin.reader_opt_count = plugin_entry->m_ReadersInfo->m_OptionCount;
expctx.cache.plugin.reader_flags = plugin_entry->m_ReadersInfo->m_ReaderFlags; expctx.cache.plugin.reader_flags = plugin_entry->m_ReadersInfo->m_ReaderFlags;
Utilities::CopyGuid(expctx.cache.plugin.reader_setting_param_guid, plugin_entry->m_ReadersInfo->m_SettingsParameterGuid); CP_GUID(expctx.cache.plugin.reader_setting_param_guid, plugin_entry->m_ReadersInfo->m_SettingsParameterGuid);
expctx.cache.plugin.reader_file_ext = static_cast<const char*>(plugin_info->m_Extension); CP_CKSTR(expctx.cache.plugin.reader_file_ext, static_cast<const char*>(plugin_info->m_Extension), YYCC_U8(""));
break; break;
} }
case CKPLUGIN_BEHAVIOR_DLL: case CKPLUGIN_BEHAVIOR_DLL:
{ {
// Behavior specific // Behavior specific
std::vector<YYCC::yycc_u8string> guids; std::vector<YYCC::yycc_u8string> guids;
YYCC::yycc_u8string guid_cache;
for (int i = 0; i < plugin_entry->m_BehaviorsInfo->m_BehaviorsGUID.Size(); ++i) { for (int i = 0; i < plugin_entry->m_BehaviorsInfo->m_BehaviorsGUID.Size(); ++i) {
int64_t guid_cache; CP_STR_GUID(guid_cache, plugin_entry->m_BehaviorsInfo->m_BehaviorsGUID[i]);
Utilities::CopyGuid(guid_cache, plugin_entry->m_BehaviorsInfo->m_BehaviorsGUID[i]); guids.emplace_back(guid_cache);
guids.emplace_back(YYCC::ParserHelper::ToString(guid_cache));
} }
expctx.cache.plugin.behavior_guids = YYCC::EncodingHelper::ToOrdinaryView( expctx.cache.plugin.behavior_guids = YYCC::StringHelper::Join(guids, YYCC_U8(", "));
YYCC::StringHelper::Join(guids, YYCC_U8(", "))
);
break; break;
} }
case CKPLUGIN_MANAGER_DLL: case CKPLUGIN_MANAGER_DLL:
@@ -176,7 +199,6 @@ namespace VSW::Materializer::ExportEnvironment {
} }
} }
expctx.db.Write(expctx.cache.plugin); expctx.db.Write(expctx.cache.plugin);
} }
} }
@@ -198,9 +220,9 @@ namespace VSW::Materializer::ExportEnvironment {
varobj = it.GetVariable(); varobj = it.GetVariable();
// variable name // variable name
var_name = it.GetName(); var_name = it.GetName();
expctx.cache.variable.name = var_name; CP_CKSTR(expctx.cache.variable.name, var_name);
// variable description // variable description
Utilities::CopyCKString(expctx.cache.variable.desciption, varobj->GetDescription()); CP_CKSTR(expctx.cache.variable.desciption, varobj->GetDescription());
// variable flags // variable flags
expctx.cache.variable.flags = varobj->GetFlags(); expctx.cache.variable.flags = varobj->GetFlags();
// variable type // variable type
@@ -211,21 +233,21 @@ namespace VSW::Materializer::ExportEnvironment {
// Because it is not a name. // Because it is not a name.
// So we should record it as empty string if it is nullptr, instead of default <unamed> // So we should record it as empty string if it is nullptr, instead of default <unamed>
var_representation = varobj->GetRepresentation(); var_representation = varobj->GetRepresentation();
Utilities::CopyCKString(expctx.cache.variable.representation, var_representation, ""); CP_CKSTR(expctx.cache.variable.representation, var_representation, YYCC_U8(""));
// We output variable stored value in different way // We output variable stored value in different way
// according to its type. // according to its type.
switch (var_type) { switch (var_type) {
case CKVariableManager::Variable::Type::INT: case CKVariableManager::Variable::Type::INT:
var_mgr->GetValue(var_name, &int_cache); var_mgr->GetValue(var_name, &int_cache);
expctx.cache.variable.data = YYCC::EncodingHelper::ToOrdinaryView(YYCC::ParserHelper::ToString(int_cache)); expctx.cache.variable.data = YYCC::ParserHelper::ToString(int_cache);
break; break;
case CKVariableManager::Variable::Type::FLOAT: case CKVariableManager::Variable::Type::FLOAT:
var_mgr->GetValue(var_name, &float_cache); var_mgr->GetValue(var_name, &float_cache);
expctx.cache.variable.data = YYCC::EncodingHelper::ToOrdinaryView(YYCC::ParserHelper::ToString(float_cache)); expctx.cache.variable.data = YYCC::ParserHelper::ToString(float_cache);
break; break;
case CKVariableManager::Variable::Type::STRING: case CKVariableManager::Variable::Type::STRING:
var_mgr->GetValue(var_name, xstring_cache); var_mgr->GetValue(var_name, xstring_cache);
expctx.cache.variable.data = xstring_cache.CStr(); CP_CKSTR(expctx.cache.variable.data, xstring_cache.CStr());
break; break;
default: default:
throw std::runtime_error("invalid variable type!"); throw std::runtime_error("invalid variable type!");
@@ -238,7 +260,11 @@ namespace VSW::Materializer::ExportEnvironment {
void Export(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) { void Export(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) {
// create database and data cache in context // create database and data cache in context
ExportContext expctx(ctx, db_path); ExportContext expctx(ctx, db_path, code_page);
if (!expctx.db.IsValid()) {
expctx.reporter.Err(YYCC_U8("Fail to open database. Export process aborted."));
return;
}
// export environment one by one // export environment one by one
IterateParameterOperation(expctx, ctx->GetParameterManager()); IterateParameterOperation(expctx, ctx->GetParameterManager());
@@ -248,6 +274,11 @@ namespace VSW::Materializer::ExportEnvironment {
#if !defined(VIRTOOLS_21) #if !defined(VIRTOOLS_21)
IterateVariable(expctx, ctx->GetVariableManager()); IterateVariable(expctx, ctx->GetVariableManager());
#endif #endif
// report success
expctx.reporter.EnableBeep();
expctx.reporter.Info(YYCC_U8("Exporting environment database done."));
expctx.reporter.DisableBeep();
} }
} }

View File

@@ -1,12 +1,648 @@
#include "ExportCore.hpp" #include "ExportCore.hpp"
#include "Database.hpp"
#include "DataTypes.hpp"
#include "Utilities.hpp"
#include <numeric>
#include <type_traits>
/**
* @brief The namespace contain functions exporting scripts
* @details
* \c Generate mean that this function will analyse something to generate some objects which are not existed in original Virtools document.
* \c Proc meath that this function only just export something which is already existed in original Virtools document, or with slight modifications.
*/
namespace VSW::Materializer::ExportScript { namespace VSW::Materializer::ExportScript {
struct ExportContext {
ExportContext(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) :
db(db_path), cache(), reporter(ctx), cp(code_page), attr_set(), ctx(ctx), param_mgr(ctx->GetParameterManager()) {}
Database::ScriptDatabase db;
DataTypes::Script::DataCache cache;
Utilities::EnhancedReporter reporter;
UINT cp;
/// @brief Variable for removing duplicated exported attributes.
std::set<CK_ID> attr_set;
/// @brief Virtools context.
CKContext* ctx;
/// @brief Virtools Parameter Manager
CKParameterManager* param_mgr;
};
#pragma region Assist Functions
static void DataDictWriter(ExportContext& expctx, const YYCC::yycc_u8string_view& field, const void* data, size_t data_length, CK_ID parent) {
// check given data length
using db_size_t = decltype(expctx.cache.data.data.length);
if (data_length > static_cast<size_t>(std::numeric_limits<db_size_t>::max()))
throw std::runtime_error("Too long data length when exporting to data dictionary.");
// if length is zero, reset ptr to nullptr
if (data_length == 0u) data = nullptr;
// write data
expctx.cache.data.field = field;
expctx.cache.data.data.ptr = data;
expctx.cache.data.data.length = static_cast<db_size_t>(data_length);
expctx.cache.data.parent = parent;
expctx.db.Write(expctx.cache.data);
}
static void DataDictWriter(ExportContext& expctx, const YYCC::yycc_u8string_view& field, const YYCC::yycc_u8string& data, CK_ID parent) {
DataDictWriter(expctx, field, data.c_str(), data.length(), parent);
}
template<class _Ty, std::enable_if_t<!std::is_same_v<_Ty, YYCC::yycc_u8string>, int> = 0>
static void DataDictWriter(ExportContext& expctx, const YYCC::yycc_u8string_view& field, const _Ty& data, CK_ID parent) {
DataDictWriter(expctx, field, &data, sizeof(_Ty), parent);
}
#define REC_RAW_DATA(field, data, len) DataDictWriter(expctx, YYCC_U8(field), data, len, parent)
#define REC_DATA(field, data) DataDictWriter(expctx, YYCC_U8(field), data, parent)
void DigParameterData(ExportContext& expctx, CKParameter* p, CK_ID parent) {
// According to our algorithm, CKParameter passed in this function can not be duplicated.
// So we don't need check it anymore.
// Get CKGUID and Parameter Type first
CKGUID t = p->GetGUID();
CKParameterType pt = p->GetType();
// Record GUID
int64_t exported_t;
CP_GUID(exported_t, t);
REC_DATA("dumper.guid", exported_t);
// Record Parameter Type name
YYCC::yycc_u8string exported_pt;
CP_CKSTR(exported_pt, expctx.param_mgr->ParameterTypeToName(pt));
REC_DATA("dumper.type-name", exported_pt);
// Detect value object scenario (associated with an existing CKObject)
if (p->GetParameterClassID() && p->GetValueObject(false)) {
// Record CK_ID of associated object
CKObject* assoc_obj = p->GetValueObject(false);
REC_DATA("dumper.assoc-ckobj", assoc_obj->GetID());
return;
}
// Nothing
if (t == CKPGUID_NONE) return;
// Float value
if (t == CKPGUID_FLOAT || t == CKPGUID_ANGLE || t == CKPGUID_PERCENTAGE || t == CKPGUID_TIME
#if defined(VIRTOOLS_50) || defined(VIRTOOLS_40) || defined(VIRTOOLS_35)
|| t == CKPGUID_FLOATSLIDER
#endif
) {
REC_DATA("dumper.float", *static_cast<float*>(p->GetReadDataPtr(false)));
return;
}
// Integral value
if (t == CKPGUID_INT || t == CKPGUID_KEY || t == CKPGUID_BOOL || t == CKPGUID_ID || t == CKPGUID_POINTER
|| t == CKPGUID_MESSAGE || t == CKPGUID_ATTRIBUTE || t == CKPGUID_BLENDMODE || t == CKPGUID_FILTERMODE
|| t == CKPGUID_BLENDFACTOR || t == CKPGUID_FILLMODE || t == CKPGUID_LITMODE || t == CKPGUID_SHADEMODE
|| t == CKPGUID_ADDRESSMODE || t == CKPGUID_WRAPMODE || t == CKPGUID_3DSPRITEMODE || t == CKPGUID_FOGMODE
|| t == CKPGUID_LIGHTTYPE || t == CKPGUID_SPRITEALIGN || t == CKPGUID_DIRECTION || t == CKPGUID_LAYERTYPE
|| t == CKPGUID_COMPOPERATOR || t == CKPGUID_BINARYOPERATOR || t == CKPGUID_SETOPERATOR
|| t == CKPGUID_OBSTACLEPRECISION || t == CKPGUID_OBSTACLEPRECISIONBEH) {
REC_DATA("dumper.int", *static_cast<int*>(p->GetReadDataPtr(false)));
return;
}
// Vector value
if (t == CKPGUID_VECTOR) {
REC_DATA("dumper.vector", *static_cast<VxVector*>(p->GetReadDataPtr(false)));
return;
}
if (t == CKPGUID_2DVECTOR) {
REC_DATA("dumper.2dvector", *static_cast<Vx2DVector*>(p->GetReadDataPtr(false)));
return;
}
if (t == CKPGUID_MATRIX) {
REC_DATA("dumper.matrix", *static_cast<VxMatrix*>(p->GetReadDataPtr(false)));
return;
}
if (t == CKPGUID_COLOR) {
REC_DATA("dumper.color", *static_cast<VxColor*>(p->GetReadDataPtr(false)));
return;
}
// 2D Curve value
if (t == CKPGUID_2DCURVE) {
// Get instance
CK2dCurve* c = static_cast<CK2dCurve*>(p->GetReadDataPtr(false));
// We build our unique binary 2d curve data.
Utilities::Curve2DBuilder builder(c);
REC_RAW_DATA("dumper.2d-curve", builder.GetDataPtr(), builder.GetDataLength());
return;
}
// String value
if (t == CKPGUID_STRING) {
// Virtools internal data may not have null terminal,
// so we use need copy it into container first.
std::string native_string(
static_cast<char*>(p->GetReadDataPtr(false)),
static_cast<size_t>(p->GetDataSize())
);
// Then do encoding convertion
YYCC::yycc_u8string utf8_string;
if (!YYCC::EncodingHelper::CharToUTF8(native_string, utf8_string, expctx.cp)) {
// If failed, report error
expctx.reporter.Err(YYCC_U8("Fail to convert string encoding for data of CKParameter. Some value may be empty!"));
// reset to blank string
utf8_string.clear();
}
REC_DATA("dumper.string", utf8_string);
return;
}
// If it gets here, we have no idea what it really is. so simply dump it.
// Buffer-like
if (t == CKPGUID_VOIDBUF
#if defined(VIRTOOLS_50) || defined(VIRTOOLS_40) || defined(VIRTOOLS_35)
|| t == CKPGUID_SHADER || t == CKPGUID_TECHNIQUE || t == CKPGUID_PASS
#endif
|| true // All unknown type goes here.
) {
// Raw data is similar with string,
// but we don't need do encoding convertion.
const void* data_ptr = p->GetReadDataPtr(false);
size_t data_len = static_cast<size_t>(p->GetDataSize());
REC_RAW_DATA("dumper.raw", data_ptr, data_len);
return;
}
}
#pragma endregion
/**
* @brief Process Attribute Parameter
* @details
* pAttr do not have any explicit interface to get them, so they only can be find via pLink analyse.
* 2 pLink analyse funcstions will call this function to record each pAttr.
* Due to this mechanism, it might cause a duplication issues,
* so we need check possible duplication in here.
* @param[in] expctx Reference to export context.
* @param[in] ckobj Pointer to CKParameter (actually is attribute parameter) for processing.
*/
static void Proc_pAttr(ExportContext& expctx, CKParameter* ckobj) {
// Check duplication.
// We should not export duplicated pAttr
auto insert_result = expctx.attr_set.emplace(ckobj->GetID());
if (!insert_result.second) return;
// Write self first
expctx.cache.pAttr.thisobj = ckobj->GetID();
CP_CKSTR(expctx.cache.pAttr.name, ckobj->GetName());
CP_GUID(expctx.cache.pAttr.type, ckobj->GetGUID());
expctx.cache.pAttr.owner = ckobj->GetOwner()->GetID();
expctx.db.Write(expctx.cache.pAttr);
}
/**
* @brief Generate pLink and eLink from pIn
* @param[in] expctx Reference to export context.
* @param[in] analysed Pointer to CKParameterIn for analysing.
* @param[in] parent
* @param[in] grandparent
* @param[in] pin_index
* @param[in] executed_from_bb True if given CKParameterIn is belong to a CKBehavior, otherwise false (CKParamterOperation).
* @param[in] is_target True if this function is called from pTarget processor.
*/
static void Generate_pLink(ExportContext& expctx, CKParameterIn* analysed, CK_ID parent, CK_ID grandparent, int pin_index, bool executed_from_bb, bool is_target) {
// First, we analyse eLink.
// Check whether this is export parameter and write to database.
// If the behavior graph where this pIn's parent locate, also include this pIn,
// we can simply assume there is an eLink between them
CKBehavior* ckobj_grandparent = static_cast<CKBehavior*>(expctx.ctx->GetObjectA(grandparent));
if (ckobj_grandparent->GetInputParameterPosition(analysed) != -1) {
expctx.cache.eLink.export_obj = analysed->GetID();
expctx.cache.eLink.internal_obj = parent;
expctx.cache.eLink.is_in = true;
expctx.cache.eLink.index = pin_index;
expctx.cache.eLink.parent = grandparent;
expctx.db.Write(expctx.cache.eLink);
// if a eLink has been detected successfully, we returned immediately
// and do not analyse any pLink any more.
return;
}
// start to analyse pLink
// first, analyse \c direct_source
CKParameter* direct_source = analysed->GetDirectSource();
if (direct_source != nullptr) {
expctx.cache.pLink.input = direct_source->GetID();
// For almost pIn, they are connected to a pLocal, so we use \c if statement to test it first
CK_CLASSID direct_source_cid = direct_source->GetClassID();
if (direct_source_cid == CKCID_PARAMETERLOCAL || direct_source_cid == CKCID_PARAMETERVARIABLE) {
// pLocal
expctx.cache.pLink.input_obj = direct_source->GetID(); // the owner of pLocal is itself.
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PLOCAL;
expctx.cache.pLink.input_is_bb = false;
expctx.cache.pLink.input_index = Utilities::INVALID_INDEX;
} else {
// According to Virtools SDK document, there are 4 possible value gotten by us:
// bb pOut / pOper pOut / CKObject Attribute / CKDataArray.
// However, the last 2 returned values have NOT been tested perfectly.
CKObject* ds_owner = direct_source->GetOwner();
switch (ds_owner->GetClassID()) {
case CKCID_BEHAVIOR:
{;
CKBehavior* ds_owner_cast = static_cast<CKBehavior*>(ds_owner);
CKParameterOut* direct_source_cast = static_cast<CKParameterOut*>(direct_source);
expctx.cache.pLink.input_obj = ds_owner->GetID();
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::POUT;
expctx.cache.pLink.input_is_bb = true;
expctx.cache.pLink.input_index = ds_owner_cast->GetOutputParameterPosition(direct_source_cast);
break;
}
case CKCID_PARAMETEROPERATION:
{
expctx.cache.pLink.input_obj = ds_owner->GetID();
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::POUT;
expctx.cache.pLink.input_is_bb = false;
expctx.cache.pLink.input_index = 0; // pOper only have 1 pOut
break;
}
case CKCID_DATAARRAY:
{
// CKDataArray, see as virtual bb pLocal shortcut
expctx.cache.pLink.input_obj = direct_source->GetID();
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PATTR;
expctx.cache.pLink.input_is_bb = false; // discard
expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard
Proc_pAttr(expctx, direct_source);
break;
}
default:
{
// CKObject, because CKDataArray also a CKObject, so we test it first.
// see as virtual bb pLocal shortcut
expctx.cache.pLink.input_obj = direct_source->GetID();
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PATTR;
expctx.cache.pLink.input_is_bb = false; // discard
expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard
Proc_pAttr(expctx, direct_source);
break;
}
}
}
}
// \c direct_source reflect the real source of current analysed pIn,
// however \c direct_source can not reflect export link.
// So we need to analyse \c shared_source now for export link.
//
// If this pIn has established some export relation, its \c shared_source must be filled, so we can detect this in here.
// Once its \c shared_source is not nullptr, we should consider export link in here.
//
// We do not need to analyse any export link here,
// we just need to export some infos to tell that there is an export link.
CKParameterIn* shared_source = analysed->GetSharedSource();
if (shared_source != nullptr) {
// pIn from BB
// Get the owner of shared_source
CKObject* ss_owner = shared_source->GetOwner();
// Setup fields
expctx.cache.pLink.input = shared_source->GetID();
expctx.cache.pLink.input_obj = ss_owner->GetID();
switch (ss_owner->GetClassID()) {
case CKCID_BEHAVIOR: // CKBehavior
{
CKBehavior* ss_owner_cast = static_cast<CKBehavior*>(ss_owner);
if (ss_owner_cast->IsUsingTarget() && (ss_owner_cast->GetTargetParameter() == shared_source)) {
// pTarget
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PTARGET;
expctx.cache.pLink.input_is_bb = true;
expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard
} else {
// pIn
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PIN;
expctx.cache.pLink.input_is_bb = true;
expctx.cache.pLink.input_index = ((CKBehavior*)ss_owner)->GetInputParameterPosition(shared_source);
}
break;
}
case CKCID_PARAMETEROPERATION: // CKParameterOperation
{
// pOper only can have pIn (there is no possibility to have pTarget).
CKParameterOperation* ss_owner_cast = static_cast<CKParameterOperation*>(ss_owner);
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PIN;
expctx.cache.pLink.input_is_bb = false;
expctx.cache.pLink.input_index = ss_owner_cast->GetInParameter1() == shared_source ? 0 : 1;
break;
}
default:
// The unexpected value.
// According to SDK manual, there are only 2 possible types.
throw std::runtime_error("unexpected shared_source owner class id!");
return;
}
}
// If the head of pLink has been analysed successfully,
// we can add tail info and push into database
if (shared_source != nullptr || direct_source != nullptr) {
expctx.cache.pLink.output = analysed->GetID();
expctx.cache.pLink.output_obj = parent;
expctx.cache.pLink.output_type = is_target ? VSW::DataTypes::ParameterLinkIOType::PTARGET : VSW::DataTypes::ParameterLinkIOType::PIN;
expctx.cache.pLink.output_is_bb = executed_from_bb;
expctx.cache.pLink.output_index = pin_index;
expctx.cache.pLink.parent = grandparent;
expctx.db.Write(expctx.cache.pLink);
}
}
/**
* @brief Generate pLink and eLink from pOut
* @param[in] expctx Reference to export context.
* @param[in] analysed Pointer to CKParameterIn for analysing.
* @param[in] parent
* @param[in] grandparent
* @param[in] pout_index
* @param[in] executed_from_bb True if given CKParameterIn is belong to a CKBehavior, otherwise false (CKParamterOperation).
*/
static void Generate_pLink(ExportContext& expctx, CKParameterOut* analysed, CK_ID parent, CK_ID grandparent, int pout_index, bool executed_from_bb) {
// Check eLink first
// Check whether there is an export parameter and write to database
// Same check method as another overload
CKBehavior* ckobj_grandparent = static_cast<CKBehavior*>(expctx.ctx->GetObjectA(grandparent));
if (ckobj_grandparent->GetOutputParameterPosition(analysed) != -1) {
expctx.cache.eLink.export_obj = analysed->GetID();
expctx.cache.eLink.internal_obj = parent;
expctx.cache.eLink.is_in = false;
expctx.cache.eLink.index = pout_index;
expctx.cache.eLink.parent = grandparent;
expctx.db.Write(expctx.cache.eLink);
// if an eLink has been generated, skip following pLink generation
return;
}
// Try to generate pLink
for (int j = 0, j_count = analysed->GetDestinationCount(); j < j_count; j++) {
CKParameter* dest = analysed->GetDestination(j);
expctx.cache.pLink.input = analysed->GetID();
expctx.cache.pLink.input_obj = parent;
expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::POUT;
expctx.cache.pLink.input_is_bb = executed_from_bb;
expctx.cache.pLink.input_index = pout_index;
expctx.cache.pLink.output = dest->GetID();
if (dest->GetClassID() == CKCID_PARAMETERLOCAL) {
// pLocal
expctx.cache.pLink.output_obj = dest->GetID();
expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::PLOCAL;
expctx.cache.pLink.output_is_bb = false; // discard
expctx.cache.pLink.output_index = Utilities::INVALID_INDEX; // discard
} else {
// pOut. It must belong to a graph BB
// (pOut can not be shared, and prototype bb or pOper do not have linkable pOut).
CKObject* dest_owner = dest->GetOwner();
switch (dest_owner->GetClassID()) {
case CKCID_BEHAVIOR:
{
CKBehavior* dest_owner_cast = static_cast<CKBehavior*>(dest_owner);
CKParameterOut* dest_cast = static_cast<CKParameterOut*>(dest);
expctx.cache.pLink.output_obj = dest_owner->GetID();
expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::POUT;
expctx.cache.pLink.output_is_bb = true;
expctx.cache.pLink.output_index = dest_owner_cast->GetOutputParameterPosition(dest_cast);
break;
}
case CKCID_DATAARRAY:
{
// CKDataArray, see as virtual BB pLocal shortcut
expctx.cache.pLink.output_obj = dest->GetID();
expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::PATTR;
expctx.cache.pLink.input_is_bb = false; // discard
expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard
Proc_pAttr(expctx, dest);
break;
}
default:
{
// CKObject. Because CKDataArray also a CKObject, so we test it above this case statement.
// See this as virtual BB pLocal shortcut
expctx.cache.pLink.output_obj = dest->GetID();
expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::PATTR;
expctx.cache.pLink.input_is_bb = false; // discard
expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard
Proc_pAttr(expctx, dest);
break;
}
}
}
// setup parent and write into database
expctx.cache.pLink.parent = grandparent;
expctx.db.Write(expctx.cache.pLink);
}
}
static void Proc_pTarget(ExportContext& expctx, CKParameterIn* ckobj, CK_ID parent, CK_ID grandparent) {
expctx.cache.pTarget.thisobj = ckobj->GetID();
CP_CKSTR(expctx.cache.pTarget.name, ckobj->GetName());
CP_GUID(expctx.cache.pTarget.type, ckobj->GetGUID());
expctx.cache.pTarget.parent = parent;
expctx.cache.pTarget.direct_source = ckobj->GetDirectSource() ? ckobj->GetDirectSource()->GetID() : Utilities::INVALID_CK_ID;
expctx.cache.pTarget.shared_source = ckobj->GetSharedSource() ? ckobj->GetSharedSource()->GetID() : Utilities::INVALID_CK_ID;
expctx.db.Write(expctx.cache.pTarget);
// try to generate pLink and eLink
Generate_pLink(expctx, ckobj, parent, grandparent, Utilities::INVALID_INDEX, true, true);
}
static void Proc_pIn(ExportContext& expctx, CKParameterIn* ckobj, CK_ID parent, CK_ID grandparent, int index, bool executed_from_bb) {
expctx.cache.pIn.thisobj = ckobj->GetID();
expctx.cache.pIn.index = index;
CP_CKSTR(expctx.cache.pIn.name, ckobj->GetName());
CP_GUID(expctx.cache.pIn.type, ckobj->GetGUID());
expctx.cache.pIn.parent = parent;
expctx.cache.pIn.direct_source = ckobj->GetDirectSource() ? ckobj->GetDirectSource()->GetID() : Utilities::INVALID_CK_ID;
expctx.cache.pIn.shared_source = ckobj->GetSharedSource() ? ckobj->GetSharedSource()->GetID() : Utilities::INVALID_CK_ID;
expctx.db.Write(expctx.cache.pIn);
// try to generate pLink and eLink
Generate_pLink(expctx, ckobj, parent, grandparent, index, executed_from_bb, false);
}
static void Proc_pOut(ExportContext& expctx, CKParameterOut* ckobj, CK_ID parent, CK_ID grandparent, int index, bool executed_from_bb) {
expctx.cache.pOut.thisobj = ckobj->GetID();
expctx.cache.pOut.index = index;
CP_CKSTR(expctx.cache.pOut.name, ckobj->GetName());
CP_GUID(expctx.cache.pOut.type, ckobj->GetGUID());
expctx.cache.pOut.parent = parent;
expctx.db.Write(expctx.cache.pOut);
// try to generate pLink and eLink
Generate_pLink(expctx, ckobj, parent, grandparent, index, executed_from_bb);
}
static void Proc_bIn(ExportContext& expctx, CKBehaviorIO* ckobj, CK_ID parent, int index) {
expctx.cache.bIn.thisobj = ckobj->GetID();
expctx.cache.bIn.index = index;
CP_CKSTR(expctx.cache.bIn.name, ckobj->GetName());
expctx.cache.bIn.parent = parent;
expctx.db.Write(expctx.cache.bIn);
}
static void Proc_bOut(ExportContext& expctx, CKBehaviorIO* ckobj, CK_ID parent, int index) {
expctx.cache.bOut.thisobj = ckobj->GetID();
expctx.cache.bOut.index = index;
CP_CKSTR(expctx.cache.bOut.name, ckobj->GetName());
expctx.cache.bOut.parent = parent;
expctx.db.Write(expctx.cache.bOut);
}
static void Proc_bLink(ExportContext& expctx, CKBehaviorLink* ckobj, CK_ID parent) {
// setup start terminal
CKBehaviorIO* io = ckobj->GetInBehaviorIO();
CKBehavior* beh = io->GetOwner();
expctx.cache.bLink.input = io->GetID();
expctx.cache.bLink.input_obj = beh->GetID();
expctx.cache.bLink.input_type = (io->GetType() == CK_BEHAVIORIO_IN ? VSW::DataTypes::BehaviorLinkIOType::INPUT : VSW::DataTypes::BehaviorLinkIOType::OUTPUT);
expctx.cache.bLink.input_index = (io->GetType() == CK_BEHAVIORIO_IN ? io->GetOwner()->GetInputPosition(io) : io->GetOwner()->GetOutputPosition(io));
// setup end terminal
io = ckobj->GetOutBehaviorIO();
beh = io->GetOwner();
expctx.cache.bLink.output = io->GetID();
expctx.cache.bLink.output_obj = beh->GetID();
expctx.cache.bLink.output_type = (io->GetType() == CK_BEHAVIORIO_IN ? VSW::DataTypes::BehaviorLinkIOType::INPUT : VSW::DataTypes::BehaviorLinkIOType::OUTPUT);
expctx.cache.bLink.output_index = (io->GetType() == CK_BEHAVIORIO_IN ? io->GetOwner()->GetInputPosition(io) : io->GetOwner()->GetOutputPosition(io));
// other properties
expctx.cache.bLink.delay = ckobj->GetActivationDelay();
expctx.cache.bLink.parent = parent;
// write to database
expctx.db.Write(expctx.cache.bLink);
}
static void Proc_pLocal(ExportContext& expctx, CKParameterLocal* ckobj, CK_ID parent, bool is_setting) {
expctx.cache.pLocal.thisobj = ckobj->GetID();
CP_CKSTR(expctx.cache.pLocal.name, ckobj->GetName());
CP_GUID(expctx.cache.pLocal.type, ckobj->GetGUID());
expctx.cache.pLocal.is_setting = is_setting;
expctx.cache.pLocal.parent = parent;
expctx.db.Write(expctx.cache.pLocal);
// Export pLocal internal data
DigParameterData(expctx, ckobj, ckobj->GetID());
}
static void Proc_pOper(ExportContext& expctx, CKParameterOperation* ckobj, CK_ID parent) {
expctx.cache.pOper.thisobj = ckobj->GetID();
CP_GUID(expctx.cache.pOper.op, ckobj->GetOperationGuid());
expctx.cache.pOper.parent = parent;
expctx.db.Write(expctx.cache.pOper);
// Process associated 2 pIn and 1 pOut
Proc_pIn(expctx, ckobj->GetInParameter1(), ckobj->GetID(), parent, 0, false);
Proc_pIn(expctx, ckobj->GetInParameter2(), ckobj->GetID(), parent, 1, false);
Proc_pOut(expctx, ckobj->GetOutParameter(), ckobj->GetID(), parent, 0, false);
}
/**
* @brief Process CKBehavior
* @param[in] expctx Reference to export context.
* @param[in] behavior Pointer to CKBehavior for processing.
* @param[in] parent The parent of this CKBehavior. Set to \c INVALID_CK_ID if it was called from script iterator.
*/
static void Proc_Behavior(ExportContext& expctx, CKBehavior* behavior, CK_ID parent) {
// Write basic behavior infomation
expctx.cache.behavior.thisobj = behavior->GetID();
CP_CKSTR(expctx.cache.behavior.name, behavior->GetName());
expctx.cache.behavior.type = behavior->GetType();
CP_CKSTR(expctx.cache.behavior.proto_name, behavior->GetPrototypeName());
CP_GUID(expctx.cache.behavior.proto_guid, behavior->GetPrototypeGuid());
expctx.cache.behavior.flags = behavior->GetFlags();
expctx.cache.behavior.priority = behavior->GetPriority();
expctx.cache.behavior.version = behavior->GetVersion();
expctx.cache.behavior.pin_count_ptarget = (behavior->IsUsingTarget() ? 1 : 0);
expctx.cache.behavior.pin_count_pin = behavior->GetInputParameterCount();
expctx.cache.behavior.pin_count_pout = behavior->GetOutputParameterCount();
expctx.cache.behavior.pin_count_bin = behavior->GetInputCount();
expctx.cache.behavior.pin_count_bout = behavior->GetOutputCount();
expctx.cache.behavior.parent = parent;
expctx.db.Write(expctx.cache.behavior);
// pTarget
if (behavior->IsUsingTarget())
Proc_pTarget(expctx, behavior->GetTargetParameter(), behavior->GetID(), parent);
// pIn
for (int i = 0, count = behavior->GetInputParameterCount(); i < count; ++i)
Proc_pIn(expctx, behavior->GetInputParameter(i), behavior->GetID(), parent, i, true);
// pOut
for (int i = 0, count = behavior->GetOutputParameterCount(); i < count; ++i)
Proc_pOut(expctx, behavior->GetOutputParameter(i), behavior->GetID(), parent, i, true);
// bIn
for (int i = 0, count = behavior->GetInputCount(); i < count; ++i)
Proc_bIn(expctx, behavior->GetInput(i), behavior->GetID(), i);
// bOut
for (int i = 0, count = behavior->GetOutputCount(); i < count; ++i)
Proc_bOut(expctx, behavior->GetOutput(i), behavior->GetID(), i);
// bLink
for (int i = 0, count = behavior->GetSubBehaviorLinkCount(); i < count; ++i)
Proc_bLink(expctx, behavior->GetSubBehaviorLink(i), behavior->GetID());
// pLocal
for (int i = 0, count = behavior->GetLocalParameterCount(); i < count; ++i)
Proc_pLocal(expctx, behavior->GetLocalParameter(i), behavior->GetID(), behavior->IsLocalParameterSetting(i));
// pOper
for (int i = 0, count = behavior->GetParameterOperationCount(); i < count; ++i)
Proc_pOper(expctx, behavior->GetParameterOperation(i), behavior->GetID());
// Iterate sub behavior
for (int i = 0, count = behavior->GetSubBehaviorCount(); i < count; ++i)
Proc_Behavior(expctx, behavior->GetSubBehavior(i), behavior->GetID());
}
static void IterateScript(ExportContext& expctx) {
// Get all CKBeObjects to try to get all scripts,
// because only CKBeObject can own script.
XObjectPointerArray obj_array = expctx.ctx->GetObjectListByType(CKCID_BEOBJECT, TRUE);
int obj_count = obj_array.Size();
for (int i = 0; i < obj_count; ++i) {
// Get CKBeObject
CKBeObject* beobj = static_cast<CKBeObject*>(obj_array.GetObjectA(i));
// Get script count. If no script, skip this object.
int script_count = beobj->GetScriptCount();
if (script_count == 0) continue;
// Iterate binding scripts
for (int j = 0; j < script_count; ++j) {
// Get associated behavior
CKBehavior* behavior = beobj->GetScript(j);
// Write to database
expctx.cache.script.beobj = beobj->GetID();
CP_CKSTR(expctx.cache.script.beobj_name, beobj->GetName());
expctx.cache.script.behavior_index = j;
expctx.cache.script.behavior = behavior->GetID();
expctx.db.Write(expctx.cache.script);
// Process this script
Proc_Behavior(expctx, behavior, Utilities::INVALID_CK_ID);
}
}
}
void Export(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) { void Export(CKContext* ctx, const YYCC::yycc_u8string_view& db_path, UINT code_page) {
// create export context
ExportContext expctx(ctx, db_path, code_page);
if (!expctx.db.IsValid()) {
expctx.reporter.Err(YYCC_U8("Fail to open database. Export process aborted."));
return;
}
// export script
IterateScript(expctx);
// report success
expctx.reporter.EnableBeep();
expctx.reporter.Info(YYCC_U8("Exporting script database done."));
expctx.reporter.DisableBeep();
} }
} }

View File

@@ -6,6 +6,35 @@ namespace VSW::Materializer::PluginMain {
#ifdef MATERIALIZER_PLUGIN #ifdef MATERIALIZER_PLUGIN
#pragma region Export Dialog Setting
ConfigManager::ConfigManager() :
m_LastFilePath(YYCC_U8("last-file-path"), YYCC_U8("")),
m_Encoding(YYCC_U8("encoding"), CP_ACP),
m_Mgr(ConfigManager::GetConfigFilePath(), UINT64_C(0), {
&m_LastFilePath, &m_Encoding
}) {}
ConfigManager::~ConfigManager() {}
ConfigManager& ConfigManager::GetSingleton() {
static ConfigManager g_Singleton;
return g_Singleton;
}
YYCC::yycc_u8string ConfigManager::GetConfigFilePath() {
// get path to executable virtools
YYCC::yycc_u8string u8_virtools_path;
if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_virtools_path))
u8_virtools_path.clear();
// get its parent folder and append with cfg file name
std::filesystem::path virtools_path(YYCC::StdPatch::ToStdPath(u8_virtools_path));
return YYCC::StdPatch::ToUTF8Path(virtools_path.parent_path() / YYCC::StdPatch::ToStdPath(YYCC_U8("vsw_materializer.cfg")));
}
#pragma endregion
PluginInterface* g_Plugininterface = nullptr; PluginInterface* g_Plugininterface = nullptr;
PluginInfo g_PluginInfo; PluginInfo g_PluginInfo;
CMenu* g_MainMenu = nullptr; CMenu* g_MainMenu = nullptr;

View File

@@ -4,9 +4,25 @@
namespace VSW::Materializer::PluginMain { namespace VSW::Materializer::PluginMain {
#ifdef MATERIALIZER_PLUGIN #ifdef MATERIALIZER_PLUGIN
class ConfigManager {
public:
static ConfigManager& GetSingleton();
private:
static YYCC::yycc_u8string GetConfigFilePath();
ConfigManager();
~ConfigManager();
public:
YYCC::ConfigManager::StringSetting m_LastFilePath;
YYCC::ConfigManager::NumberSetting<UINT> m_Encoding;
YYCC::ConfigManager::CoreManager m_Mgr;
};
void InitializePluginInfo(); void InitializePluginInfo();
PluginInfo* GetPluginInfo(); PluginInfo* GetPluginInfo();
PluginInterface* GetPluginInterface(); PluginInterface* GetPluginInterface();
#endif #endif
} }

View File

@@ -1,86 +1,260 @@
#include "StandaloneMain.hpp" #include "StandaloneMain.hpp"
#include "ExportCore.hpp"
#include "GenericHelper.hpp"
#include <optional>
namespace VSW::Materializer::StandaloneMain { namespace VSW::Materializer::StandaloneMain {
#ifdef MATERIALIZER_STANDALONE #ifdef MATERIALIZER_STANDALONE
#pragma region Program Command Line Parser
struct CmdArguments {
CmdArguments() :
m_InputFilePath(),
m_ScriptDbPath(), m_DocumentDbPath(), m_EnvironmentDbPath(),
m_CodePage(CP_ACP) {}
YYCC::yycc_u8string m_InputFilePath;
YYCC::yycc_u8string m_ScriptDbPath, m_DocumentDbPath, m_EnvironmentDbPath;
UINT m_CodePage;
};
static YYCC::Constraints::Constraint<UINT> GetCodePageConstraint() {
return YYCC::Constraints::Constraint<UINT> {
[](const UINT& val) -> bool {
return YYCC::WinFctHelper::IsValidCodePage(val);
}
};
}
class CmdParser {
public:
CmdParser() :
m_InputFilePath(YYCC_U8("input"), YYCC_U8_CHAR('i'), YYCC_U8("The path to Virtools file for exporting."), YYCC_U8("example.cmo"), true),
m_ScriptDbPath(YYCC_U8("script"), YYCC_U8_CHAR('s'), YYCC_U8("The path to exported script database. Input file is required."), YYCC_U8("script.db"), true),
m_DocumentDbPath(YYCC_U8("document"), YYCC_U8_CHAR('d'), YYCC_U8("The path to exported document database. Input file is required."), YYCC_U8("doc.db"), true),
m_EnvironmentDbPath(YYCC_U8("environment"), YYCC_U8_CHAR('e'), YYCC_U8("The path to exported environment database. Input file is not required."), YYCC_U8("env.db"), true),
m_CodePage(YYCC_U8("code-page"), YYCC_U8_CHAR('c'), YYCC_U8("The code page used when reading Virtools document."), YYCC_U8("1252"), true, GetCodePageConstraint()),
m_Version(YYCC_U8("version"), YYCC_U8_CHAR('v'), YYCC_U8("Print version infomation about this program and exit.")),
m_Help(YYCC_U8("help"), YYCC_U8_CHAR('h'), YYCC_U8("Print this help page and exit.")),
m_OptionContext(YYCC_U8("Virtools Schematic Weaver - Materializer"), YYCC_U8("The exporter of Virtools Schematic Weaver"), {
&m_InputFilePath,
&m_ScriptDbPath, &m_DocumentDbPath, &m_EnvironmentDbPath, &m_CodePage,
&m_Version, &m_Help
}) {}
~CmdParser() {}
YYCC_DEL_CLS_COPY_MOVE(CmdParser);
public:
YYCC::ArgParser::StringArgument m_InputFilePath;
YYCC::ArgParser::StringArgument m_ScriptDbPath;
YYCC::ArgParser::StringArgument m_DocumentDbPath;
YYCC::ArgParser::StringArgument m_EnvironmentDbPath;
YYCC::ArgParser::NumberArgument<UINT> m_CodePage;
YYCC::ArgParser::SwitchArgument m_Version;
YYCC::ArgParser::SwitchArgument m_Help;
YYCC::ArgParser::OptionContext m_OptionContext;
};
static bool ParseCmd(int argc, char* argv[], CmdArguments& captured) {
// fetch argument list
#if YYCC_OS == YYCC_OS_WINDOWS
auto al = YYCC::ArgParser::ArgumentList::CreateFromWin32();
#else
auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(argc, argv);
#endif
// do parse
CmdParser parser;
if (!parser.m_OptionContext.Parse(al)) {
YYCC::ConsoleHelper::WriteLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("Invalid command line.")));
parser.m_OptionContext.Help();
return false;
}
// check help command
if (parser.m_Help.IsCaptured()) {
parser.m_OptionContext.Help();
return false;
}
// check version command
if (parser.m_Version.IsCaptured()) {
YYCC::ConsoleHelper::WriteLine(YYCC_U8("Virtools Schematic Weaver - Materializer v2.0.0"));
return false;
}
// check command relation
// if specify script or document export, user must provide input file
if (parser.m_ScriptDbPath.IsCaptured() || parser.m_DocumentDbPath.IsCaptured()) {
if (!parser.m_InputFilePath.IsCaptured()) {
YYCC::ConsoleHelper::WriteLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("You must specify one input file if you want to export script or document.")));
parser.m_OptionContext.Help();
return false;
}
}
// setup argument
if (parser.m_InputFilePath.IsCaptured()) captured.m_InputFilePath = parser.m_InputFilePath.Get();
else captured.m_InputFilePath.clear();
if (parser.m_ScriptDbPath.IsCaptured()) captured.m_ScriptDbPath = parser.m_ScriptDbPath.Get();
else captured.m_ScriptDbPath.clear();
if (parser.m_DocumentDbPath.IsCaptured()) captured.m_DocumentDbPath = parser.m_DocumentDbPath.Get();
else captured.m_DocumentDbPath.clear();
if (parser.m_EnvironmentDbPath.IsCaptured()) captured.m_EnvironmentDbPath = parser.m_EnvironmentDbPath.Get();
else captured.m_EnvironmentDbPath.clear();
if (parser.m_CodePage.IsCaptured()) captured.m_CodePage = parser.m_CodePage.Get();
else captured.m_CodePage = CP_ACP;
// okey, return
return true;
}
#pragma endregion
#pragma region Assistant Functions
class TemporaryFile {
public:
TemporaryFile(CKContext* ctx, const YYCC::yycc_u8string_view& u8_vt_file) :
m_IsSuccess(false), m_TempFile() {
if (ctx == nullptr) throw std::invalid_argument("Invalid CKContext");
if (u8_vt_file.empty()) throw std::invalid_argument("Invalid Virtools file path");
// build source virtools file
auto vt_file = YYCC::StdPatch::ToStdPath(u8_vt_file);
// build cache path located in Windows temp path and keep its extension
YYCC::yycc_u8string u8_temp_dir;
if (!YYCC::WinFctHelper::GetTempDirectory(u8_temp_dir))
throw std::runtime_error("Fail to fetch Windows Temp directory");
auto temp_dir = YYCC::StdPatch::ToStdPath(u8_temp_dir);
temp_dir /= YYCC::StdPatch::ToStdPath(YYCC_U8("07159749-81e5-4ec2-b649-87b8eb9c1f5a"));
temp_dir.replace_extension(vt_file.extension());
m_TempFile = YYCC::StdPatch::ToUTF8Path(temp_dir);
// copy it to temp directory
if (!YYCC::WinFctHelper::CopyFile(u8_vt_file, m_TempFile, FALSE))
throw std::runtime_error("Fail to copy file.");
// okey
m_IsSuccess = true;
}
~TemporaryFile() {
if (m_IsSuccess) {
std::wstring w_temp_file;
if (!YYCC::EncodingHelper::UTF8ToWchar(m_TempFile, w_temp_file)) return;
::DeleteFileW(w_temp_file.c_str());
}
}
TemporaryFile(TemporaryFile&& rhs) :
m_IsSuccess(rhs.m_IsSuccess), m_TempFile(rhs.m_TempFile) {
rhs.m_IsSuccess = false;
rhs.m_TempFile.clear();
}
TemporaryFile& operator=(TemporaryFile&& rhs) {
this->m_IsSuccess = rhs.m_IsSuccess;
this->m_TempFile = rhs.m_TempFile;
rhs.m_IsSuccess = false;
rhs.m_TempFile.clear();
return *this;
}
YYCC_DEL_CLS_COPY(TemporaryFile);
public:
bool IsSuccess() const { return m_IsSuccess; }
const YYCC::yycc_u8string& GetPath() const { return m_TempFile; }
private:
bool m_IsSuccess;
YYCC::yycc_u8string m_TempFile;
};
static void CustomAssert(VSW::Reporter& reporter, bool condition, const YYCC::yycc_char8_t* msg) {
if (!condition) {
if (msg != nullptr)
reporter.Err(msg);
std::abort();
}
}
#define CUSTOM_ASSERT(condition, msg) CustomAssert(reporter, (condition), YYCC_U8(msg))
#pragma endregion
void PlayerMain(int argc, char* argv[]) { void PlayerMain(int argc, char* argv[]) {
printf("Super Script Materializer\n"); // ========== Check Passed Arguments ==========
printf("Homepage: https://github.com/yyc12345/SuperScriptMaterializer\n"); CmdArguments captured;
printf("Report bug: https://github.com/yyc12345/SuperScriptMaterializer/issues\n"); if (!ParseCmd(argc, argv, captured)) {
return;
}
// ====================== Init ck2 engine // ========== Print Header ==========
YYCC::ConsoleHelper::WriteLine(YYCC_U8("Virtools Schematic Weaver - Materializer"));
YYCC::ConsoleHelper::WriteLine(YYCC_U8("Homepage: https://github.com/yyc12345/SuperScriptMaterializer"));
YYCC::ConsoleHelper::WriteLine(YYCC_U8("Report bug: https://github.com/yyc12345/SuperScriptMaterializer/issues"));
// ========== Init CK2 Engine ==========
// Prepare reporter
VSW::Reporter reporter;
CUSTOM_ASSERT(CKStartUp() == CK_OK, "CKStartUp() Error");
CKPluginManager* plugin_mgr = CKGetPluginManager();
CUSTOM_ASSERT(plugin_mgr != nullptr, "CKPluginManager is nullptr");
CUSTOM_ASSERT(plugin_mgr->ParsePlugins("RenderEngines") > 0, "Error loading RenderEngines");
CUSTOM_ASSERT(plugin_mgr->ParsePlugins("Managers") > 0, "Error loading Managers");
CUSTOM_ASSERT(plugin_mgr->ParsePlugins("BuildingBlocks") > 0, "Error loading BuildingBlocks");
CUSTOM_ASSERT(plugin_mgr->ParsePlugins("Plugins") > 0, "Error loading Plugins");
// ========== Create CKContext ==========
CKContext* ctx = nullptr;
#if defined(VIRTOOLS_21) #if defined(VIRTOOLS_21)
CommonAssert(LoadLibrary("CK2.dll") != NULL, "Error loading CK2.dll"); CUSTOM_ASSERT(CKCreateContext(&ctx, NULL, 0, 0) == CK_OK, "CKCreateContext Error");
#else
CUSTOM_ASSERT(CKCreateContext(&ctx, NULL) == CK_OK, "CKCreateContext Error");
#endif #endif
CommonAssert(!CKStartUp(), "CKStartUp Error"); // ========== Load File ==========
CKPluginManager* pluginManager = CKGetPluginManager(); std::optional<TemporaryFile> loaded_file;
CommonAssert(pluginManager != NULL, "PluginManager = null"); CKObjectArray* loaded_file_objs = CreateCKObjectArray();
CommonAssert(pluginManager->ParsePlugins("RenderEngines") > 0, "Error loading RenderEngines"); if (!captured.m_InputFilePath.empty()) {
CommonAssert(pluginManager->ParsePlugins("Managers") > 0, "Error loading Managers"); TemporaryFile cache(ctx, captured.m_InputFilePath);
CommonAssert(pluginManager->ParsePlugins("BuildingBlocks") > 0, "Error loading BuildingBlocks"); if (cache.IsSuccess()) {
CommonAssert(pluginManager->ParsePlugins("Plugins") > 0, "Error loading Plugins"); std::string temp_file;
if (YYCC::EncodingHelper::UTF8ToChar(cache.GetPath(), temp_file, CP_ACP)) {
if (ctx->Load(const_cast<CKSTRING>(temp_file.c_str()), loaded_file_objs) == CK_OK) {
loaded_file = std::move(cache);
}
}
}
CUSTOM_ASSERT(loaded_file.has_value(), "Fail to open specified file.");
}
// ====================== create context and load file // ========== Export Data ==========
CKContext* context = NULL; if (!captured.m_ScriptDbPath.empty()) {
CommonAssert(!CKCreateContext(&context, NULL), "CKCreateContext Error"); reporter.Info(YYCC_U8("Exporting script database..."));
ExportScript::Export(ctx, captured.m_ScriptDbPath, captured.m_CodePage);
}
if (!captured.m_DocumentDbPath.empty()) {
reporter.Info(YYCC_U8("Exporting document database..."));
ExportDocument::Export(ctx, captured.m_DocumentDbPath, captured.m_CodePage);
}
if (!captured.m_EnvironmentDbPath.empty()) {
reporter.Info(YYCC_U8("Exporting environment database..."));
ExportEnvironment::Export(ctx, captured.m_EnvironmentDbPath, captured.m_CodePage);
}
CKObjectArray* array = CreateCKObjectArray(); // ========== Unload File and Clear CKContext ==========
CommonAssert(!context->Load((char*)virtools_composition, array), "CKContext->Load() Error"); DeleteCKObjectArray(loaded_file_objs);
loaded_file.reset();
ctx->Reset();
ctx->ClearAll();
printf("Parsing %s...\n", virtools_composition); // ========== Destroy CKContext ==========
// todo: Virtools 4.0 standalone version throw exception in there, but i don't know why
// ====================== do SSMaterializerDatabase export
// define and Init
scriptDatabase* _script_db = new scriptDatabase();
dbScriptDataStructHelper* _script_helper = new dbScriptDataStructHelper();
envDatabase* _env_db = new envDatabase();
dbEnvDataStructHelper* _env_helper = new dbEnvDataStructHelper();
DeleteFile(script_db_path);
DeleteFile(env_db_path);
_script_db->open(script_db_path);
_script_helper->init(context->GetParameterManager());
_env_db->open(env_db_path);
_env_helper->init();
// export
IterateScript(context, _script_db, _script_helper);
IterateParameterOperation(context->GetParameterManager(), _env_db, _env_helper);
IterateParameter(context->GetParameterManager(), _env_db, _env_helper);
IterateMessage(context->GetMessageManager(), _env_db, _env_helper);
IterateAttribute(context->GetAttributeManager(), _env_db, _env_helper);
IteratePlugin(CKGetPluginManager(), _env_db, _env_helper);
#if !defined(VIRTOOLS_21)
IterateVariable(context->GetVariableManager(), _env_db, _env_helper);
#endif
// free
_script_helper->dispose();
_script_db->close();
_env_helper->dispose();
_env_db->close();
delete _script_helper;
delete _script_db;
delete _env_helper;
delete _env_db;
printf("Done!");
// ====================== free resources and shutdown engine
DeleteCKObjectArray(array);
context->Reset();
context->ClearAll();
// todo: Virtools 4.0 standalone version throw exception in there, but i don't knwo why
// but it doesn't affect SSMaterializerDatabase export, perhaps // but it doesn't affect SSMaterializerDatabase export, perhaps
CKCloseContext(context); CKCloseContext(ctx);
// ========== Shutdown CK2 Engine ==========
CKShutdown(); CKShutdown();
// todo: Virtools 2.5 standalone version throw exception in there, but i don't knwo why // todo: Virtools 2.5 standalone version throw exception in there, but i don't know why
// but it doesn't affect SSMaterializerDatabase export, perhaps // but it doesn't affect SSMaterializerDatabase export, perhaps
} }

View File

@@ -2,14 +2,103 @@
namespace VSW::Materializer::Utilities { namespace VSW::Materializer::Utilities {
std::string RelativeAddress(const void* absolute_addr) { #pragma region Enhanced Reporter
// prepare return value
std::string ret("<error>");
EnhancedReporter::EnhancedReporter(CKContext* ctx) :
m_Ctx(ctx), m_OrderBeep(false) {}
EnhancedReporter::~EnhancedReporter() {}
void EnhancedReporter::EnableBeep() { m_OrderBeep = true; }
void EnhancedReporter::DisableBeep() { m_OrderBeep = false; }
void EnhancedReporter::PrePrint(const YYCC::yycc_char8_t* strl) const {
// only write when CKContext is not nullptr and we are in Interface Mode (Dev mode).
if (m_Ctx != nullptr && m_Ctx->IsInInterfaceMode())
m_Ctx->OutputToConsole(const_cast<CKSTRING>(YYCC::EncodingHelper::UTF8ToChar(strl, CP_ACP).c_str()), m_OrderBeep);
}
#pragma endregion
#pragma region Curve 2D Builder
Curve2DBuilder::Curve2DBuilder(CK2dCurve* curve_2d) : m_Cache() {
BuildCurve(curve_2d);
}
Curve2DBuilder::~Curve2DBuilder() {}
const void* Curve2DBuilder::GetDataPtr() const { return m_Cache.c_str(); }
size_t Curve2DBuilder::GetDataLength() const { return m_Cache.size(); }
void Curve2DBuilder::BuildCurve(CK2dCurve* c) {
// check curve
if (c == nullptr) return;
// get curve control point count
int cp_count = c->GetControlPointCount();
// reserve enough space
// count * (x + y + is_linear + is_tcb + (io_tangent_tuple / tcb_tuple))
m_Cache.reserve(static_cast<size_t>(cp_count) * (sizeof(float) * 2u + sizeof(float) * 4u + sizeof(uint32_t) + sizeof(uint32_t)));
// iterate control point
for (int i = 0; i < cp_count; ++i) {
BuildCurvePoint(c->GetControlPoint(i));
}
}
void Curve2DBuilder::BuildCurvePoint(CK2dCurvePoint* cp) {
// check control point
if (cp == nullptr) return;
// prepare variable
uint32_t int_cache;
Vx2DVector vector_cache;
float float_cache;
#define APPEND_DATA(data) m_Cache.append(reinterpret_cast<decltype(m_Cache)::value_type*>(&data), sizeof(data))
// x y value
vector_cache = cp->GetPosition();
APPEND_DATA(vector_cache);
// is linear
int_cache = static_cast<uint32_t>(cp->IsLinear());
APPEND_DATA(int_cache);
// is tcb
int_cache = static_cast<uint32_t>(cp->IsTCB());
APPEND_DATA(int_cache);
if (cp->IsTCB()) {
// TCB control point
float_cache = cp->GetTension();
APPEND_DATA(float_cache);
float_cache = cp->GetContinuity();
APPEND_DATA(float_cache);
float_cache = cp->GetBias();
APPEND_DATA(float_cache);
// To keep balance with non-TCB control point,
// We add a blank 0.0f in there
float_cache = 0.0f;
APPEND_DATA(float_cache);
} else {
// non-TCB control point
vector_cache = cp->GetInTangent();
APPEND_DATA(vector_cache);
vector_cache = cp->GetOutTangent();
APPEND_DATA(vector_cache);
}
#undef APPEND_DATA
}
#pragma endregion
void RelativeAddress(const EnhancedReporter& reporter, YYCC::yycc_u8string& relative_addr_str, const void* absolute_addr) {
// If address is nullptr, return directly // If address is nullptr, return directly
if (absolute_addr == nullptr) { if (absolute_addr == nullptr) {
ret = "<nullptr>"; relative_addr_str = YYCC_U8("<nullptr>");
return ret; return;
} }
// Get the module handle which given function address belongs to // Get the module handle which given function address belongs to
@@ -19,16 +108,22 @@ namespace VSW::Materializer::Utilities {
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // get address and do not inc ref counter. GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // get address and do not inc ref counter.
(LPCWSTR)absolute_addr, (LPCWSTR)absolute_addr,
&hModule); &hModule);
if (hModule == NULL) if (hModule == NULL) {
return ret; reporter.ErrF(YYCC_U8("Fail to get module of given absolute address 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR ". Some relative address may be empty."), absolute_addr);
relative_addr_str.clear();
return;
}
// Get full path to module // Get full path to module
YYCC::yycc_u8string u8_module_path; YYCC::yycc_u8string u8_module_path;
if (!YYCC::WinFctHelper::GetModuleFileName(hModule, u8_module_path)) if (!YYCC::WinFctHelper::GetModuleFileName(hModule, u8_module_path)) {
return ret; reporter.ErrF(YYCC_U8("Fail to get file name of given module 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR ". Some relative address may be empty."), hModule);
relative_addr_str.clear();
return;
}
// Then get its file name part // Then get its file name part
auto module_path = YYCC::FsPathPatch::FromUTF8Path(u8_module_path.c_str()); auto module_path = YYCC::StdPatch::ToStdPath(u8_module_path);
auto u8_module_name = YYCC::FsPathPatch::ToUTF8Path(module_path.filename()); auto u8_module_name = YYCC::StdPatch::ToUTF8Path(module_path.filename());
// Get the base address of current module // Get the base address of current module
// HMODULE is the base address of loaded module // HMODULE is the base address of loaded module
@@ -36,42 +131,74 @@ namespace VSW::Materializer::Utilities {
uintptr_t relative_addr = reinterpret_cast<uintptr_t>(absolute_addr) - reinterpret_cast<uintptr_t>(hModule); uintptr_t relative_addr = reinterpret_cast<uintptr_t>(absolute_addr) - reinterpret_cast<uintptr_t>(hModule);
// get final result // get final result
auto u8_ret = YYCC::StringHelper::Printf(YYCC_U8("%s+0x%" PRI_XPTR_LEFT_PADDING PRIXPTR), u8_module_name.c_str(), relative_addr); if (!YYCC::StringHelper::Printf(relative_addr_str, YYCC_U8("%s+0x%" PRI_XPTR_LEFT_PADDING PRIXPTR), u8_module_name.c_str(), relative_addr)) {
ret = YYCC::EncodingHelper::ToOrdinaryView(u8_ret); reporter.Err(YYCC_U8("Fail to format relative address. Some relative address may be empty."));
return ret; relative_addr_str.clear();
}
} }
//void CopyStrGuid(std::string& dst, const CKGUID& src) { //void GetBase64(YYCC::yycc_u8string& dst, const char* data, size_t data_len) {
// auto ret = YYCC::StringHelper::Printf(YYCC_U8("<0x%08" PRIX32 ", 0x%08" PRIX32 ">"), src.d1, src.d2); // // Reference: https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
// dst = YYCC::EncodingHelper::ToOrdinaryView(ret); // static const YYCC::yycc_char8_t* BASE64_TABLE = YYCC_U8("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
// static const int MOD_TABLE[] = { 0, 2, 1 };
// // compute size
// size_t output_length = 4u * ((data_len + 2u) / 3u);
// dst.resize(output_length);
// // compute
// for (size_t i = 0, j = 0; i < data_len;) {
// uint32_t octet_a = i < data_len ? (unsigned char)data[i++] : 0;
// uint32_t octet_b = i < data_len ? (unsigned char)data[i++] : 0;
// uint32_t octet_c = i < data_len ? (unsigned char)data[i++] : 0;
// uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
// dst[j++] = BASE64_TABLE[(triple >> 3 * 6) & 0x3F];
// dst[j++] = BASE64_TABLE[(triple >> 2 * 6) & 0x3F];
// dst[j++] = BASE64_TABLE[(triple >> 1 * 6) & 0x3F];
// dst[j++] = BASE64_TABLE[(triple >> 0 * 6) & 0x3F];
// } // }
void CopyGuid(int64_t& dst, const CKGUID& src) { // // fill blank
// todo: use template argument to implement this to improve performance // for (int i = 0; i < MOD_TABLE[data_len % 3]; i++)
if (sizeof(dst) != sizeof(src)) // dst[output_length - 1 - i] = '=';
throw std::invalid_argument("CKGUID size error"); //}
std::memcpy(&dst, &src, sizeof(int64_t));
void CopyStrGuid(const EnhancedReporter& reporter, YYCC::yycc_u8string& dst, const CKGUID& src) {
if (!YYCC::StringHelper::Printf(dst, YYCC_U8("<0x%08" PRIX32 ", 0x%08" PRIX32 ">"), src.d1, src.d2)) {
reporter.Err(YYCC_U8("Fail to format CKGUID. Some stringified GUID may be empty."));
dst.clear();
}
} }
void CopyCKString(std::string& storage, const char* str, const char* fallback) { void CopyGuid(int64_t& dst, const CKGUID& src) {
// reset dst to zero
uint64_t* pdst = reinterpret_cast<uint64_t*>(&dst);
// CKGUID.d1 to high 32 bits
*pdst = static_cast<uint64_t>(src.d1);
*pdst <<= 32u;
// CKGUID.d2 to low 32 bits
*pdst = (*pdst) | static_cast<uint64_t>(src.d2);
}
void CopyCKString(const EnhancedReporter& reporter, YYCC::yycc_u8string& storage, const char* str, UINT code_page, const YYCC::yycc_char8_t* fallback) {
// check whether callback is nullptr.
if (fallback == nullptr) if (fallback == nullptr)
throw std::invalid_argument("fallback string should not be nullptr!"); throw std::invalid_argument("fallback string should not be nullptr!");
if (str == nullptr) storage = fallback;
else storage = str; // if given string is nullptr, use fallback instead
if (str == nullptr) {
storage = fallback;
return;
} }
#pragma region Enhanced Reporter // otherwise do encoding convertion of original string.
if (!YYCC::EncodingHelper::CharToUTF8(str, storage, code_page)) {
EnhancedReporter::EnhancedReporter(CKContext* ctx) : reporter.Err(YYCC_U8("Fail to convert encoding. Some string may use fallback string accidently."));
m_Ctx(ctx) {} storage = fallback;
}
EnhancedReporter::~EnhancedReporter() {}
void EnhancedReporter::PrePrint(const YYCC::yycc_char8_t* strl) {
if (m_Ctx != nullptr)
m_Ctx->OutputToConsole(const_cast<CKSTRING>(YYCC::EncodingHelper::UTF8ToChar(strl, CP_ACP).c_str()), FALSE);
} }
#pragma endregion
} }

View File

@@ -6,28 +6,68 @@ namespace VSW::Materializer::Utilities {
/// @brief The value representing a invalid CK_ID. /// @brief The value representing a invalid CK_ID.
constexpr CK_ID INVALID_CK_ID = static_cast<CK_ID>(-1); constexpr CK_ID INVALID_CK_ID = static_cast<CK_ID>(-1);
constexpr int INVALID_INDEX = static_cast<int>(-1);
constexpr char NULLPTR_CKSTRING[] = "<null>";
class EnhancedReporter : public VSW::Reporter { class EnhancedReporter : public VSW::Reporter {
public: public:
EnhancedReporter(CKContext* ctx); EnhancedReporter(CKContext* ctx);
~EnhancedReporter(); ~EnhancedReporter();
public:
void EnableBeep();
void DisableBeep();
protected: protected:
virtual void PrePrint(const YYCC::yycc_char8_t* strl) override; virtual void PrePrint(const YYCC::yycc_char8_t* strl) const override;
private: private:
CKContext* m_Ctx; CKContext* m_Ctx;
bool m_OrderBeep;
};
class Curve2DBuilder {
public:
Curve2DBuilder(CK2dCurve* curve_2d);
~Curve2DBuilder();
public:
const void* GetDataPtr() const;
size_t GetDataLength() const;
private:
void BuildCurve(CK2dCurve* c);
void BuildCurvePoint(CK2dCurvePoint* cp);
std::basic_string<uint8_t> m_Cache;
}; };
/** /**
* @brief Get relative address from given absolute address * @brief Get relative address from given absolute address
* @details This function is used when exporting function pointer into database. * @details This function is used when exporting function pointer into database.
* @param[out] relative_addr_str
* The variable holding relative address result.
* The result is module based relative address like \c xxx.dll+0x00000000.
* @param[in] absolute_addr The absolute address * @param[in] absolute_addr The absolute address
* @return Module based relative address like \c xxx.dll+0x00000000.
*/ */
std::string RelativeAddress(const void* absolute_addr); void RelativeAddress(const EnhancedReporter& reporter, YYCC::yycc_u8string& relative_addr_str, const void* absolute_addr);
//void CopyStrGuid(std::string& dst, const CKGUID& src); void CopyStrGuid(const EnhancedReporter& reporter, YYCC::yycc_u8string& dst, const CKGUID& src);
void CopyGuid(int64_t& dst, const CKGUID& src); void CopyGuid(int64_t& dst, const CKGUID& src);
void CopyCKString(std::string& storage, const char* str, const char* fallback = "<unamed>"); void CopyCKString(
const EnhancedReporter& reporter,
YYCC::yycc_u8string& storage,
const char* str,
UINT code_page,
const YYCC::yycc_char8_t* fallback = YYCC::EncodingHelper::ToUTF8(NULLPTR_CKSTRING)
);
#pragma region Convenient Macros
#define CP_ADDR(dst, src) ::VSW::Materializer::Utilities::RelativeAddress(expctx.reporter, (dst), (src))
#define CP_STR_GUID(dst, src) ::VSW::Materializer::Utilities::CopyStrGuid(expctx.reporter, (dst), (src))
#define CP_GUID(dst, src) ::VSW::Materializer::Utilities::CopyGuid((dst), (src))
#define CP_CKSTR(dst, src, ...) ::VSW::Materializer::Utilities::CopyCKString(expctx.reporter, (dst), (src), expctx.cp, ##__VA_ARGS__)
#pragma endregion
} }

View File

@@ -25,12 +25,19 @@ public:
YYCC::ExceptionHelper::Register(vtobjplugin::VirtoolsMenu::UnhandledExceptionCallback); YYCC::ExceptionHelper::Register(vtobjplugin::VirtoolsMenu::UnhandledExceptionCallback);
#endif #endif
// load config from file
auto& config_manager = VSW::Materializer::PluginMain::ConfigManager::GetSingleton();
config_manager.m_Mgr.Load();
// init plugin info // init plugin info
VSW::Materializer::PluginMain::InitializePluginInfo(); VSW::Materializer::PluginMain::InitializePluginInfo();
return CWinApp::InitInstance(); return CWinApp::InitInstance();
} }
virtual int ExitInstance() override { virtual int ExitInstance() override {
// save config to file
auto& config_manager = VSW::Materializer::PluginMain::ConfigManager::GetSingleton();
config_manager.m_Mgr.Save();
// unregister unhandler exception handler // unregister unhandler exception handler
#ifdef MATERIALIZER_RELEASE #ifdef MATERIALIZER_RELEASE
@@ -45,7 +52,19 @@ CMaterializer theApp;
#else #else
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// register unhandler exception handler
#ifdef MATERIALIZER_RELEASE
YYCC::ExceptionHelper::Register(vtobjplugin::VirtoolsMenu::UnhandledExceptionCallback);
#endif
// Run core code.
VSW::Materializer::StandaloneMain::PlayerMain(argc, argv); VSW::Materializer::StandaloneMain::PlayerMain(argc, argv);
// unregister unhandler exception handler
#ifdef MATERIALIZER_RELEASE
YYCC::ExceptionHelper::Unregister();
#endif
return 0; return 0;
} }

153
script/sqlite_helper.py Normal file
View File

@@ -0,0 +1,153 @@
import typing
import re
class FieldDecl():
c_EnumTuple: typing.ClassVar[tuple[str, ...]] = (
'VSW::DataTypes::ParameterLinkIOType',
'VSW::DataTypes::BehaviorLinkIOType'
)
m_DeclType: str
m_DeclName: str
def __init__(self, decl_type: str, decl_name: str):
self.m_DeclType = decl_type
self.m_DeclName = decl_name
def is_bool(self):
return self.m_DeclType == 'bool'
def is_string(self):
return self.m_DeclType == 'YYCC::yycc_u8string'
def is_blob(self):
return self.m_DeclType == 'BlobDescriptor'
def is_int64(self):
return self.m_DeclType == 'int64_t'
def is_enum(self):
return self.m_DeclType in FieldDecl.c_EnumTuple
class StructDecl():
m_StructName: str
m_StructFields: tuple[FieldDecl, ...]
def __init__(self, name: str, fields: tuple[FieldDecl, ...]):
self.m_StructName = name
self.m_StructFields = fields
def accept_input() -> str:
cache: list[str] = list()
blank_line: bool = False
while True:
recv: str = input("> ")
if len(recv) == 0:
# If double blank line, exit
# Otherwise set blank line flag
if blank_line: break
else: blank_line = True
else:
# Reset blank line flag
blank_line = False
cache.append(recv)
return '\n'.join(cache)
def analyse_input(val: str) -> tuple[StructDecl, ...]:
# result container
ret: list[StructDecl] = list()
# regex for capturing struct declarations
struct_matcher: re.Pattern = re.compile('struct[ \t]+([a-zA-Z0-9_]+)[ \t]+{([^}]*)};')
# regex for capturing struct field declarations
field_matcher: re.Pattern = re.compile('([a-zA-Z0-9_:]+)[ \t]+([a-zA-Z0-9_]+)[ \t]*;')
# capture struct declaration part
found_match: re.Match
for found_match in struct_matcher.finditer(val):
# get struct name
struct_name: str = found_match.group(1)
# analyse struct body
struct_body: str = found_match.group(2)
struct_fields: list[FieldDecl] = []
for ln in struct_body.split('\n'):
# Skip annotation
ln = ln.strip()
if ln.startswith('//'): continue
# Check whether it is declaration
found_field_match: re.Match = field_matcher.match(ln)
if found_field_match is not None:
field_decl_type: str = found_field_match.group(1)
field_decl_name: str = found_field_match.group(2)
struct_fields.append(FieldDecl(field_decl_type, field_decl_name))
# add into result
ret.append(StructDecl(struct_name, tuple(struct_fields)))
return tuple(ret)
def output_result(decls: tuple[StructDecl, ...]) -> None:
# assistant function for sql create table statement
def conv_sql_create_table(decl_pair: FieldDecl) -> str:
if decl_pair.is_string(): return f'[{decl_pair.m_DeclName}] TEXT'
elif decl_pair.is_blob(): return f'[{decl_pair.m_DeclName}] BLOB'
else: return f'[{decl_pair.m_DeclName}] INTEGER'
# assistant function for sql insert statement
def conv_sql_insert(decl_pair: FieldDecl) -> str:
return '?'
# assistant function for c++ bind statement
def conv_cpp(decl_pair: FieldDecl) -> str:
if decl_pair.is_string():
return f'WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.{decl_pair.m_DeclName})));'
elif decl_pair.is_int64():
return f'WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.{decl_pair.m_DeclName}));'
elif decl_pair.is_blob():
return f'WRITER_BIND(sqlite3_bind_blob(WRITER_STMT, WRITER_INDEX, REVEAL_BLOB(data.{decl_pair.m_DeclName})));'
elif decl_pair.is_enum():
return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.{decl_pair.m_DeclName})));'
elif decl_pair.is_bool():
return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_BOOL(data.{decl_pair.m_DeclName})));'
else:
return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.{decl_pair.m_DeclName}));'
ret_sql_drop_table: list[str] = []
ret_sql_create_table: list[str] = []
ret_sql_insert: list[str] = []
ret_cpp_bind: list[tuple[str, str]] = []
for struct_decl in decls:
# generate drop table statement
gen_statement: str = f'DROP TABLE IF EXISTS [{struct_decl.m_StructName}];'
ret_sql_drop_table.append(gen_statement)
# generate sql create table statement
table_string: str = ', '.join(map(conv_sql_create_table, struct_decl.m_StructFields))
gen_statement = f'CREATE TABLE [{struct_decl.m_StructName}] ({table_string});'
ret_sql_create_table.append(gen_statement)
# generate sql insert statement
table_string = ', '.join(map(conv_sql_insert, struct_decl.m_StructFields))
gen_statement = f'INSERT INTO [{struct_decl.m_StructName}] VALUES ({table_string});'
ret_sql_insert.append(gen_statement)
# generate c++ bind statement
bind_string: str = '\n'.join(map(conv_cpp, struct_decl.m_StructFields))
ret_cpp_bind.append((struct_decl.m_StructName, bind_string))
print('========== SQL Drop Table ==========')
for item in ret_sql_drop_table:
print(item)
print('========== SQL Create Table ==========')
for item in ret_sql_create_table:
print(item)
print('========== SQL Insert ==========')
for item in ret_sql_insert:
print(item)
print('========== C++ Bind ==========')
for name, item in ret_cpp_bind:
print(f'===== {name} =====')
print(item)
if __name__ == '__main__':
input_str: str = accept_input()
decls: tuple[StructDecl, ...] = analyse_input(input_str)
output_result(decls)

View File

@@ -18,7 +18,6 @@ FILES
target_include_directories(VSWShared target_include_directories(VSWShared
PUBLIC PUBLIC
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
YYCC::YYCCommonplace
) )
# Setup linked library # Setup linked library
target_link_libraries(VSWShared target_link_libraries(VSWShared

View File

@@ -6,32 +6,36 @@ namespace VSW {
Reporter::Reporter() {} Reporter::Reporter() {}
Reporter::~Reporter() {} Reporter::~Reporter() {}
void Reporter::PrePrint(const YYCC::yycc_char8_t* strl) {} void Reporter::PrePrint(const YYCC::yycc_char8_t* strl) const {}
#define GENERIC_REPORTER_WRITE(ty, data) YYCC::ConsoleHelper::Write(YYCC_U8("[" #ty "] ")); \ #define GENERIC_REPORTER_WRITE(ty, data) YYCC::yycc_u8string cache(YYCC_U8("[" #ty "] ")); \
YYCC::ConsoleHelper::WriteLine(data); cache += data; \
#define GENERIC_REPORTER_FORMAT(ty, data) YYCC::ConsoleHelper::Write(YYCC_U8("[" #ty "] ")); \ this->PrePrint(cache.c_str()); \
va_list argptr; \ YYCC::ConsoleHelper::WriteLine(cache.c_str());
#define GENERIC_REPORTER_FORMAT(ty, data) va_list argptr; \
va_start(argptr, data); \ va_start(argptr, data); \
YYCC::ConsoleHelper::WriteLine(YYCC::StringHelper::VPrintf(data, argptr).c_str()); \ YYCC::yycc_u8string cache(YYCC::StringHelper::VPrintf(data, argptr)); \
cache.insert(0u, YYCC_U8("[" #ty "] ")); \
this->PrePrint(cache.c_str()); \
YYCC::ConsoleHelper::WriteLine(cache.c_str()); \
va_end(argptr); va_end(argptr);
void Reporter::Err(const YYCC::yycc_char8_t* strl) { void Reporter::Err(const YYCC::yycc_char8_t* strl) const {
GENERIC_REPORTER_WRITE(Error, strl); GENERIC_REPORTER_WRITE(Error, strl);
} }
void Reporter::ErrF(const YYCC::yycc_char8_t* fmt, ...) { void Reporter::ErrF(const YYCC::yycc_char8_t* fmt, ...) const {
GENERIC_REPORTER_FORMAT(Error ,fmt); GENERIC_REPORTER_FORMAT(Error ,fmt);
} }
void Reporter::Warn(const YYCC::yycc_char8_t* strl) { void Reporter::Warn(const YYCC::yycc_char8_t* strl) const {
GENERIC_REPORTER_WRITE(Warning, strl); GENERIC_REPORTER_WRITE(Warning, strl);
} }
void Reporter::WarnF(const YYCC::yycc_char8_t* fmt, ...) { void Reporter::WarnF(const YYCC::yycc_char8_t* fmt, ...) const {
GENERIC_REPORTER_FORMAT(Warning ,fmt); GENERIC_REPORTER_FORMAT(Warning ,fmt);
} }
void Reporter::Info(const YYCC::yycc_char8_t* strl) { void Reporter::Info(const YYCC::yycc_char8_t* strl) const {
GENERIC_REPORTER_WRITE(Info, strl); GENERIC_REPORTER_WRITE(Info, strl);
} }
void Reporter::InfoF(const YYCC::yycc_char8_t* fmt, ...) { void Reporter::InfoF(const YYCC::yycc_char8_t* fmt, ...) const {
GENERIC_REPORTER_FORMAT(Info ,fmt); GENERIC_REPORTER_FORMAT(Info ,fmt);
} }

View File

@@ -10,33 +10,32 @@ namespace VSW {
~Reporter(); ~Reporter();
protected: protected:
virtual void PrePrint(const YYCC::yycc_char8_t* strl); virtual void PrePrint(const YYCC::yycc_char8_t* strl) const;
public: public:
void Err(const YYCC::yycc_char8_t* strl); void Err(const YYCC::yycc_char8_t* strl) const;
void ErrF(const YYCC::yycc_char8_t* fmt, ...); void ErrF(const YYCC::yycc_char8_t* fmt, ...) const;
void Warn(const YYCC::yycc_char8_t* strl); void Warn(const YYCC::yycc_char8_t* strl) const;
void WarnF(const YYCC::yycc_char8_t* fmt, ...); void WarnF(const YYCC::yycc_char8_t* fmt, ...) const;
void Info(const YYCC::yycc_char8_t* strl); void Info(const YYCC::yycc_char8_t* strl) const;
void InfoF(const YYCC::yycc_char8_t* fmt, ...); void InfoF(const YYCC::yycc_char8_t* fmt, ...) const;
}; };
namespace DataTypes { namespace DataTypes {
enum class BehaviorLinkIOType : int { enum class BehaviorLinkIOType : int {
Input, INPUT, OUTPUT
Output
}; };
enum class ParameterLinkIOType : int { enum class ParameterLinkIOType : int {
ParameterIn, PIN,
ParameterOut, POUT,
/// @brief When using this, ignore [index] and [input_is_bb], set [input_index] to -1 /// @brief When using this, ignore [index] and [input_is_bb], set [input_index] to -1
ParameterLocal, PLOCAL,
/// @brief When using this, ignore [index] and [input_is_bb], set [input_index] to -1 /// @brief When using this, ignore [index] and [input_is_bb], set [input_index] to -1
ParameterTarget, PTARGET,
/// @brief When using this, ignore [index], and [input_is_bb] will become [input_is_dataarray] /// @brief When using this, ignore [index], and [input_is_bb] will become [input_is_dataarray]
pParameterAttribute PATTR
}; };
} }