From acc7aa190d7bd430d4744108a9d6e4c511d56a04 Mon Sep 17 00:00:00 2001 From: Nathan Brooks Date: Wed, 27 May 2020 21:33:50 -0600 Subject: [PATCH 1/3] Add license manager and client - TrajectoryGenerator constructor and reset now check for an active license - ./license_client -h describes license management --- CMakeLists.txt | 38 +- include/trackjoint/LexActivator.h | 800 +++++++++++ include/trackjoint/LexStatusCodes.h | 360 +++++ include/trackjoint/cxxopts.hpp | 1840 ++++++++++++++++++++++++++ include/trackjoint/license_manager.h | 38 + lib/libLexActivator.so | Bin 0 -> 1476672 bytes src/license_client.cpp | 17 + src/license_manager.cpp | 300 +++++ src/trajectory_generator.cpp | 15 + 9 files changed, 3407 insertions(+), 1 deletion(-) create mode 100644 include/trackjoint/LexActivator.h create mode 100644 include/trackjoint/LexStatusCodes.h create mode 100644 include/trackjoint/cxxopts.hpp create mode 100644 include/trackjoint/license_manager.h create mode 100644 lib/libLexActivator.so create mode 100644 src/license_client.cpp create mode 100644 src/license_manager.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 042200cf..2a364684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,10 +50,29 @@ include_directories( include_directories( include + lib ${catkin_INCLUDE_DIRS} ) set(LIBRARY_NAME trackjoint) + +# License manager +add_library( + ${PROJECT_NAME}_license_manager + src/license_manager.cpp +) +set_target_properties( + ${PROJECT_NAME}_license_manager + PROPERTIES + OUTPUT_NAME license_manager PREFIX "" +) +target_link_libraries( + ${PROJECT_NAME}_license_manager + ${catkin_LIBRARIES} + ${PROJECT_SOURCE_DIR}/lib/libLexActivator.so +) + +# TrackJoint add_library(${LIBRARY_NAME} src/trajectory_generator.cpp src/single_joint_generator.cpp @@ -61,6 +80,7 @@ add_library(${LIBRARY_NAME} ) target_link_libraries( ${LIBRARY_NAME} + ${LIBRARY_NAME}_license_manager ${catkin_LIBRARIES} ) @@ -115,6 +135,22 @@ target_link_libraries( ${catkin_LIBRARIES} ) +# License client +add_executable( + ${PROJECT_NAME}_license_client + src/license_client.cpp +) +set_target_properties( + ${PROJECT_NAME}_license_client + PROPERTIES + OUTPUT_NAME license_client PREFIX "" +) +target_link_libraries( + ${PROJECT_NAME}_license_client + ${LIBRARY_NAME}_license_manager + ${catkin_LIBRARIES} +) + ############# ## Install ## ############# @@ -122,7 +158,7 @@ target_link_libraries( # Mark executables and/or libraries for installation install( TARGETS - ${PROJECT_NAME} ${PROJECT_NAME}_simple_example ${PROJECT_NAME}_streaming_example + ${PROJECT_NAME} ${PROJECT_NAME}_simple_example ${PROJECT_NAME}_streaming_example ${PROJECT_NAME}_license_client ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION diff --git a/include/trackjoint/LexActivator.h b/include/trackjoint/LexActivator.h new file mode 100644 index 00000000..f88c1aba --- /dev/null +++ b/include/trackjoint/LexActivator.h @@ -0,0 +1,800 @@ +/* LexActivator.h */ +#pragma once + +#include +#include "LexStatusCodes.h" +#ifdef _WIN32 +/* +Make sure you're using the MSVC or Intel compilers on Windows. +*/ +#include + +#ifdef LEXACTIVATOR_EXPORTS +#ifdef LEXACTIVATOR_STATIC +#define LEXACTIVATOR_API extern "C" +#else +#define LEXACTIVATOR_API extern "C" __declspec(dllexport) +#endif +#else +#ifdef __cplusplus +#ifdef LEXACTIVATOR_STATIC +#define LEXACTIVATOR_API extern "C" +#else +#define LEXACTIVATOR_API extern "C" __declspec(dllimport) +#endif +#else +#ifdef LEXACTIVATOR_STATIC +#define LEXACTIVATOR_API +#else +#define LEXACTIVATOR_API __declspec(dllimport) +#endif +#endif +#endif + +#if defined(USE_STDCALL_DLL) && !defined(LEXACTIVATOR_STATIC) +#define LA_CC __stdcall +#else +#define LA_CC __cdecl +#endif +typedef const wchar_t* CSTRTYPE; +typedef wchar_t* STRTYPE; +#else +#define LA_CC +#if __GNUC__ >= 4 +#ifdef __cplusplus +#define LEXACTIVATOR_API extern "C" __attribute__((visibility("default"))) +#else +#define LEXACTIVATOR_API __attribute__((visibility("default"))) +#endif +#else +#ifdef __cplusplus +#define LEXACTIVATOR_API extern "C" +#else +#define LEXACTIVATOR_API +#endif +#endif +typedef const char* CSTRTYPE; +typedef char* STRTYPE; +#endif + +typedef void(LA_CC* CallbackType)(uint32_t); + +#define LA_USER ((uint32_t)1) +#define LA_SYSTEM ((uint32_t)2) +#define LA_IN_MEMORY ((uint32_t)4) + +/* + FUNCTION: SetProductFile() + + PURPOSE: Sets the absolute path of the Product.dat file. + + This function must be called on every start of your program + before any other functions are called. + + PARAMETERS: + * filePath - absolute path of the product file (Product.dat) + + RETURN CODES: LA_OK, LA_E_FILE_PATH, LA_E_PRODUCT_FILE + + NOTE: If this function fails to set the path of product file, none of the + other functions will work. +*/ +LEXACTIVATOR_API int LA_CC SetProductFile(CSTRTYPE filePath); + +/* + FUNCTION: SetProductData() + + PURPOSE: Embeds the Product.dat file in the application. + + It can be used instead of SetProductFile() in case you want + to embed the Product.dat file in your application. + + This function must be called on every start of your program + before any other functions are called. + + PARAMETERS: + * productData - content of the Product.dat file + + RETURN CODES: LA_OK, LA_E_PRODUCT_DATA + + NOTE: If this function fails to set the product data, none of the + other functions will work. +*/ +LEXACTIVATOR_API int LA_CC SetProductData(CSTRTYPE productData); + +/* + FUNCTION: SetProductId() + + PURPOSE: Sets the product id of your application. + + This function must be called on every start of your program before + any other functions are called, with the exception of SetProductFile() + or SetProductData() function. + + PARAMETERS: + * productId - the unique product id of your application as mentioned + on the product page in the dashboard. + + * flags - depending upon whether your application requires admin/root + permissions to run or not, this parameter can have one of the following + values: LA_SYSTEM, LA_USER, LA_IN_MEMORY + + RETURN CODES: LA_OK, LA_E_WMIC, LA_E_PRODUCT_FILE, LA_E_PRODUCT_DATA, LA_E_PRODUCT_ID, + LA_E_SYSTEM_PERMISSION + + NOTE: If this function fails to set the product id, none of the other + functions will work. +*/ +LEXACTIVATOR_API int LA_CC SetProductId(CSTRTYPE productId, uint32_t flags); + +/* + FUNCTION: SetLicenseKey() + + PURPOSE: Sets the license key required to activate the license. + + PARAMETERS: + * licenseKey - a valid license key. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY +*/ +LEXACTIVATOR_API int LA_CC SetLicenseKey(CSTRTYPE licenseKey); + +/* + FUNCTION: SetLicenseUserCredential() + + PURPOSE: Sets the license user email and password for authentication. + + This function must be called before ActivateLicense() or IsLicenseGenuine() + function if 'requireAuthentication' property of the license is set to true. + + PARAMETERS: + * email - user email address. + * password - user password. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY +*/ +LEXACTIVATOR_API int LA_CC SetLicenseUserCredential(CSTRTYPE email, CSTRTYPE password); + +/* + FUNCTION: SetLicenseCallback() + + PURPOSE: Sets server sync callback function. + + Whenever the server sync occurs in a separate thread, and server returns the response, + license callback function gets invoked with the following status codes: + LA_OK, LA_EXPIRED, LA_SUSPENDED, + LA_E_REVOKED, LA_E_ACTIVATION_NOT_FOUND, LA_E_MACHINE_FINGERPRINT + LA_E_AUTHENTICATION_FAILED, LA_E_COUNTRY, LA_E_INET, LA_E_SERVER, + LA_E_RATE_LIMIT, LA_E_IP + + PARAMETERS: + * callback - name of the callback function + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY +*/ +LEXACTIVATOR_API int LA_CC SetLicenseCallback(CallbackType callback); +/* + FUNCTION: SetActivationMetadata() + + PURPOSE: Sets the activation metadata. + + The metadata appears along with the activation details of the license + in dashboard. + + PARAMETERS: + * key - string of maximum length 256 characters with utf-8 encoding. + * value - string of maximum length 256 characters with utf-8 encoding. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_METADATA_KEY_LENGTH, + LA_E_METADATA_VALUE_LENGTH, LA_E_ACTIVATION_METADATA_LIMIT +*/ +LEXACTIVATOR_API int LA_CC SetActivationMetadata(CSTRTYPE key, CSTRTYPE value); + +/* + FUNCTION: SetTrialActivationMetadata() + + PURPOSE: Sets the trial activation metadata. + + The metadata appears along with the trial activation details of the product + in dashboard. + + PARAMETERS: + * key - string of maximum length 256 characters with utf-8 encoding. + * value - string of maximum length 256 characters with utf-8 encoding. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_METADATA_KEY_LENGTH, + LA_E_METADATA_VALUE_LENGTH, LA_E_TRIAL_ACTIVATION_METADATA_LIMIT +*/ +LEXACTIVATOR_API int LA_CC SetTrialActivationMetadata(CSTRTYPE key, CSTRTYPE value); + +/* + FUNCTION: SetAppVersion() + + PURPOSE: Sets the current app version of your application. + + The app version appears along with the activation details in dashboard. It + is also used to generate app analytics. + + PARAMETERS: + * appVersion - string of maximum length 256 characters with utf-8 encoding. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_APP_VERSION_LENGTH +*/ +LEXACTIVATOR_API int LA_CC SetAppVersion(CSTRTYPE appVersion); + +/* + FUNCTION: SetOfflineActivationRequestMeterAttributeUses() + + PURPOSE: Sets the meter attribute uses for the offline activation request. + + This function should only be called before GenerateOfflineActivationRequest() + function to set the meter attributes in case of offline activation. + + PARAMETERS: + * name - name of the meter attribute + * uses - the uses value + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY + +*/ +LEXACTIVATOR_API int LA_CC SetOfflineActivationRequestMeterAttributeUses(CSTRTYPE name, uint32_t uses); + +/* + FUNCTION: SetNetworkProxy() + + PURPOSE: Sets the network proxy to be used when contacting Cryptlex servers. + + The proxy format should be: [protocol://][username:password@]machine[:port] + + Following are some examples of the valid proxy strings: + - http://127.0.0.1:8000/ + - http://user:pass@127.0.0.1:8000/ + - socks5://127.0.0.1:8000/ + + PARAMETERS: + * proxy - proxy string having correct proxy format + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_NET_PROXY + + NOTE: Proxy settings of the computer are automatically detected. So, in most of the + cases you don't need to care whether your user is behind a proxy server or not. +*/ +LEXACTIVATOR_API int LA_CC SetNetworkProxy(CSTRTYPE proxy); + +/* + FUNCTION: SetCryptlexHost() + + PURPOSE: In case you are running Cryptlex on-premise, you can set the + host for your on-premise server. + + PARAMETERS: + * host - the address of the Cryptlex on-premise server + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_HOST_URL +*/ +LEXACTIVATOR_API int LA_CC SetCryptlexHost(CSTRTYPE host); + +/* + FUNCTION: GetProductMetadata() + + PURPOSE: Gets the product metadata as set in the dashboard. + + This is available for trial as well as license activations. + + PARAMETERS: + * key - key to retrieve the value + * value - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the value parameter + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_METADATA_KEY_NOT_FOUND, LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetProductMetadata(CSTRTYPE key, STRTYPE value, uint32_t length); + +/* + FUNCTION: GetLicenseMetadata() + + PURPOSE: Gets the license metadata as set in the dashboard. + + PARAMETERS: + * key - key to retrieve the value + * value - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the value parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METADATA_KEY_NOT_FOUND, LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseMetadata(CSTRTYPE key, STRTYPE value, uint32_t length); + +/* + FUNCTION: GetLicenseMeterAttribute() + + PURPOSE: Gets the license meter attribute allowed uses and total uses. + + PARAMETERS: + * name - name of the meter attribute + * allowedUses - pointer to the integer that receives the value + * totalUses - pointer to the integer that receives the value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METER_ATTRIBUTE_NOT_FOUND +*/ +LEXACTIVATOR_API int LA_CC GetLicenseMeterAttribute(CSTRTYPE name, uint32_t* allowedUses, uint32_t* totalUses); + +/* + FUNCTION: GetLicenseKey() + + PURPOSE: Gets the license key used for activation. + + PARAMETERS: + * licenseKey - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the licenseKey parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseKey(STRTYPE licenseKey, uint32_t length); + +/* + FUNCTION: GetLicenseExpiryDate() + + PURPOSE: Gets the license expiry date timestamp. + + PARAMETERS: + * expiryDate - pointer to the integer that receives the value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED +*/ +LEXACTIVATOR_API int LA_CC GetLicenseExpiryDate(uint32_t* expiryDate); + +/* + FUNCTION: GetLicenseUserEmail() + + PURPOSE: Gets the email associated with license user. + + PARAMETERS: + * email - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the email parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED, + LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseUserEmail(STRTYPE email, uint32_t length); + +/* + FUNCTION: GetLicenseUserName() + + PURPOSE: Gets the name associated with the license user. + + PARAMETERS: + * name - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the name parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED, + LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseUserName(STRTYPE name, uint32_t length); + +/* + FUNCTION: GetLicenseUserCompany() + + PURPOSE: Gets the company associated with the license user. + + PARAMETERS: + * company - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the company parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED, + LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseUserCompany(STRTYPE company, uint32_t length); + +/* + FUNCTION: GetLicenseUserMetadata() + + PURPOSE: Gets the metadata associated with the license user. + + PARAMETERS: + * key - key to retrieve the value + * value - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the value parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METADATA_KEY_NOT_FOUND, LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseUserMetadata(CSTRTYPE key, STRTYPE value, uint32_t length); + +/* + FUNCTION: GetLicenseType() + + PURPOSE: Gets the license type (node-locked or hosted-floating). + + PARAMETERS: + * licenseType - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the licenseType parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED, + LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetLicenseType(STRTYPE licenseType, uint32_t length); + +/* + FUNCTION: GetActivationMetadata() + + PURPOSE: Gets the activation metadata. + + PARAMETERS: + * key - key to retrieve the value + * value - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the value parameter + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_METADATA_KEY_NOT_FOUND, LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetActivationMetadata(CSTRTYPE key, STRTYPE value, uint32_t length); + +/* + FUNCTION: GetActivationMeterAttributeUses() + + PURPOSE: Gets the meter attribute uses consumed by the activation. + + PARAMETERS: + * name - name of the meter attribute + * allowedUses - pointer to the integer that receives the value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METER_ATTRIBUTE_NOT_FOUND +*/ +LEXACTIVATOR_API int LA_CC GetActivationMeterAttributeUses(CSTRTYPE name, uint32_t* uses); + +/* + FUNCTION: GetServerSyncGracePeriodExpiryDate() + + PURPOSE: Gets the server sync grace period expiry date timestamp. + + PARAMETERS: + * expiryDate - pointer to the integer that receives the value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED +*/ +LEXACTIVATOR_API int LA_CC GetServerSyncGracePeriodExpiryDate(uint32_t* expiryDate); + +/* + FUNCTION: GetTrialActivationMetadata() + + PURPOSE: Gets the trial activation metadata. + + PARAMETERS: + * key - key to retrieve the value + * value - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the value parameter + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_METADATA_KEY_NOT_FOUND, LA_E_BUFFER_SIZE +*/ + +LEXACTIVATOR_API int LA_CC GetTrialActivationMetadata(CSTRTYPE key, STRTYPE value, uint32_t length); + +/* + FUNCTION: GetTrialExpiryDate() + + PURPOSE: Gets the trial expiry date timestamp. + + PARAMETERS: + * trialExpiryDate - pointer to the integer that receives the value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED +*/ +LEXACTIVATOR_API int LA_CC GetTrialExpiryDate(uint32_t* trialExpiryDate); + +/* + FUNCTION: GetTrialId() + + PURPOSE: Gets the trial activation id. Used in case of trial extension. + + PARAMETERS: + * trialId - pointer to a buffer that receives the value of the string + * length - size of the buffer pointed to by the value parameter + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME, LA_E_TIME_MODIFIED, + LA_E_BUFFER_SIZE +*/ +LEXACTIVATOR_API int LA_CC GetTrialId(STRTYPE trialId, uint32_t length); + +/* + FUNCTION: GetLocalTrialExpiryDate() + + PURPOSE: Gets the trial expiry date timestamp. + + PARAMETERS: + * trialExpiryDate - pointer to the integer that receives the value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME_MODIFIED +*/ +LEXACTIVATOR_API int LA_CC GetLocalTrialExpiryDate(uint32_t* trialExpiryDate); + +/* + FUNCTION: CheckForReleaseUpdate() + + PURPOSE: Checks whether a new release is available for the product. + + This function should only be used if you manage your releases through + Cryptlex release management API. + + PARAMETERS: + * platform - release platform e.g. windows, macos, linux + * version - current release version + * channel - release channel e.g. stable + * releaseUpdateCallback - name of the callback function. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_RELEASE_VERSION_FORMAT +*/ +LEXACTIVATOR_API int LA_CC CheckForReleaseUpdate(CSTRTYPE platform, CSTRTYPE version, CSTRTYPE channel, + CallbackType releaseUpdateCallback); + +/* + FUNCTION: ActivateLicense() + + PURPOSE: Activates the license by contacting the Cryptlex servers. It + validates the key and returns with encrypted and digitally signed token + which it stores and uses to activate your application. + + This function should be executed at the time of registration, ideally on + a button click. + + RETURN CODES: LA_OK, LA_EXPIRED, LA_SUSPENDED, LA_E_REVOKED, LA_FAIL, LA_E_PRODUCT_ID, + LA_E_INET, LA_E_VM, LA_E_TIME, LA_E_ACTIVATION_LIMIT, LA_E_SERVER, LA_E_CLIENT, + LA_E_AUTHENTICATION_FAILED, LA_E_LICENSE_TYPE, LA_E_COUNTRY, LA_E_IP, LA_E_RATE_LIMIT, LA_E_LICENSE_KEY +*/ +LEXACTIVATOR_API int LA_CC ActivateLicense(); + +/* + FUNCTION: ActivateLicenseOffline() + + PURPOSE: Activates your licenses using the offline activation response file. + + PARAMETERS: + * filePath - path of the offline activation response file. + + RETURN CODES: LA_OK, LA_EXPIRED, LA_FAIL, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_OFFLINE_RESPONSE_FILE + LA_E_VM, LA_E_TIME, LA_E_FILE_PATH, LA_E_OFFLINE_RESPONSE_FILE_EXPIRED +*/ +LEXACTIVATOR_API int LA_CC ActivateLicenseOffline(CSTRTYPE filePath); + +/* + FUNCTION: GenerateOfflineActivationRequest() + + PURPOSE: Generates the offline activation request needed for generating + offline activation response in the dashboard. + + PARAMETERS: + * filePath - path of the file for the offline request. + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_FILE_PERMISSION +*/ +LEXACTIVATOR_API int LA_CC GenerateOfflineActivationRequest(CSTRTYPE filePath); + +/* + FUNCTION: DeactivateLicense() + + PURPOSE: Deactivates the license activation and frees up the corresponding activation + slot by contacting the Cryptlex servers. + + This function should be executed at the time of de-registration, ideally on + a button click. + + RETURN CODES: LA_OK, LA_E_DEACTIVATION_LIMIT, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME + LA_E_LICENSE_KEY, LA_E_INET, LA_E_SERVER, LA_E_RATE_LIMIT, LA_E_TIME_MODIFIED +*/ +LEXACTIVATOR_API int LA_CC DeactivateLicense(); + +/* + FUNCTION: GenerateOfflineDeactivationRequest() + + PURPOSE: Generates the offline deactivation request needed for deactivation of + the license in the dashboard and deactivates the license locally. + + A valid offline deactivation file confirms that the license has been successfully + deactivated on the user's machine. + + PARAMETERS: + * filePath - path of the file for the offline request. + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_FILE_PERMISSION, + LA_E_TIME, LA_E_TIME_MODIFIED +*/ +LEXACTIVATOR_API int LA_CC GenerateOfflineDeactivationRequest(CSTRTYPE filePath); + +/* + FUNCTION: IsLicenseGenuine() + + PURPOSE: It verifies whether your app is genuinely activated or not. The verification is + done locally by verifying the cryptographic digital signature fetched at the time of + activation. + + After verifying locally, it schedules a server check in a separate thread. After the + first server sync it periodically does further syncs at a frequency set for the license. + + In case server sync fails due to network error, and it continues to fail for fixed + number of days (grace period), the function returns LA_GRACE_PERIOD_OVER instead of LA_OK. + + This function must be called on every start of your program to verify the activation + of your app. + + RETURN CODES: LA_OK, LA_EXPIRED, LA_SUSPENDED, LA_GRACE_PERIOD_OVER, LA_FAIL, + LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_TIME, LA_E_TIME_MODIFIED + + NOTE: If application was activated offline using ActivateLicenseOffline() function, you + may want to set grace period to 0 to ignore grace period. +*/ +LEXACTIVATOR_API int LA_CC IsLicenseGenuine(); + +/* + FUNCTION: IsLicenseValid() + + PURPOSE: It verifies whether your app is genuinely activated or not. The verification is + done locally by verifying the cryptographic digital signature fetched at the time of + activation. + + This is just an auxiliary function which you may use in some specific cases, when you + want to skip the server sync. + + RETURN CODES: LA_OK, LA_EXPIRED, LA_SUSPENDED, LA_GRACE_PERIOD_OVER, LA_FAIL, + LA_E_PRODUCT_ID, LA_E_LICENSE_KEY, LA_E_TIME, LA_E_TIME_MODIFIED + + NOTE: You may want to set grace period to 0 to ignore grace period. +*/ +LEXACTIVATOR_API int LA_CC IsLicenseValid(); + +/* + FUNCTION: ActivateTrial() + + PURPOSE: Starts the verified trial in your application by contacting the + Cryptlex servers. + + This function should be executed when your application starts first time on + the user's computer, ideally on a button click. + + RETURN CODES: LA_OK, LA_TRIAL_EXPIRED, LA_FAIL, LA_E_PRODUCT_ID, LA_E_INET, + LA_E_VM, LA_E_TIME, LA_E_SERVER, LA_E_CLIENT, LA_E_COUNTRY, LA_E_IP, LA_E_RATE_LIMIT +*/ +LEXACTIVATOR_API int LA_CC ActivateTrial(); + +/* + FUNCTION: ActivateTrialOffline() + + PURPOSE: Activates your trial using the offline activation response file. + + PARAMETERS: + * filePath - path of the offline activation response file. + + RETURN CODES: LA_OK, LA_TRIAL_EXPIRED, LA_FAIL, LA_E_PRODUCT_ID, LA_E_OFFLINE_RESPONSE_FILE + LA_E_VM, LA_E_TIME, LA_E_FILE_PATH, LA_E_OFFLINE_RESPONSE_FILE_EXPIRED +*/ +LEXACTIVATOR_API int LA_CC ActivateTrialOffline(CSTRTYPE filePath); + +/* + FUNCTION: GenerateOfflineTrialActivationRequest() + + PURPOSE: Generates the offline trial activation request needed for generating + offline trial activation response in the dashboard. + + PARAMETERS: + * filePath - path of the file for the offline request. + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_FILE_PERMISSION +*/ +LEXACTIVATOR_API int LA_CC GenerateOfflineTrialActivationRequest(CSTRTYPE filePath); + +/* + FUNCTION: IsTrialGenuine() + + PURPOSE: It verifies whether trial has started and is genuine or not. The + verification is done locally by verifying the cryptographic digital signature + fetched at the time of trial activation. + + This function must be called on every start of your program during the trial period. + + RETURN CODES: LA_OK, LA_TRIAL_EXPIRED, LA_FAIL, LA_E_TIME, LA_E_PRODUCT_ID, LA_E_TIME_MODIFIED + +*/ +LEXACTIVATOR_API int LA_CC IsTrialGenuine(); + +/* + FUNCTION: ActivateLocalTrial() + + PURPOSE: Starts the local(unverified) trial. + + This function should be executed when your application starts first time on + the user's computer. + + PARAMETERS: + * trialLength - trial length in days + + RETURN CODES: LA_OK, LA_LOCAL_TRIAL_EXPIRED, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME_MODIFIED + + NOTE: The function is only meant for local(unverified) trials. +*/ +LEXACTIVATOR_API int LA_CC ActivateLocalTrial(uint32_t trialLength); + +/* + FUNCTION: IsLocalTrialGenuine() + + PURPOSE: It verifies whether trial has started and is genuine or not. The + verification is done locally. + + This function must be called on every start of your program during the trial period. + + RETURN CODES: LA_OK, LA_LOCAL_TRIAL_EXPIRED, LA_FAIL, LA_E_PRODUCT_ID, + LA_E_TIME_MODIFIED + + NOTE: The function is only meant for local(unverified) trials. +*/ +LEXACTIVATOR_API int LA_CC IsLocalTrialGenuine(); + +/* + FUNCTION: ExtendLocalTrial() + + PURPOSE: Extends the local trial. + + PARAMETERS: + * trialExtensionLength - number of days to extend the trial + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_TIME_MODIFIED + + NOTE: The function is only meant for local(unverified) trials. +*/ +LEXACTIVATOR_API int LA_CC ExtendLocalTrial(uint32_t trialExtensionLength); + +/* + FUNCTION: IncrementActivationMeterAttributeUses() + + PURPOSE: Increments the meter attribute uses of the activation. + + PARAMETERS: + * name - name of the meter attribute + * increment - the increment value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METER_ATTRIBUTE_NOT_FOUND, + LA_E_INET, LA_E_TIME, LA_E_SERVER, LA_E_CLIENT, LA_E_METER_ATTRIBUTE_USES_LIMIT_REACHED, + LA_E_AUTHENTICATION_FAILED, LA_E_COUNTRY, LA_E_IP, LA_E_RATE_LIMIT, LA_E_LICENSE_KEY + +*/ +LEXACTIVATOR_API int LA_CC IncrementActivationMeterAttributeUses(CSTRTYPE name, uint32_t increment); + +/* + FUNCTION: DecrementActivationMeterAttributeUses() + + PURPOSE: Decrements the meter attribute uses of the activation. + + PARAMETERS: + * name - name of the meter attribute + * decrement - the decrement value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METER_ATTRIBUTE_NOT_FOUND, + LA_E_INET, LA_E_TIME, LA_E_SERVER, LA_E_CLIENT, LA_E_RATE_LIMIT, LA_E_LICENSE_KEY, + LA_E_AUTHENTICATION_FAILED, LA_E_COUNTRY, LA_E_IP, LA_E_ACTIVATION_NOT_FOUND + + NOTE: If the decrement is more than the current uses, it resets the uses to 0. +*/ +LEXACTIVATOR_API int LA_CC DecrementActivationMeterAttributeUses(CSTRTYPE name, uint32_t decrement); + +/* + FUNCTION: ResetActivationMeterAttributeUses() + + PURPOSE: Resets the meter attribute uses consumed by the activation. + + PARAMETERS: + * name - name of the meter attribute + * decrement - the decrement value + + RETURN CODES: LA_OK, LA_FAIL, LA_E_PRODUCT_ID, LA_E_METER_ATTRIBUTE_NOT_FOUND, + LA_E_INET, LA_E_TIME, LA_E_SERVER, LA_E_CLIENT, LA_E_RATE_LIMIT, LA_E_LICENSE_KEY, + LA_E_AUTHENTICATION_FAILED, LA_E_COUNTRY, LA_E_IP, LA_E_ACTIVATION_NOT_FOUND +*/ +LEXACTIVATOR_API int LA_CC ResetActivationMeterAttributeUses(CSTRTYPE name); + +/* + FUNCTION: Reset() + + PURPOSE: Resets the activation and trial data stored in the machine. + + This function is meant for developer testing only. + + RETURN CODES: LA_OK, LA_E_PRODUCT_ID + + NOTE: The function does not reset local(unverified) trial data. +*/ +LEXACTIVATOR_API int LA_CC Reset(); diff --git a/include/trackjoint/LexStatusCodes.h b/include/trackjoint/LexStatusCodes.h new file mode 100644 index 00000000..5e198a3a --- /dev/null +++ b/include/trackjoint/LexStatusCodes.h @@ -0,0 +1,360 @@ +#ifndef LEX_STATUS_CODES_H +#define LEX_STATUS_CODES_H + +enum LexStatusCodes +{ + /* + CODE: LA_OK + + MESSAGE: Success code. + */ + LA_OK = 0, + + /* + CODE: LA_FAIL + + MESSAGE: Failure code. + */ + LA_FAIL = 1, + + /* + CODE: LA_EXPIRED + + MESSAGE: The license has expired or system time has been tampered + with. Ensure your date and time settings are correct. + */ + LA_EXPIRED = 20, + + /* + CODE: LA_SUSPENDED + + MESSAGE: The license has been suspended. + */ + LA_SUSPENDED = 21, + + /* + CODE: LA_GRACE_PERIOD_OVER + + MESSAGE: The grace period for server sync is over. + */ + LA_GRACE_PERIOD_OVER = 22, + + /* + CODE: LA_TRIAL_EXPIRED + + MESSAGE: The trial has expired or system time has been tampered + with. Ensure your date and time settings are correct. + */ + LA_TRIAL_EXPIRED = 25, + + /* + CODE: LA_LOCAL_TRIAL_EXPIRED + + MESSAGE: The local trial has expired or system time has been tampered + with. Ensure your date and time settings are correct. + */ + LA_LOCAL_TRIAL_EXPIRED = 26, + + /* + CODE: LA_RELEASE_UPDATE_AVAILABLE + + MESSAGE: A new update is available for the product. This means a new release has + been published for the product. + */ + LA_RELEASE_UPDATE_AVAILABLE = 30, + + /* + CODE: LA_RELEASE_NO_UPDATE_AVAILABLE + + MESSAGE: No new update is available for the product. The current version is latest. + */ + LA_RELEASE_NO_UPDATE_AVAILABLE = 31, + + /* + CODE: LA_E_FILE_PATH + + MESSAGE: Invalid file path. + */ + LA_E_FILE_PATH = 40, + + /* + CODE: LA_E_PRODUCT_FILE + + MESSAGE: Invalid or corrupted product file. + */ + LA_E_PRODUCT_FILE = 41, + + /* + CODE: LA_E_PRODUCT_DATA + + MESSAGE: Invalid product data. + */ + LA_E_PRODUCT_DATA = 42, + + /* + CODE: LA_E_PRODUCT_ID + + MESSAGE: The product id is incorrect. + */ + LA_E_PRODUCT_ID = 43, + + /* + CODE: LA_E_SYSTEM_PERMISSION + + MESSAGE: Insufficent system permissions. Occurs when LA_SYSTEM flag is used + but application is not run with admin privileges. + */ + LA_E_SYSTEM_PERMISSION = 44, + + /* + CODE: LA_E_FILE_PERMISSION + + MESSAGE: No permission to write to file. + */ + LA_E_FILE_PERMISSION = 45, + + /* + CODE: LA_E_WMIC + + MESSAGE: Fingerprint couldn't be generated because Windows Management + Instrumentation (WMI) service has been disabled. This error is specific + to Windows only. + */ + LA_E_WMIC = 46, + + /* + CODE: LA_E_TIME + + MESSAGE: The difference between the network time and the system time is + more than allowed clock offset. + */ + LA_E_TIME = 47, + + /* + CODE: LA_E_INET + + MESSAGE: Failed to connect to the server due to network error. + */ + LA_E_INET = 48, + + /* + CODE: LA_E_NET_PROXY + + MESSAGE: Invalid network proxy. + */ + LA_E_NET_PROXY = 49, + + /* + CODE: LA_E_HOST_URL + + MESSAGE: Invalid Cryptlex host url. + */ + LA_E_HOST_URL = 50, + + /* + CODE: LA_E_BUFFER_SIZE + + MESSAGE: The buffer size was smaller than required. + */ + LA_E_BUFFER_SIZE = 51, + + /* + CODE: LA_E_APP_VERSION_LENGTH + + MESSAGE: App version length is more than 256 characters. + */ + LA_E_APP_VERSION_LENGTH = 52, + + /* + CODE: LA_E_REVOKED + + MESSAGE: The license has been revoked. + */ + LA_E_REVOKED = 53, + + /* + CODE: LA_E_LICENSE_KEY + + MESSAGE: Invalid license key. + */ + LA_E_LICENSE_KEY = 54, + + /* + CODE: LA_E_LICENSE_TYPE + + MESSAGE: Invalid license type. Make sure floating license + is not being used. + */ + LA_E_LICENSE_TYPE = 55, + + /* + CODE: LA_E_OFFLINE_RESPONSE_FILE + + MESSAGE: Invalid offline activation response file. + */ + LA_E_OFFLINE_RESPONSE_FILE = 56, + + /* + CODE: LA_E_OFFLINE_RESPONSE_FILE_EXPIRED + + MESSAGE: The offline activation response has expired. + */ + LA_E_OFFLINE_RESPONSE_FILE_EXPIRED = 57, + + /* + CODE: LA_E_ACTIVATION_LIMIT + + MESSAGE: The license has reached it's allowed activations limit. + */ + LA_E_ACTIVATION_LIMIT = 58, + + /* + CODE: LA_E_ACTIVATION_NOT_FOUND + + MESSAGE: The license activation was deleted on the server. + */ + LA_E_ACTIVATION_NOT_FOUND = 59, + + /* + CODE: LA_E_DEACTIVATION_LIMIT + + MESSAGE: The license has reached it's allowed deactivations limit. + */ + LA_E_DEACTIVATION_LIMIT = 60, + + /* + CODE: LA_E_TRIAL_NOT_ALLOWED + + MESSAGE: Trial not allowed for the product. + */ + LA_E_TRIAL_NOT_ALLOWED = 61, + + /* + CODE: LA_E_TRIAL_ACTIVATION_LIMIT + + MESSAGE: Your account has reached it's trial activations limit. + */ + LA_E_TRIAL_ACTIVATION_LIMIT = 62, + + /* + CODE: LA_E_MACHINE_FINGERPRINT + + MESSAGE: Machine fingerprint has changed since activation. + */ + LA_E_MACHINE_FINGERPRINT = 63, + + /* + CODE: LA_E_METADATA_KEY_LENGTH + + MESSAGE: Metadata key length is more than 256 characters. + */ + LA_E_METADATA_KEY_LENGTH = 64, + + /* + CODE: LA_E_METADATA_VALUE_LENGTH + + MESSAGE: Metadata value length is more than 256 characters. + */ + LA_E_METADATA_VALUE_LENGTH = 65, + + /* + CODE: LA_E_ACTIVATION_METADATA_LIMIT + + MESSAGE: The license has reached it's metadata fields limit. + */ + LA_E_ACTIVATION_METADATA_LIMIT = 66, + + /* + CODE: LA_E_TRIAL_ACTIVATION_METADATA_LIMIT + + MESSAGE: The trial has reached it's metadata fields limit. + */ + LA_E_TRIAL_ACTIVATION_METADATA_LIMIT = 67, + + /* + CODE: LA_E_METADATA_KEY_NOT_FOUND + + MESSAGE: The metadata key does not exist. + */ + LA_E_METADATA_KEY_NOT_FOUND = 68, + + /* + CODE: LA_E_TIME_MODIFIED + + MESSAGE: The system time has been tampered (backdated). + */ + LA_E_TIME_MODIFIED = 69, + + /* + CODE: LA_E_RELEASE_VERSION_FORMAT + + MESSAGE: Invalid version format. + */ + LA_E_RELEASE_VERSION_FORMAT = 70, + + /* + CODE: LA_E_AUTHENTICATION_FAILED + + MESSAGE: Incorrect email or password. + */ + LA_E_AUTHENTICATION_FAILED = 71, + + /* + CODE: LA_E_METER_ATTRIBUTE_NOT_FOUND + + MESSAGE: The meter attribute does not exist. + */ + LA_E_METER_ATTRIBUTE_NOT_FOUND = 72, + + /* + CODE: LA_E_METER_ATTRIBUTE_USES_LIMIT_REACHED + + MESSAGE: The meter attribute has reached it's usage limit. + */ + LA_E_METER_ATTRIBUTE_USES_LIMIT_REACHED = 73, + + /* + CODE: LA_E_VM + + MESSAGE: Application is being run inside a virtual machine / hypervisor, + and activation has been disallowed in the VM. + */ + LA_E_VM = 80, + + /* + CODE: LA_E_COUNTRY + + MESSAGE: Country is not allowed. + */ + LA_E_COUNTRY = 81, + + /* + CODE: LA_E_IP + + MESSAGE: IP address is not allowed. + */ + LA_E_IP = 82, + + /* + CODE: LA_E_RATE_LIMIT + + MESSAGE: Rate limit for API has reached, try again later. + */ + LA_E_RATE_LIMIT = 90, + + /* + CODE: LA_E_SERVER + + MESSAGE: Server error. + */ + LA_E_SERVER = 91, + + /* + CODE: LA_E_CLIENT + + MESSAGE: Client error. + */ + LA_E_CLIENT = 92 +}; + +#endif // LEX_STATUS_CODES_H diff --git a/include/trackjoint/cxxopts.hpp b/include/trackjoint/cxxopts.hpp new file mode 100644 index 00000000..e7de9a40 --- /dev/null +++ b/include/trackjoint/cxxopts.hpp @@ -0,0 +1,1840 @@ +/* + +Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef CXXOPTS_HPP_INCLUDED +#define CXXOPTS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cpp_lib_optional +#include +#define CXXOPTS_HAS_OPTIONAL +#endif + +#ifndef CXXOPTS_VECTOR_DELIMITER +#define CXXOPTS_VECTOR_DELIMITER ',' +#endif + +#define CXXOPTS__VERSION_MAJOR 2 +#define CXXOPTS__VERSION_MINOR 2 +#define CXXOPTS__VERSION_PATCH 0 + +namespace cxxopts +{ +static constexpr struct +{ + uint8_t major, minor, patch; +} version = { CXXOPTS__VERSION_MAJOR, CXXOPTS__VERSION_MINOR, CXXOPTS__VERSION_PATCH }; +} + +// when we ask cxxopts to use Unicode, help strings are processed using ICU, +// which results in the correct lengths being computed for strings when they +// are formatted for the help output +// it is necessary to make sure that can be found by the +// compiler, and that icu-uc is linked in to the binary. + +#ifdef CXXOPTS_USE_UNICODE +#include + +namespace cxxopts +{ +typedef icu::UnicodeString String; + +inline String toLocalString(std::string s) +{ + return icu::UnicodeString::fromUTF8(std::move(s)); +} + +class UnicodeStringIterator : public std::iterator +{ +public: + UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) : s(string), i(pos) + { + } + + value_type operator*() const + { + return s->char32At(i); + } + + bool operator==(const UnicodeStringIterator& rhs) const + { + return s == rhs.s && i == rhs.i; + } + + bool operator!=(const UnicodeStringIterator& rhs) const + { + return !(*this == rhs); + } + + UnicodeStringIterator& operator++() + { + ++i; + return *this; + } + + UnicodeStringIterator operator+(int32_t v) + { + return UnicodeStringIterator(s, i + v); + } + +private: + const icu::UnicodeString* s; + int32_t i; +}; + +inline String& stringAppend(String& s, String a) +{ + return s.append(std::move(a)); +} + +inline String& stringAppend(String& s, int n, UChar32 c) +{ + for (int i = 0; i != n; ++i) + { + s.append(c); + } + + return s; +} + +template +String& stringAppend(String& s, Iterator begin, Iterator end) +{ + while (begin != end) + { + s.append(*begin); + ++begin; + } + + return s; +} + +inline size_t stringLength(const String& s) +{ + return s.length(); +} + +inline std::string toUTF8String(const String& s) +{ + std::string result; + s.toUTF8String(result); + + return result; +} + +inline bool empty(const String& s) +{ + return s.isEmpty(); +} +} + +namespace std +{ +inline cxxopts::UnicodeStringIterator begin(const icu::UnicodeString& s) +{ + return cxxopts::UnicodeStringIterator(&s, 0); +} + +inline cxxopts::UnicodeStringIterator end(const icu::UnicodeString& s) +{ + return cxxopts::UnicodeStringIterator(&s, s.length()); +} +} + +// ifdef CXXOPTS_USE_UNICODE +#else + +namespace cxxopts +{ +typedef std::string String; + +template +T toLocalString(T&& t) +{ + return std::forward(t); +} + +inline size_t stringLength(const String& s) +{ + return s.length(); +} + +inline String& stringAppend(String& s, String a) +{ + return s.append(std::move(a)); +} + +inline String& stringAppend(String& s, size_t n, char c) +{ + return s.append(n, c); +} + +template +String& stringAppend(String& s, Iterator begin, Iterator end) +{ + return s.append(begin, end); +} + +template +std::string toUTF8String(T&& t) +{ + return std::forward(t); +} + +inline bool empty(const std::string& s) +{ + return s.empty(); +} +} + +// ifdef CXXOPTS_USE_UNICODE +#endif + +namespace cxxopts +{ +namespace +{ +#ifdef _WIN32 +const std::string LQUOTE("\'"); +const std::string RQUOTE("\'"); +#else +const std::string LQUOTE("‘"); +const std::string RQUOTE("’"); +#endif +} + +class Value : public std::enable_shared_from_this +{ +public: + virtual ~Value() = default; + + virtual std::shared_ptr clone() const = 0; + + virtual void parse(const std::string& text) const = 0; + + virtual void parse() const = 0; + + virtual bool has_default() const = 0; + + virtual bool is_container() const = 0; + + virtual bool has_implicit() const = 0; + + virtual std::string get_default_value() const = 0; + + virtual std::string get_implicit_value() const = 0; + + virtual std::shared_ptr default_value(const std::string& value) = 0; + + virtual std::shared_ptr implicit_value(const std::string& value) = 0; + + virtual std::shared_ptr no_implicit_value() = 0; + + virtual bool is_boolean() const = 0; +}; + +class OptionException : public std::exception +{ +public: + OptionException(const std::string& message) : m_message(message) + { + } + + virtual const char* what() const noexcept + { + return m_message.c_str(); + } + +private: + std::string m_message; +}; + +class OptionSpecException : public OptionException +{ +public: + OptionSpecException(const std::string& message) : OptionException(message) + { + } +}; + +class OptionParseException : public OptionException +{ +public: + OptionParseException(const std::string& message) : OptionException(message) + { + } +}; + +class option_exists_error : public OptionSpecException +{ +public: + option_exists_error(const std::string& option) + : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") + { + } +}; + +class invalid_option_format_error : public OptionSpecException +{ +public: + invalid_option_format_error(const std::string& format) + : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) + { + } +}; + +class option_syntax_exception : public OptionParseException +{ +public: + option_syntax_exception(const std::string& text) + : OptionParseException("Argument " + LQUOTE + text + RQUOTE + " starts with a - but has incorrect syntax") + { + } +}; + +class option_not_exists_exception : public OptionParseException +{ +public: + option_not_exists_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") + { + } +}; + +class missing_argument_exception : public OptionParseException +{ +public: + missing_argument_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is missing an argument") + { + } +}; + +class option_requires_argument_exception : public OptionParseException +{ +public: + option_requires_argument_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " requires an argument") + { + } +}; + +class option_not_has_argument_exception : public OptionParseException +{ +public: + option_not_has_argument_exception(const std::string& option, const std::string& arg) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not take an argument, but argument " + LQUOTE + + arg + RQUOTE + " given") + { + } +}; + +class option_not_present_exception : public OptionParseException +{ +public: + option_not_present_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") + { + } +}; + +class argument_incorrect_type : public OptionParseException +{ +public: + argument_incorrect_type(const std::string& arg) + : OptionParseException("Argument " + LQUOTE + arg + RQUOTE + " failed to parse") + { + } +}; + +class option_required_exception : public OptionParseException +{ +public: + option_required_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is required but not present") + { + } +}; + +template +void throw_or_mimic(const std::string& text) +{ + static_assert(std::is_base_of::value, "throw_or_mimic only works on std::exception and " + "deriving classes"); + +#ifndef CXXOPTS_NO_EXCEPTIONS + // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw + throw T{ text }; +#else + // Otherwise manually instantiate the exception, print what() to stderr, + // and abort + T exception{ text }; + std::cerr << exception.what() << std::endl; + std::cerr << "Aborting (exceptions disabled)..." << std::endl; + std::abort(); +#endif +} + +namespace values +{ +namespace +{ +std::basic_regex integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); +std::basic_regex truthy_pattern("(t|T)(rue)?|1"); +std::basic_regex falsy_pattern("(f|F)(alse)?|0"); +} + +namespace detail +{ +template +struct SignedCheck; + +template +struct SignedCheck +{ + template + void operator()(bool negative, U u, const std::string& text) + { + if (negative) + { + if (u > static_cast((std::numeric_limits::min)())) + { + throw_or_mimic(text); + } + } + else + { + if (u > static_cast((std::numeric_limits::max)())) + { + throw_or_mimic(text); + } + } + } +}; + +template +struct SignedCheck +{ + template + void operator()(bool, U, const std::string&) + { + } +}; + +template +void check_signed_range(bool negative, U value, const std::string& text) +{ + SignedCheck::is_signed>()(negative, value, text); +} +} + +template +R checked_negate(T&& t, const std::string&, std::true_type) +{ + // if we got to here, then `t` is a positive number that fits into + // `R`. So to avoid MSVC C4146, we first cast it to `R`. + // See https://github.com/jarro2783/cxxopts/issues/62 for more details. + return static_cast(-static_cast(t - 1) - 1); +} + +template +T checked_negate(T&& t, const std::string& text, std::false_type) +{ + throw_or_mimic(text); + return t; +} + +template +void integer_parser(const std::string& text, T& value) +{ + std::smatch match; + std::regex_match(text, match, integer_pattern); + + if (match.length() == 0) + { + throw_or_mimic(text); + } + + if (match.length(4) > 0) + { + value = 0; + return; + } + + using US = typename std::make_unsigned::type; + + constexpr bool is_signed = std::numeric_limits::is_signed; + const bool negative = match.length(1) > 0; + const uint8_t base = match.length(2) > 0 ? 16 : 10; + + auto value_match = match[3]; + + US result = 0; + + for (auto iter = value_match.first; iter != value_match.second; ++iter) + { + US digit = 0; + + if (*iter >= '0' && *iter <= '9') + { + digit = static_cast(*iter - '0'); + } + else if (base == 16 && *iter >= 'a' && *iter <= 'f') + { + digit = static_cast(*iter - 'a' + 10); + } + else if (base == 16 && *iter >= 'A' && *iter <= 'F') + { + digit = static_cast(*iter - 'A' + 10); + } + else + { + throw_or_mimic(text); + } + + const US next = static_cast(result * base + digit); + if (result > next) + { + throw_or_mimic(text); + } + + result = next; + } + + detail::check_signed_range(negative, result, text); + + if (negative) + { + value = checked_negate(result, text, std::integral_constant()); + } + else + { + value = static_cast(result); + } +} + +template +void stringstream_parser(const std::string& text, T& value) +{ + std::stringstream in(text); + in >> value; + if (!in) + { + throw_or_mimic(text); + } +} + +inline void parse_value(const std::string& text, uint8_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, int8_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, uint16_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, int16_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, uint32_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, int32_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, uint64_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, int64_t& value) +{ + integer_parser(text, value); +} + +inline void parse_value(const std::string& text, bool& value) +{ + std::smatch result; + std::regex_match(text, result, truthy_pattern); + + if (!result.empty()) + { + value = true; + return; + } + + std::regex_match(text, result, falsy_pattern); + if (!result.empty()) + { + value = false; + return; + } + + throw_or_mimic(text); +} + +inline void parse_value(const std::string& text, std::string& value) +{ + value = text; +} + +// The fallback parser. It uses the stringstream parser to parse all types +// that have not been overloaded explicitly. It has to be placed in the +// source code before all other more specialized templates. +template +void parse_value(const std::string& text, T& value) +{ + stringstream_parser(text, value); +} + +template +void parse_value(const std::string& text, std::vector& value) +{ + std::stringstream in(text); + std::string token; + while (in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) + { + T v; + parse_value(token, v); + value.emplace_back(std::move(v)); + } +} + +#ifdef CXXOPTS_HAS_OPTIONAL +template +void parse_value(const std::string& text, std::optional& value) +{ + T result; + parse_value(text, result); + value = std::move(result); +} +#endif + +inline void parse_value(const std::string& text, char& c) +{ + if (text.length() != 1) + { + throw_or_mimic(text); + } + + c = text[0]; +} + +template +struct type_is_container +{ + static constexpr bool value = false; +}; + +template +struct type_is_container> +{ + static constexpr bool value = true; +}; + +template +class abstract_value : public Value +{ + using Self = abstract_value; + +public: + abstract_value() : m_result(std::make_shared()), m_store(m_result.get()) + { + } + + abstract_value(T* t) : m_store(t) + { + } + + virtual ~abstract_value() = default; + + abstract_value(const abstract_value& rhs) + { + if (rhs.m_result) + { + m_result = std::make_shared(); + m_store = m_result.get(); + } + else + { + m_store = rhs.m_store; + } + + m_default = rhs.m_default; + m_implicit = rhs.m_implicit; + m_default_value = rhs.m_default_value; + m_implicit_value = rhs.m_implicit_value; + } + + void parse(const std::string& text) const + { + parse_value(text, *m_store); + } + + bool is_container() const + { + return type_is_container::value; + } + + void parse() const + { + parse_value(m_default_value, *m_store); + } + + bool has_default() const + { + return m_default; + } + + bool has_implicit() const + { + return m_implicit; + } + + std::shared_ptr default_value(const std::string& value) + { + m_default = true; + m_default_value = value; + return shared_from_this(); + } + + std::shared_ptr implicit_value(const std::string& value) + { + m_implicit = true; + m_implicit_value = value; + return shared_from_this(); + } + + std::shared_ptr no_implicit_value() + { + m_implicit = false; + return shared_from_this(); + } + + std::string get_default_value() const + { + return m_default_value; + } + + std::string get_implicit_value() const + { + return m_implicit_value; + } + + bool is_boolean() const + { + return std::is_same::value; + } + + const T& get() const + { + if (m_store == nullptr) + { + return *m_result; + } + else + { + return *m_store; + } + } + +protected: + std::shared_ptr m_result; + T* m_store; + + bool m_default = false; + bool m_implicit = false; + + std::string m_default_value; + std::string m_implicit_value; +}; + +template +class standard_value : public abstract_value +{ +public: + using abstract_value::abstract_value; + + std::shared_ptr clone() const + { + return std::make_shared>(*this); + } +}; + +template <> +class standard_value : public abstract_value +{ +public: + ~standard_value() = default; + + standard_value() + { + set_default_and_implicit(); + } + + standard_value(bool* b) : abstract_value(b) + { + set_default_and_implicit(); + } + + std::shared_ptr clone() const + { + return std::make_shared>(*this); + } + +private: + void set_default_and_implicit() + { + m_default = true; + m_default_value = "false"; + m_implicit = true; + m_implicit_value = "true"; + } +}; +} + +template +std::shared_ptr value() +{ + return std::make_shared>(); +} + +template +std::shared_ptr value(T& t) +{ + return std::make_shared>(&t); +} + +class OptionAdder; + +class OptionDetails +{ +public: + OptionDetails(const std::string& short_, const std::string& long_, const String& desc, + std::shared_ptr val) + : m_short(short_), m_long(long_), m_desc(desc), m_value(val), m_count(0) + { + } + + OptionDetails(const OptionDetails& rhs) : m_desc(rhs.m_desc), m_count(rhs.m_count) + { + m_value = rhs.m_value->clone(); + } + + OptionDetails(OptionDetails&& rhs) = default; + + const String& description() const + { + return m_desc; + } + + const Value& value() const + { + return *m_value; + } + + std::shared_ptr make_storage() const + { + return m_value->clone(); + } + + const std::string& short_name() const + { + return m_short; + } + + const std::string& long_name() const + { + return m_long; + } + +private: + std::string m_short; + std::string m_long; + String m_desc; + std::shared_ptr m_value; + int m_count; +}; + +struct HelpOptionDetails +{ + std::string s; + std::string l; + String desc; + bool has_default; + std::string default_value; + bool has_implicit; + std::string implicit_value; + std::string arg_help; + bool is_container; + bool is_boolean; +}; + +struct HelpGroupDetails +{ + std::string name; + std::string description; + std::vector options; +}; + +class OptionValue +{ +public: + void parse(std::shared_ptr details, const std::string& text) + { + ensure_value(details); + ++m_count; + m_value->parse(text); + } + + void parse_default(std::shared_ptr details) + { + ensure_value(details); + m_default = true; + m_value->parse(); + } + + size_t count() const noexcept + { + return m_count; + } + + // TODO: maybe default options should count towards the number of arguments + bool has_default() const noexcept + { + return m_default; + } + + template + const T& as() const + { + if (m_value == nullptr) + { + throw_or_mimic("No value"); + } + +#ifdef CXXOPTS_NO_RTTI + return static_cast&>(*m_value).get(); +#else + return dynamic_cast&>(*m_value).get(); +#endif + } + +private: + void ensure_value(std::shared_ptr details) + { + if (m_value == nullptr) + { + m_value = details->make_storage(); + } + } + + std::shared_ptr m_value; + size_t m_count = 0; + bool m_default = false; +}; + +class KeyValue +{ +public: + KeyValue(std::string key_, std::string value_) : m_key(std::move(key_)), m_value(std::move(value_)) + { + } + + const std::string& key() const + { + return m_key; + } + + const std::string& value() const + { + return m_value; + } + + template + T as() const + { + T result; + values::parse_value(m_value, result); + return result; + } + +private: + std::string m_key; + std::string m_value; +}; + +class ParseResult +{ +public: + ParseResult(const std::shared_ptr>>, + std::vector, bool allow_unrecognised, int&, char**&); + + size_t count(const std::string& o) const + { + auto iter = m_options->find(o); + if (iter == m_options->end()) + { + return 0; + } + + auto riter = m_results.find(iter->second); + + return riter->second.count(); + } + + const OptionValue& operator[](const std::string& option) const + { + auto iter = m_options->find(option); + + if (iter == m_options->end()) + { + throw_or_mimic(option); + } + + auto riter = m_results.find(iter->second); + + return riter->second; + } + + const std::vector& arguments() const + { + return m_sequential; + } + +private: + void parse(int& argc, char**& argv); + + void add_to_option(const std::string& option, const std::string& arg); + + bool consume_positional(std::string a); + + void parse_option(std::shared_ptr value, const std::string& name, const std::string& arg = ""); + + void parse_default(std::shared_ptr details); + + void checked_parse_arg(int argc, char* argv[], int& current, std::shared_ptr value, + const std::string& name); + + const std::shared_ptr>> m_options; + std::vector m_positional; + std::vector::iterator m_next_positional; + std::unordered_set m_positional_set; + std::unordered_map, OptionValue> m_results; + + bool m_allow_unrecognised; + + std::vector m_sequential; +}; + +struct Option +{ + Option(const std::string& opts, const std::string& desc, + const std::shared_ptr& value = ::cxxopts::value(), const std::string& arg_help = "") + : opts_(opts), desc_(desc), value_(value), arg_help_(arg_help) + { + } + + std::string opts_; + std::string desc_; + std::shared_ptr value_; + std::string arg_help_; +}; + +class Options +{ + typedef std::unordered_map> OptionMap; + +public: + Options(std::string program, std::string help_string = "") + : m_program(std::move(program)) + , m_help_string(toLocalString(std::move(help_string))) + , m_custom_help("[OPTION...]") + , m_positional_help("positional parameters") + , m_show_positional(false) + , m_allow_unrecognised(false) + , m_options(std::make_shared()) + , m_next_positional(m_positional.end()) + { + } + + Options& positional_help(std::string help_text) + { + m_positional_help = std::move(help_text); + return *this; + } + + Options& custom_help(std::string help_text) + { + m_custom_help = std::move(help_text); + return *this; + } + + Options& show_positional_help() + { + m_show_positional = true; + return *this; + } + + Options& allow_unrecognised_options() + { + m_allow_unrecognised = true; + return *this; + } + + ParseResult parse(int& argc, char**& argv); + + OptionAdder add_options(std::string group = ""); + + void add_options(const std::string& group, std::initializer_list