From b547268fa6b7ff4140e0949d82d24358b2926a53 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Mon, 2 Jan 2023 14:23:16 +0200 Subject: [PATCH] refactor: rewrite the plugin in rust --- .cargo/config.toml | 2 + .gitignore | 8 +- Cargo.toml | 15 + LICENSE_APACHE-2.0 | 177 +++++++ LICENSE => LICENSE_MIT | 2 +- SemverCompare.cpp | 46 -- SemverCompare.nsi | 36 -- SemverCompare.sln | 20 - SemverCompare.vcxproj | 101 ---- SemverCompare.vcxproj.filters | 33 -- buildDebug.ps1 | 1 - buildRelease.ps1 | 1 - demo.nsi | 16 + include/nsis/api.h | 86 ---- include/nsis/nsis_tchar.h | 214 -------- include/nsis/pluginapi.h | 105 ---- include/nsis/pluginapi.lib | Bin 6894 -> 0 bytes include/semver.hpp | 935 ---------------------------------- src/lib.rs | 71 +++ src/utils.rs | 82 +++ 20 files changed, 367 insertions(+), 1584 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 Cargo.toml create mode 100644 LICENSE_APACHE-2.0 rename LICENSE => LICENSE_MIT (93%) delete mode 100644 SemverCompare.cpp delete mode 100644 SemverCompare.nsi delete mode 100644 SemverCompare.sln delete mode 100644 SemverCompare.vcxproj delete mode 100644 SemverCompare.vcxproj.filters delete mode 100644 buildDebug.ps1 delete mode 100644 buildRelease.ps1 create mode 100644 demo.nsi delete mode 100644 include/nsis/api.h delete mode 100644 include/nsis/nsis_tchar.h delete mode 100644 include/nsis/pluginapi.h delete mode 100644 include/nsis/pluginapi.lib delete mode 100644 include/semver.hpp create mode 100644 src/lib.rs create mode 100644 src/utils.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..9380186 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "i686-pc-windows-msvc" diff --git a/.gitignore b/.gitignore index 8705136..4fde1fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ -Release/ -Debug/ -.vscode/ -.vs/ -*.user +/target +/Cargo.lock *.exe +.vscode/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3eeccef --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "nsis-semvercompare" +version = "0.0.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +semver = "1.0.16" + +[dependencies.windows-sys] +version = "0.42.0" +features = ["Win32_System_Memory", "Win32_Foundation", "Win32_Globalization"] diff --git a/LICENSE_APACHE-2.0 b/LICENSE_APACHE-2.0 new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/LICENSE_APACHE-2.0 @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE b/LICENSE_MIT similarity index 93% rename from LICENSE rename to LICENSE_MIT index caecc40..7e54d8e 100644 --- a/LICENSE +++ b/LICENSE_MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Alexei Sitnikov +Copyright (c) 2019 - 2022 Tauri Programme within The Commons Conservancy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/SemverCompare.cpp b/SemverCompare.cpp deleted file mode 100644 index 53d3e83..0000000 --- a/SemverCompare.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "include\nsis\pluginapi.h" -#include "include\semver.hpp" - -#define NSIS_MAX_STRLEN 1024 - -extern "C" void __declspec(dllexport) SemverCompare(HWND hwndParent, - int string_size, - TCHAR* variables, - stack_t** stacktop, - extra_parameters* extra) { - EXDLL_INIT(); - - TCHAR arg1[NSIS_MAX_STRLEN]; - if (popstringn(arg1, NSIS_MAX_STRLEN)) - return; - - TCHAR arg2[NSIS_MAX_STRLEN]; - if (popstringn(arg2, NSIS_MAX_STRLEN)) - return; - - std::wstring ver1w(arg1); - std::wstring ver2w(arg2); - - std::string ver1(ver1w.begin(), ver1w.end()); - std::string ver2(ver2w.begin(), ver2w.end()); - - std::optional v1 = semver::from_string_noexcept(ver1); - std::optional v2 = semver::from_string_noexcept(ver2); - - if (v1.has_value() && !v2.has_value()) { - pushint(1); - } else if (!v1.has_value() && v2.has_value()) { - pushint(-1); - } else if (!v1.has_value() && !v2.has_value()) { - pushint(0); - } else { - pushint(v1.value().compare(v2.value())); - } -} diff --git a/SemverCompare.nsi b/SemverCompare.nsi deleted file mode 100644 index 651c4e6..0000000 --- a/SemverCompare.nsi +++ /dev/null @@ -1,36 +0,0 @@ -Name "SemverCompare" -OutFile "SemverCompare.exe" -ShowInstDetails show - -!addplugindir "Debug" -!addplugindir "Release" - -Section "nsSemverCompare" - SemverCompare::SemverCompare "1.2.1" "1.2.0" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.0" "1.2.1" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.1" "1.2.1" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.1-alpha.1" "1.2.1-beta.5" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.1-rc.1" "1.2.1-beta.1" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.1-alpha.1" "1.2.1-alpha.1" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2qe2.1-alpha.1" "1.2.1-alpha.1" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.1-alpha.1" "-q1.2.1-alpha.1" - Pop $1 - DetailPrint $1 - SemverCompare::SemverCompare "1.2.saf1-alpha.1" "-q1.2.1-alpha.1" - Pop $1 - DetailPrint $1 -SectionEnd diff --git a/SemverCompare.sln b/SemverCompare.sln deleted file mode 100644 index 1b4f4c8..0000000 --- a/SemverCompare.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SemverCompare", "SemverCompare.vcxproj", "{EE997742-B1B4-4FA0-A46E-E8F2614D457B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Debug|Win32.ActiveCfg = Debug|Win32 - {EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Debug|Win32.Build.0 = Debug|Win32 - {EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Release|Win32.ActiveCfg = Release|Win32 - {EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/SemverCompare.vcxproj b/SemverCompare.vcxproj deleted file mode 100644 index e4fdb2a..0000000 --- a/SemverCompare.vcxproj +++ /dev/null @@ -1,101 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {EE997742-B1B4-4FA0-A46E-E8F2614D457B} - Win32Proj - SemverCompare - 10.0 - - - - DynamicLibrary - true - Unicode - v143 - - - DynamicLibrary - false - true - Unicode - v143 - false - - - - - - - - - - - - - true - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;SemverCompare_EXPORTS;%(PreprocessorDefinitions) - MultiThreadedDebug - stdcpp17 - stdc17 - - - Windows - true - kernel32.lib;include/nsis/pluginapi.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;SemverCompare_EXPORTS;%(PreprocessorDefinitions) - MultiThreaded - stdcpp17 - stdc17 - - - Windows - true - kernel32.lib;include/nsis/pluginapi.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - true - true - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SemverCompare.vcxproj.filters b/SemverCompare.vcxproj.filters deleted file mode 100644 index b77f962..0000000 --- a/SemverCompare.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - - - - \ No newline at end of file diff --git a/buildDebug.ps1 b/buildDebug.ps1 deleted file mode 100644 index 1b29377..0000000 --- a/buildDebug.ps1 +++ /dev/null @@ -1 +0,0 @@ -msbuild ./SemverCompare.sln /p:Configuration=Debug \ No newline at end of file diff --git a/buildRelease.ps1 b/buildRelease.ps1 deleted file mode 100644 index 13d53b3..0000000 --- a/buildRelease.ps1 +++ /dev/null @@ -1 +0,0 @@ -msbuild ./SemverCompare.sln /p:Configuration=Release \ No newline at end of file diff --git a/demo.nsi b/demo.nsi new file mode 100644 index 0000000..0227144 --- /dev/null +++ b/demo.nsi @@ -0,0 +1,16 @@ + +Name "demo" +OutFile "demo.exe" +ShowInstDetails show +Unicode true + +!addplugindir ".\target\release" +!addplugindir ".\target\debug" +!addplugindir ".\target\i686-pc-windows-msvc\release" +!addplugindir ".\target\i686-pc-windows-msvc\debug" + +Section + nsis_semvercompare::SemverCompare "1.0.0" "1.1.0" + Pop $1 + DetailPrint $1 +SectionEnd \ No newline at end of file diff --git a/include/nsis/api.h b/include/nsis/api.h deleted file mode 100644 index fb2a608..0000000 --- a/include/nsis/api.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * apih - * - * This file is a part of NSIS. - * - * Copyright (C) 1999-2009 Nullsoft and Contributors - * - * Licensed under the zlib/libpng license (the "License"); - * you may not use this file except in compliance with the License. - * - * Licence details can be found in the file COPYING. - * - * This software is provided 'as-is', without any express or implied - * warranty. - */ - -#ifndef _NSIS_EXEHEAD_API_H_ -#define _NSIS_EXEHEAD_API_H_ - -// Starting with NSIS 2.42, you can check the version of the plugin API in -// exec_flags->plugin_api_version The format is 0xXXXXYYYY where X is the major -// version and Y is the minor version (MAKELONG(y,x)) When doing version checks, -// always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= -// NSISPIAPIVER_1_0) {} - -#define NSISPIAPIVER_1_0 0x00010000 -#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0 - -// NSIS Plug-In Callback Messages -enum NSPIM { - NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup - NSPIM_GUIUNLOAD, // Called after .onGUIEnd -}; - -// Prototype for callbacks registered with -// extra_parameters->RegisterPluginCallback() Return NULL for unknown messages -// Should always be __cdecl for future expansion possibilities -typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM); - -// extra_parameters data structures containing other interesting stuff -// but the stack, variables and HWND passed on to plug-ins. -typedef struct { - int autoclose; - int all_user_var; - int exec_error; - int abort; - int exec_reboot; // NSIS_SUPPORT_REBOOT - int reboot_called; // NSIS_SUPPORT_REBOOT - int XXX_cur_insttype; // depreacted - int plugin_api_version; // see NSISPIAPIVER_CURR - // used to be XXX_insttype_changed - int silent; // NSIS_CONFIG_SILENT_SUPPORT - int instdir_error; - int rtl; - int errlvl; - int alter_reg_view; - int status_update; -} exec_flags_t; - -#ifndef NSISCALL -#define NSISCALL __stdcall -#endif - -typedef struct { - exec_flags_t* exec_flags; - int(NSISCALL* ExecuteCodeSegment)(int, HWND); - void(NSISCALL* validate_filename)(TCHAR*); - int(NSISCALL* RegisterPluginCallback)( - HMODULE, - NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and - // < 0 on errors -} extra_parameters; - -// Definitions for page showing plug-ins -// See Ui.c to understand better how they're used - -// sent to the outer window to tell it to go to the next inner window -#define WM_NOTIFY_OUTER_NEXT (WM_USER + 0x8) - -// custom pages should send this message to let NSIS know they're ready -#define WM_NOTIFY_CUSTOM_READY (WM_USER + 0xd) - -// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning -#define NOTIFY_BYE_BYE 'x' - -#endif /* _PLUGIN_H_ */ diff --git a/include/nsis/nsis_tchar.h b/include/nsis/nsis_tchar.h deleted file mode 100644 index ac710f8..0000000 --- a/include/nsis/nsis_tchar.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * nsis_tchar.h - * - * This file is a part of NSIS. - * - * Copyright (C) 1999-2007 Nullsoft and Contributors - * - * This software is provided 'as-is', without any express or implied - * warranty. - * - * For Unicode support by Jim Park -- 08/30/2007 - */ - -// Jim Park: Only those we use are listed here. - -#pragma once - -#ifdef _UNICODE - -#ifndef _T -#define __T(x) L##x -#define _T(x) __T(x) -#define _TEXT(x) __T(x) -#endif -typedef wchar_t TCHAR; -typedef wchar_t _TUCHAR; - -// program -#define _tmain wmain -#define _tWinMain wWinMain -#define _tenviron _wenviron -#define __targv __wargv - -// printfs -#define _ftprintf fwprintf -#define _sntprintf _snwprintf -#define _stprintf _swprintf -#define _tprintf wprintf -#define _vftprintf vfwprintf -#define _vsntprintf _vsnwprintf -#define _vstprintf _vswprintf - -// scanfs -#define _tscanf wscanf -#define _stscanf swscanf - -// string manipulations -#define _tcscat wcscat -#define _tcschr wcschr -#define _tcsclen wcslen -#define _tcscpy wcscpy -#define _tcsdup _wcsdup -#define _tcslen wcslen -#define _tcsnccpy wcsncpy -#define _tcsncpy wcsncpy -#define _tcsrchr wcsrchr -#define _tcsstr wcsstr -#define _tcstok wcstok - -// string comparisons -#define _tcscmp wcscmp -#define _tcsicmp _wcsicmp -#define _tcsncicmp _wcsnicmp -#define _tcsncmp wcsncmp -#define _tcsnicmp _wcsnicmp - -// upper / lower -#define _tcslwr _wcslwr -#define _tcsupr _wcsupr -#define _totlower towlower -#define _totupper towupper - -// conversions to numbers -#define _tcstoi64 _wcstoi64 -#define _tcstol wcstol -#define _tcstoul wcstoul -#define _tstof _wtof -#define _tstoi _wtoi -#define _tstoi64 _wtoi64 -#define _ttoi _wtoi -#define _ttoi64 _wtoi64 -#define _ttol _wtol - -// conversion from numbers to strings -#define _itot _itow -#define _ltot _ltow -#define _i64tot _i64tow -#define _ui64tot _ui64tow - -// file manipulations -#define _tfopen _wfopen -#define _topen _wopen -#define _tremove _wremove -#define _tunlink _wunlink - -// reading and writing to i/o -#define _fgettc fgetwc -#define _fgetts fgetws -#define _fputts fputws -#define _gettchar getwchar - -// directory -#define _tchdir _wchdir - -// environment -#define _tgetenv _wgetenv -#define _tsystem _wsystem - -// time -#define _tcsftime wcsftime - -#else // ANSI - -#ifndef _T -#define _T(x) x -#define _TEXT(x) x -#endif -typedef char TCHAR; -typedef unsigned char _TUCHAR; - -// program -#define _tmain main -#define _tWinMain WinMain -#define _tenviron environ -#define __targv __argv - -// printfs -#define _ftprintf fprintf -#define _sntprintf _snprintf -#define _stprintf sprintf -#define _tprintf printf -#define _vftprintf vfprintf -#define _vsntprintf _vsnprintf -#define _vstprintf vsprintf - -// scanfs -#define _tscanf scanf -#define _stscanf sscanf - -// string manipulations -#define _tcscat strcat -#define _tcschr strchr -#define _tcsclen strlen -#define _tcscnlen strnlen -#define _tcscpy strcpy -#define _tcsdup _strdup -#define _tcslen strlen -#define _tcsnccpy strncpy -#define _tcsrchr strrchr -#define _tcsstr strstr -#define _tcstok strtok - -// string comparisons -#define _tcscmp strcmp -#define _tcsicmp _stricmp -#define _tcsncmp strncmp -#define _tcsncicmp _strnicmp -#define _tcsnicmp _strnicmp - -// upper / lower -#define _tcslwr _strlwr -#define _tcsupr _strupr - -#define _totupper toupper -#define _totlower tolower - -// conversions to numbers -#define _tcstol strtol -#define _tcstoul strtoul -#define _tstof atof -#define _tstoi atoi -#define _tstoi64 _atoi64 -#define _tstoi64 _atoi64 -#define _ttoi atoi -#define _ttoi64 _atoi64 -#define _ttol atol - -// conversion from numbers to strings -#define _i64tot _i64toa -#define _itot _itoa -#define _ltot _ltoa -#define _ui64tot _ui64toa - -// file manipulations -#define _tfopen fopen -#define _topen _open -#define _tremove remove -#define _tunlink _unlink - -// reading and writing to i/o -#define _fgettc fgetc -#define _fgetts fgets -#define _fputts fputs -#define _gettchar getchar - -// directory -#define _tchdir _chdir - -// environment -#define _tgetenv getenv -#define _tsystem system - -// time -#define _tcsftime strftime - -#endif - -// is functions (the same in Unicode / ANSI) -#define _istgraph isgraph -#define _istascii __isascii - -#define __TFILE__ _T(__FILE__) -#define __TDATE__ _T(__DATE__) -#define __TTIME__ _T(__TIME__) diff --git a/include/nsis/pluginapi.h b/include/nsis/pluginapi.h deleted file mode 100644 index 17aa62e..0000000 --- a/include/nsis/pluginapi.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef ___NSIS_PLUGIN__H___ -#define ___NSIS_PLUGIN__H___ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "api.h" -#include "nsis_tchar.h" - -#ifndef NSISCALL -#define NSISCALL __stdcall -#endif - -#define EXDLL_INIT() \ - { \ - g_stringsize = string_size; \ - g_stacktop = stacktop; \ - g_variables = variables; \ - } - -typedef struct _stack_t { - struct _stack_t* next; - TCHAR text[1]; // this should be the length of string_size -} stack_t; - -enum { - INST_0, // $0 - INST_1, // $1 - INST_2, // $2 - INST_3, // $3 - INST_4, // $4 - INST_5, // $5 - INST_6, // $6 - INST_7, // $7 - INST_8, // $8 - INST_9, // $9 - INST_R0, // $R0 - INST_R1, // $R1 - INST_R2, // $R2 - INST_R3, // $R3 - INST_R4, // $R4 - INST_R5, // $R5 - INST_R6, // $R6 - INST_R7, // $R7 - INST_R8, // $R8 - INST_R9, // $R9 - INST_CMDLINE, // $CMDLINE - INST_INSTDIR, // $INSTDIR - INST_OUTDIR, // $OUTDIR - INST_EXEDIR, // $EXEDIR - INST_LANG, // $LANGUAGE - __INST_LAST -}; - -extern unsigned int g_stringsize; -extern stack_t** g_stacktop; -extern TCHAR* g_variables; - -int NSISCALL popstring(TCHAR* str); // 0 on success, 1 on empty stack -int NSISCALL -popstringn(TCHAR* str, - int maxlen); // with length limit, pass 0 for g_stringsize -int NSISCALL popint(); // pops an integer -int NSISCALL popint_or(); // with support for or'ing (2|4|8) -int NSISCALL myatoi(const TCHAR* s); // converts a string to an integer -unsigned NSISCALL myatou( - const TCHAR* s); // converts a string to an unsigned integer, decimal only -int NSISCALL myatoi_or(const TCHAR* s); // with support for or'ing (2|4|8) -void NSISCALL pushstring(const TCHAR* str); -void NSISCALL pushint(int value); -TCHAR* NSISCALL getuservariable(const int varnum); -void NSISCALL setuservariable(const int varnum, const TCHAR* var); - -#ifdef _UNICODE -#define PopStringW(x) popstring(x) -#define PushStringW(x) pushstring(x) -#define SetUserVariableW(x, y) setuservariable(x, y) - -int NSISCALL PopStringA(char* ansiStr); -void NSISCALL PushStringA(const char* ansiStr); -void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); -void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); -void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr); - -#else -// ANSI defs - -#define PopStringA(x) popstring(x) -#define PushStringA(x) pushstring(x) -#define SetUserVariableA(x, y) setuservariable(x, y) - -int NSISCALL PopStringW(wchar_t* wideStr); -void NSISCALL PushStringW(wchar_t* wideStr); -void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); -void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); -void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif //!___NSIS_PLUGIN__H___ diff --git a/include/nsis/pluginapi.lib b/include/nsis/pluginapi.lib deleted file mode 100644 index 800adddef6b248eaddf36118d6b7fe9023b3435b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6894 zcmeHMYiv`=6`q^xI3@`sK$dlZLJ~sDGdMAikg&y0oFGI34gqHoS&Wl7;NZlTeZ2uh zm8Dlm8yWAe`lAA=sG_Tt+Wy$Sq~;G&16#F9w^C{O(TBEbwOh4|LaW_wO9`!TzcVw} zuNxCq?axj!bI+W6<~wK3oH=uSZ{5B?Z0PJ4%6HV}mnNsv(S*{xJD=~6-JMN)Bz3x+ zG4>o|mXiN<-M`=8;qo`_I&`@G;GshY54-j^xZV33I=bjOEIMwti}?=(wd3(%%om7- z0)ye8+tp&?^%Kt zU?LPA9!SK3;b0&h9Oyjn>Fyqgh7)H(G?&8`)r2i$iYx z)8*Yt9sA1r2aZ^mF?JepLZxvy797%E4vHRQFM-%sYV_o_yc%-B!Ni${KI6_+5Z4Rj zT&%jiQ45~e3?W?GP&Znk50wf+lhsyNpO$!CoQb9y^;O7RlX4Wtu4*&h5%9kbnUAF$ znNSRGLm6XER4T>rx^V9W$mmjzF2(R>aq~A)t{7e&#(w}Aiwy({(ri&YJ7hLVxng)b zFuoZw0V$_G1#c2EuP=hvf$`TN^PZF=Hx`?(eF^MCrBcj3T90PPT$XZ~^;jSdz7Ltd zO1Y=$-GVc!mCh-YVtSv)Jr86~O1Y=`IRcrME%c^ckc$Q+b%#pe4KF#4nn2SihB-5x>CRw<;4;nm~z3MsP~-cHDQ7Qvea$YIEo zF3svKW?vO#*5}B%7TD(wz-)%h2`QIZ--5UzxiQGxSVXP~a^Ho_`%*5m9P6Y7}C*mtU&fix970Cr?aoV zmXhMfsFSE}rYtArp4Nf!L^vFejA#Ri@z79YIJi9?8ya|qL!y=KTTY3mjAzv~Hauv#T0>R=^wUQ72&xIAIFlY)soIP}dcrV!AdUdxaD3*jQBtd^IRqXe--< zR)hiwM#mWy!?zS3a@l?T>P*I?$&Y*=l3enUbH?ix{)IaGXxfJ^cdt)el0Wg2W65qY zFWS7qovT1mT-C7p%w5U@n^CQ-1#NcGJJ6$|urh8NnO(+?Cm;BdiOT*f4-?iTU*wc! zch<;9zJ6}yC>v$Ibiy{(Svi{Sr=GB_Uz*ri=|A-n{6nS*BgsF)Nb&$hSPkD2!nAhu zg=yU7z8uFGq2?P+!yh$SUBX||Dfu2D_X}mT=E8u_foevzvTbN71ZxjW!&6Omz3G^yVyyQb&}Gc|%cDm#Yg)r+Vi%y`^Th=u zg^#e6I0Bqn;UW->&TJ|MIBgJs&+hGRuxVRF&~D%!Oma{!?Fd9{yH_}`w>P7V9zTUL z3K|i)vFPcopL%+v?Ovk0YC2k?KcR^~c`>n5pDDqA)wJ!I zX8vc3I**w@;WPgvzS8+ne~g)T88g2$e^;Q%nSV$#pQo9p%hh>tYwNq1`9sY7_al1C zr9=g|ULIH#k0?)&GrkGqy{I*)jL~BY6~irbhj07K4`{k)UqL^0g{9MJfrEn)4x4=^ zmpA(k#f;d)TR@R(YbbU67Z}1qfnj3|xdj>@rPF7D&13@9e^e=$!n9dTj`p`7)ygQr z3~-9}i`d^A*)V9=5YGC>(D0fY-@?4;$<#Fx3}}rG2d%H*Ga5wKZ_+MWIAtEg^qbzIm?C3I5mw~`~Vy(6(;0LaPyHXOvrSos7eP~ z^5*JuuOg@oyI%E5-S}8`t0h1F%UFE4Z%Q z6{P%-kG#T!Oo>rd=xn7G{N1gax3b8c61m2NOb2W}a*YX@(xj>&AULw;w`oO^LG97Iq`g1BCjED#K`8A2W zP9Wz*FXiB3qprzO>rJC-`6zleq-eSLDg@UIS;A^g>^7$fhG_q&>!3*X=8qPoN3$Pm5lU*Ma9`8|KZ2Mz($9~usJoDIZ| zMS2opE!2KN3%Z<8>NP%wEcp3DjLnQV7BOI4&6s$>2Nyog0v`XSvd~AAf=?m*>xbaU ek0S8bf}cXN-#dhH6Y(fMz-S}=>{&lHl>Z0IkG8}B diff --git a/include/semver.hpp b/include/semver.hpp deleted file mode 100644 index 8ea3861..0000000 --- a/include/semver.hpp +++ /dev/null @@ -1,935 +0,0 @@ -// _____ _ _ -// / ____| | | (_) -// | (___ ___ _ __ ___ __ _ _ __ | |_ _ ___ -// \___ \ / _ \ '_ ` _ \ / _` | '_ \| __| |/ __| -// ____) | __/ | | | | | (_| | | | | |_| | (__ -// |_____/ \___|_| |_| |_|\__,_|_| |_|\__|_|\___| -// __ __ _ _ _____ -// \ \ / / (_) (_) / ____|_ _ -// \ \ / /__ _ __ ___ _ ___ _ __ _ _ __ __ _ | | _| |_ _| |_ -// \ \/ / _ \ '__/ __| |/ _ \| '_ \| | '_ \ / _` | | | |_ _|_ _| -// \ / __/ | \__ \ | (_) | | | | | | | | (_| | | |____|_| |_| -// \/ \___|_| |___/_|\___/|_| |_|_|_| |_|\__, | \_____| -// https://github.com/Neargye/semver __/ | -// version 0.3.0 |___/ -// -// Licensed under the MIT License . -// SPDX-License-Identifier: MIT -// Copyright (c) 2018 - 2021 Daniil Goncharov . -// Copyright (c) 2020 - 2021 Alexander Gorbunov . -// -// 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 NEARGYE_SEMANTIC_VERSIONING_HPP -#define NEARGYE_SEMANTIC_VERSIONING_HPP - -#define SEMVER_VERSION_MAJOR 0 -#define SEMVER_VERSION_MINOR 3 -#define SEMVER_VERSION_PATCH 0 - -#include -#include -#include -#include -#include -#include -#include -#if __has_include() -#include -#else -#include -#endif - -#if defined(SEMVER_CONFIG_FILE) -#include SEMVER_CONFIG_FILE -#endif - -#if defined(SEMVER_THROW) -// define SEMVER_THROW(msg) to override semver throw behavior. -#elif defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) -#include -#define SEMVER_THROW(msg) (throw std::invalid_argument{msg}) -#else -#include -#include -#define SEMVER_THROW(msg) (assert(!msg), std::abort()) -#endif - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored \ - "-Wmissing-braces" // Ignore warning: suggest braces around initialization - // of subobject 'return {first, - // std::errc::invalid_argument};'. -#endif - -namespace semver { - -enum struct prerelease : std::uint8_t { alpha = 0, beta = 1, rc = 2, none = 3 }; - -#if __has_include() -struct from_chars_result : std::from_chars_result { - [[nodiscard]] constexpr operator bool() const noexcept { - return ec == std::errc{}; - } -}; - -struct to_chars_result : std::to_chars_result { - [[nodiscard]] constexpr operator bool() const noexcept { - return ec == std::errc{}; - } -}; -#else -struct from_chars_result { - const char* ptr; - std::errc ec; - - [[nodiscard]] constexpr operator bool() const noexcept { - return ec == std::errc{}; - } -}; - -struct to_chars_result { - char* ptr; - std::errc ec; - - [[nodiscard]] constexpr operator bool() const noexcept { - return ec == std::errc{}; - } -}; -#endif - -// Max version string length = 3() + 1(.) + 3() + 1(.) + -// 3() + 1(-) + 5() + 1(.) + 3() = 21. -inline constexpr auto max_version_string_length = std::size_t{21}; - -namespace detail { - -inline constexpr auto alpha = std::string_view{"alpha", 5}; -inline constexpr auto beta = std::string_view{"beta", 4}; -inline constexpr auto rc = std::string_view{"rc", 2}; - -// Min version string length = 1() + 1(.) + 1() + 1(.) + -// 1() = 5. -inline constexpr auto min_version_string_length = 5; - -constexpr char to_lower(char c) noexcept { - return (c >= 'A' && c <= 'Z') ? static_cast(c + ('a' - 'A')) : c; -} - -constexpr bool is_digit(char c) noexcept { - return c >= '0' && c <= '9'; -} - -constexpr bool is_space(char c) noexcept { - return c == ' '; -} - -constexpr bool is_operator(char c) noexcept { - return c == '<' || c == '>' || c == '='; -} - -constexpr bool is_dot(char c) noexcept { - return c == '.'; -} - -constexpr bool is_logical_or(char c) noexcept { - return c == '|'; -} - -constexpr bool is_hyphen(char c) noexcept { - return c == '-'; -} - -constexpr bool is_letter(char c) noexcept { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); -} - -constexpr std::uint8_t to_digit(char c) noexcept { - return static_cast(c - '0'); -} - -constexpr std::uint8_t length(std::uint8_t x) noexcept { - return x < 10 ? 1 : (x < 100 ? 2 : 3); -} - -constexpr std::uint8_t length(prerelease t) noexcept { - if (t == prerelease::alpha) { - return static_cast(alpha.length()); - } else if (t == prerelease::beta) { - return static_cast(beta.length()); - } else if (t == prerelease::rc) { - return static_cast(rc.length()); - } - - return 0; -} - -constexpr bool equals(const char* first, - const char* last, - std::string_view str) noexcept { - for (std::size_t i = 0; first != last && i < str.length(); ++i, ++first) { - if (to_lower(*first) != to_lower(str[i])) { - return false; - } - } - - return true; -} - -constexpr char* to_chars(char* str, std::uint8_t x, bool dot = true) noexcept { - do { - *(--str) = static_cast('0' + (x % 10)); - x /= 10; - } while (x != 0); - - if (dot) { - *(--str) = '.'; - } - - return str; -} - -constexpr char* to_chars(char* str, prerelease t) noexcept { - const auto p = t == prerelease::alpha ? alpha - : t == prerelease::beta ? beta - : t == prerelease::rc ? rc - : std::string_view{}; - - if (p.size() > 0) { - for (auto it = p.rbegin(); it != p.rend(); ++it) { - *(--str) = *it; - } - *(--str) = '-'; - } - - return str; -} - -constexpr const char* from_chars(const char* first, - const char* last, - std::uint8_t& d) noexcept { - if (first != last && is_digit(*first)) { - std::int32_t t = 0; - for (; first != last && is_digit(*first); ++first) { - t = t * 10 + to_digit(*first); - } - if (t <= (std::numeric_limits::max)()) { - d = static_cast(t); - return first; - } - } - - return nullptr; -} - -constexpr const char* from_chars(const char* first, - const char* last, - std::optional& d) noexcept { - if (first != last && is_digit(*first)) { - std::int32_t t = 0; - for (; first != last && is_digit(*first); ++first) { - t = t * 10 + to_digit(*first); - } - if (t <= (std::numeric_limits::max)()) { - d = static_cast(t); - return first; - } - } - - return nullptr; -} - -constexpr const char* from_chars(const char* first, - const char* last, - prerelease& p) noexcept { - if (is_hyphen(*first)) { - ++first; - } - - if (equals(first, last, alpha)) { - p = prerelease::alpha; - return first + alpha.length(); - } else if (equals(first, last, beta)) { - p = prerelease::beta; - return first + beta.length(); - } else if (equals(first, last, rc)) { - p = prerelease::rc; - return first + rc.length(); - } - - return nullptr; -} - -constexpr bool check_delimiter(const char* first, - const char* last, - char d) noexcept { - return first != last && first != nullptr && *first == d; -} - -template -struct resize_uninitialized { - static auto resize(T& str, std::size_t size) - -> std::void_t { - str.resize(size); - } -}; - -template -struct resize_uninitialized< - T, - std::void_t().__resize_default_init(42))>> { - static void resize(T& str, std::size_t size) { - str.__resize_default_init(size); - } -}; - -} // namespace detail - -struct version { - std::uint8_t major = 0; - std::uint8_t minor = 1; - std::uint8_t patch = 0; - prerelease prerelease_type = prerelease::none; - std::optional prerelease_number = std::nullopt; - - constexpr version(std::uint8_t mj, - std::uint8_t mn, - std::uint8_t pt, - prerelease prt = prerelease::none, - std::optional prn = std::nullopt) noexcept - : major{mj}, - minor{mn}, - patch{pt}, - prerelease_type{prt}, - prerelease_number{prt == prerelease::none ? std::nullopt : prn} {} - - explicit constexpr version(std::string_view str) - : version(0, 0, 0, prerelease::none, 0) { - from_string(str); - } - - constexpr version() = - default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase - - constexpr version(const version&) = default; - - constexpr version(version&&) = default; - - ~version() = default; - - version& operator=(const version&) = default; - - version& operator=(version&&) = default; - - [[nodiscard]] constexpr from_chars_result from_chars( - const char* first, - const char* last) noexcept { - if (first == nullptr || last == nullptr || - (last - first) < detail::min_version_string_length) { - return {first, std::errc::invalid_argument}; - } - - auto next = first; - if (next = detail::from_chars(next, last, major); - detail::check_delimiter(next, last, '.')) { - if (next = detail::from_chars(++next, last, minor); - detail::check_delimiter(next, last, '.')) { - if (next = detail::from_chars(++next, last, patch); next == last) { - prerelease_type = prerelease::none; - prerelease_number = {}; - return {next, std::errc{}}; - } else if (detail::check_delimiter(next, last, '-')) { - if (next = detail::from_chars(next, last, prerelease_type); - next == last) { - prerelease_number = {}; - return {next, std::errc{}}; - } else if (detail::check_delimiter(next, last, '.')) { - if (next = detail::from_chars(++next, last, prerelease_number); - next == last) { - return {next, std::errc{}}; - } - } - } - } - } - - return {first, std::errc::invalid_argument}; - } - - [[nodiscard]] constexpr to_chars_result to_chars(char* first, - char* last) const noexcept { - const auto length = string_length(); - if (first == nullptr || last == nullptr || (last - first) < length) { - return {last, std::errc::value_too_large}; - } - - auto next = first + length; - if (prerelease_type != prerelease::none) { - if (prerelease_number.has_value()) { - next = detail::to_chars(next, prerelease_number.value()); - } - next = detail::to_chars(next, prerelease_type); - } - next = detail::to_chars(next, patch); - next = detail::to_chars(next, minor); - next = detail::to_chars(next, major, false); - - return {first + length, std::errc{}}; - } - - [[nodiscard]] constexpr bool from_string_noexcept( - std::string_view str) noexcept { - return from_chars(str.data(), str.data() + str.length()); - } - - constexpr version& from_string(std::string_view str) { - if (!from_string_noexcept(str)) { - SEMVER_THROW("semver::version::from_string invalid version."); - } - - return *this; - } - - [[nodiscard]] std::string to_string() const { - auto str = std::string{}; - detail::resize_uninitialized::resize(str, string_length()); - if (!to_chars(str.data(), str.data() + str.length())) { - SEMVER_THROW("semver::version::to_string invalid version."); - } - - return str; - } - - [[nodiscard]] constexpr std::uint8_t string_length() const noexcept { - // () + 1(.) + () + 1(.) + () - auto length = detail::length(major) + detail::length(minor) + - detail::length(patch) + 2; - if (prerelease_type != prerelease::none) { - // + 1(-) + () - length += detail::length(prerelease_type) + 1; - if (prerelease_number.has_value()) { - // + 1(.) + () - length += detail::length(prerelease_number.value()) + 1; - } - } - - return static_cast(length); - } - - [[nodiscard]] constexpr int compare(const version& other) const noexcept { - if (major != other.major) { - return major - other.major; - } - - if (minor != other.minor) { - return minor - other.minor; - } - - if (patch != other.patch) { - return patch - other.patch; - } - - if (prerelease_type != other.prerelease_type) { - return static_cast(prerelease_type) - - static_cast(other.prerelease_type); - } - - if (prerelease_number.has_value()) { - if (other.prerelease_number.has_value()) { - return prerelease_number.value() - other.prerelease_number.value(); - } - return 1; - } else if (other.prerelease_number.has_value()) { - return -1; - } - - return 0; - } -}; - -[[nodiscard]] constexpr bool operator==(const version& lhs, - const version& rhs) noexcept { - return lhs.compare(rhs) == 0; -} - -[[nodiscard]] constexpr bool operator!=(const version& lhs, - const version& rhs) noexcept { - return lhs.compare(rhs) != 0; -} - -[[nodiscard]] constexpr bool operator>(const version& lhs, - const version& rhs) noexcept { - return lhs.compare(rhs) > 0; -} - -[[nodiscard]] constexpr bool operator>=(const version& lhs, - const version& rhs) noexcept { - return lhs.compare(rhs) >= 0; -} - -[[nodiscard]] constexpr bool operator<(const version& lhs, - const version& rhs) noexcept { - return lhs.compare(rhs) < 0; -} - -[[nodiscard]] constexpr bool operator<=(const version& lhs, - const version& rhs) noexcept { - return lhs.compare(rhs) <= 0; -} - -[[nodiscard]] constexpr version operator""_version(const char* str, - std::size_t length) { - return version{std::string_view{str, length}}; -} - -[[nodiscard]] constexpr bool valid(std::string_view str) noexcept { - return version{}.from_string_noexcept(str); -} - -[[nodiscard]] constexpr from_chars_result from_chars(const char* first, - const char* last, - version& v) noexcept { - return v.from_chars(first, last); -} - -[[nodiscard]] constexpr to_chars_result to_chars(char* first, - char* last, - const version& v) noexcept { - return v.to_chars(first, last); -} - -[[nodiscard]] constexpr std::optional from_string_noexcept( - std::string_view str) noexcept { - if (version v{}; v.from_string_noexcept(str)) { - return v; - } - - return std::nullopt; -} - -[[nodiscard]] constexpr version from_string(std::string_view str) { - return version{str}; -} - -[[nodiscard]] inline std::string to_string(const version& v) { - return v.to_string(); -} - -template -inline std::basic_ostream& operator<<( - std::basic_ostream& os, - const version& v) { - for (const auto c : v.to_string()) { - os.put(c); - } - - return os; -} - -inline namespace comparators { - -enum struct comparators_option : std::uint8_t { - exclude_prerelease, - include_prerelease -}; - -[[nodiscard]] constexpr int compare( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - if (option == comparators_option::exclude_prerelease) { - return version{lhs.major, lhs.minor, lhs.patch}.compare( - version{rhs.major, rhs.minor, rhs.patch}); - } - return lhs.compare(rhs); -} - -[[nodiscard]] constexpr bool equal_to( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - return compare(lhs, rhs, option) == 0; -} - -[[nodiscard]] constexpr bool not_equal_to( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - return compare(lhs, rhs, option) != 0; -} - -[[nodiscard]] constexpr bool greater( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - return compare(lhs, rhs, option) > 0; -} - -[[nodiscard]] constexpr bool greater_equal( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - return compare(lhs, rhs, option) >= 0; -} - -[[nodiscard]] constexpr bool less( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - return compare(lhs, rhs, option) < 0; -} - -[[nodiscard]] constexpr bool less_equal( - const version& lhs, - const version& rhs, - comparators_option option = - comparators_option::include_prerelease) noexcept { - return compare(lhs, rhs, option) <= 0; -} - -} // namespace comparators - -namespace range { - -namespace detail { - -using namespace semver::detail; - -class range { - public: - constexpr explicit range(std::string_view str) noexcept : parser{str} {} - - constexpr bool satisfies(const version& ver, bool include_prerelease) { - const bool has_prerelease = ver.prerelease_type != prerelease::none; - - do { - if (is_logical_or_token()) { - parser.advance_token(range_token_type::logical_or); - } - - bool contains = true; - bool allow_compare = include_prerelease; - - while (is_operator_token() || is_number_token()) { - const auto range = parser.parse_range(); - const bool equal_without_tags = - equal_to(range.ver, ver, comparators_option::exclude_prerelease); - - if (has_prerelease && equal_without_tags) { - allow_compare = true; - } - - if (!range.satisfies(ver)) { - contains = false; - break; - } - } - - if (has_prerelease) { - if (allow_compare && contains) { - return true; - } - } else if (contains) { - return true; - } - - } while (is_logical_or_token()); - - return false; - } - - private: - enum struct range_operator : std::uint8_t { - less, - less_or_equal, - greater, - greater_or_equal, - equal - }; - - struct range_comparator { - range_operator op; - version ver; - - constexpr bool satisfies(const version& version) const { - switch (op) { - case range_operator::equal: - return version == ver; - case range_operator::greater: - return version > ver; - case range_operator::greater_or_equal: - return version >= ver; - case range_operator::less: - return version < ver; - case range_operator::less_or_equal: - return version <= ver; - default: - SEMVER_THROW("semver::range unexpected operator."); - } - } - }; - - enum struct range_token_type : std::uint8_t { - none, - number, - range_operator, - dot, - logical_or, - hyphen, - prerelease, - end_of_line - }; - - struct range_token { - range_token_type type = range_token_type::none; - std::uint8_t number = 0; - range_operator op = range_operator::equal; - prerelease prerelease_type = prerelease::none; - }; - - struct range_lexer { - std::string_view text; - std::size_t pos; - - constexpr explicit range_lexer(std::string_view text) noexcept - : text{text}, pos{0} {} - - constexpr range_token get_next_token() noexcept { - while (!end_of_line()) { - if (is_space(text[pos])) { - advance(1); - continue; - } - - if (is_logical_or(text[pos])) { - advance(2); - return {range_token_type::logical_or}; - } - - if (is_operator(text[pos])) { - const auto op = get_operator(); - return {range_token_type::range_operator, 0, op}; - } - - if (is_digit(text[pos])) { - const auto number = get_number(); - return {range_token_type::number, number}; - } - - if (is_dot(text[pos])) { - advance(1); - return {range_token_type::dot}; - } - - if (is_hyphen(text[pos])) { - advance(1); - return {range_token_type::hyphen}; - } - - if (is_letter(text[pos])) { - const auto prerelease = get_prerelease(); - return {range_token_type::prerelease, 0, range_operator::equal, - prerelease}; - } - } - - return {range_token_type::end_of_line}; - } - - constexpr bool end_of_line() const noexcept { return pos >= text.length(); } - - constexpr void advance(std::size_t i) noexcept { pos += i; } - - constexpr range_operator get_operator() noexcept { - if (text[pos] == '<') { - advance(1); - if (text[pos] == '=') { - advance(1); - return range_operator::less_or_equal; - } - return range_operator::less; - } else if (text[pos] == '>') { - advance(1); - if (text[pos] == '=') { - advance(1); - return range_operator::greater_or_equal; - } - return range_operator::greater; - } else if (text[pos] == '=') { - advance(1); - return range_operator::equal; - } - - return range_operator::equal; - } - - constexpr std::uint8_t get_number() noexcept { - const auto first = text.data() + pos; - const auto last = text.data() + text.length(); - if (std::uint8_t n{}; from_chars(first, last, n) != nullptr) { - advance(length(n)); - return n; - } - - return 0; - } - - constexpr prerelease get_prerelease() noexcept { - const auto first = text.data() + pos; - const auto last = text.data() + text.length(); - if (first > last) { - advance(1); - return prerelease::none; - } - - if (prerelease p{}; from_chars(first, last, p) != nullptr) { - advance(length(p)); - return p; - } - - advance(1); - - return prerelease::none; - } - }; - - struct range_parser { - range_lexer lexer; - range_token current_token; - - constexpr explicit range_parser(std::string_view str) - : lexer{str}, current_token{range_token_type::none} { - advance_token(range_token_type::none); - } - - constexpr void advance_token(range_token_type token_type) { - if (current_token.type != token_type) { - SEMVER_THROW("semver::range unexpected token."); - } - current_token = lexer.get_next_token(); - } - - constexpr range_comparator parse_range() { - if (current_token.type == range_token_type::number) { - const auto version = parse_version(); - return {range_operator::equal, version}; - } else if (current_token.type == range_token_type::range_operator) { - const auto range_operator = current_token.op; - advance_token(range_token_type::range_operator); - const auto version = parse_version(); - return {range_operator, version}; - } - - return {range_operator::equal, version{}}; - } - - constexpr version parse_version() { - const auto major = parse_number(); - - advance_token(range_token_type::dot); - const auto minor = parse_number(); - - advance_token(range_token_type::dot); - const auto patch = parse_number(); - - prerelease prerelease = prerelease::none; - std::optional prerelease_number = std::nullopt; - - if (current_token.type == range_token_type::hyphen) { - advance_token(range_token_type::hyphen); - prerelease = parse_prerelease(); - if (current_token.type == range_token_type::dot) { - advance_token(range_token_type::dot); - prerelease_number = parse_number(); - } - } - - return {major, minor, patch, prerelease, prerelease_number}; - } - - constexpr std::uint8_t parse_number() { - const auto token = current_token; - advance_token(range_token_type::number); - - return token.number; - } - - constexpr prerelease parse_prerelease() { - const auto token = current_token; - advance_token(range_token_type::prerelease); - - return token.prerelease_type; - } - }; - - [[nodiscard]] constexpr bool is_logical_or_token() const noexcept { - return parser.current_token.type == range_token_type::logical_or; - } - [[nodiscard]] constexpr bool is_operator_token() const noexcept { - return parser.current_token.type == range_token_type::range_operator; - } - - [[nodiscard]] constexpr bool is_number_token() const noexcept { - return parser.current_token.type == range_token_type::number; - } - - range_parser parser; -}; - -} // namespace detail - -enum struct satisfies_option : std::uint8_t { - exclude_prerelease, - include_prerelease -}; - -constexpr bool satisfies( - const version& ver, - std::string_view str, - satisfies_option option = satisfies_option::exclude_prerelease) { - switch (option) { - case satisfies_option::exclude_prerelease: - return detail::range{str}.satisfies(ver, false); - case satisfies_option::include_prerelease: - return detail::range{str}.satisfies(ver, true); - default: - SEMVER_THROW("semver::range unexpected satisfies_option."); - } -} - -} // namespace range - -// Version lib semver. -inline constexpr auto semver_version = - version{SEMVER_VERSION_MAJOR, SEMVER_VERSION_MINOR, SEMVER_VERSION_PATCH}; - -} // namespace semver - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -#endif // NEARGYE_SEMANTIC_VERSIONING_HPP \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d132699 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,71 @@ +mod utils; + +use std::str::FromStr; + +use semver::Version; +use utils::{exdll_init, popstring, pushint, stack_t, wchar_t}; +use windows_sys::Win32::Foundation::HWND; + +#[no_mangle] +pub unsafe extern "C" fn SemverCompare( + _hwnd_parent: HWND, + string_size: u32, + variables: *mut wchar_t, + stacktop: *mut *mut stack_t, +) { + exdll_init(string_size, variables, stacktop); + + let v1 = popstring().unwrap(); + let v2 = popstring().unwrap(); + + let ret = semver_compare(&v1, &v2); + pushint(ret); +} + +fn semver_compare(v1: &str, v2: &str) -> i32 { + let v1 = Version::from_str(&v1); + let v2 = Version::from_str(&v2); + + let (v1, v2) = match (v1, v2) { + (Ok(_), Err(_)) => return 1, + (Err(_), Err(_)) => return 0, + (Err(_), Ok(_)) => return -1, + (Ok(v1), Ok(v2)) => (v1, v2), + }; + + if v1 > v2 { + 1 + } else if v1 == v2 { + 0 + } else if v1 < v2 { + -1 + } else { + 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + for (v1, v2, ret) in [ + ("1.2.1", "1.2.0", 1), + ("1.2.0", "1.2.1", -1), + ("1.2.1", "1.2.1", 0), + ("1.2.1-alpha.1", "1.2.1-beta.5", -1), + ("1.2.1-rc.1", "1.2.1-beta.1", 1), + ("1.2.1-alpha.1", "1.2.1-alpha.1", 0), + ("1.2qe2.1-alpha.1", "1.2.1-alpha.1", -1), + ("1.2.1-alpha.1", "-q1.2.1-alpha.1", 1), + ("1.2.saf1-alpha.1", "-q1.2.1-alpha.1", 0), + ("1.0.0-aluc.0", "1.0.0", -1), + (" 1.0.0-aluc.1", "1.0.0-bdfsf.0", -1), + ("1.2.1-fffasd.1", "1.2.1-dasdqwe.1", 1), + ("1.2.1-gasfdlkj.1", "1.2.1-calskjd.1", 1), + ] { + assert_eq!(semver_compare(v1, v2), ret); + } + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ec3eebc --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,82 @@ +#![allow(non_camel_case_types)] + +use std::{ + ffi::{OsStr, OsString}, + iter::once, + mem::{size_of, size_of_val}, + os::windows::prelude::{OsStrExt, OsStringExt}, +}; + +use windows_sys::Win32::{ + Globalization::{lstrcpyW, lstrcpynW}, + System::Memory::{GlobalAlloc, GlobalFree, GPTR}, +}; + +static mut G_STRINGSIZE: u32 = 0; +static mut G_VARIABLES: *mut wchar_t = std::ptr::null_mut(); +static mut G_STACKTOP: *mut *mut stack_t = std::ptr::null_mut(); + +pub unsafe fn exdll_init(string_size: u32, variables: *mut wchar_t, stacktop: *mut *mut stack_t) { + G_STRINGSIZE = string_size; + G_VARIABLES = variables; + G_STACKTOP = stacktop; +} + +pub type wchar_t = i32; + +#[repr(C)] +#[derive(Debug)] +pub struct stack_t { + next: *mut stack_t, + text: [wchar_t; 1], +} + +pub unsafe fn pushstring(s: impl AsRef) { + if G_STACKTOP.is_null() { + return; + } + + let string_wide = encode_wide(s); + let th: *mut stack_t = GlobalAlloc( + GPTR, + size_of::() + G_STRINGSIZE as usize * size_of_val(&string_wide), + ) as _; + lstrcpynW( + (*th).text.as_ptr() as _, + string_wide.as_ptr() as _, + G_STRINGSIZE as _, + ); + (*th).next = *G_STACKTOP; + *G_STACKTOP = th; +} + +pub unsafe fn popstring() -> Result { + if G_STACKTOP.is_null() || (*G_STACKTOP).is_null() { + return Err(()); + } + + let mut string_wide: Vec = vec![0; G_STRINGSIZE as _]; + let th: *mut stack_t = *G_STACKTOP; + lstrcpyW(string_wide.as_mut_ptr(), (*th).text.as_ptr() as _); + let string = decode_wide(&string_wide).to_str().ok_or(())?.to_string(); + *G_STACKTOP = (*th).next; + GlobalFree(th as _); + + Ok(string) +} + +pub unsafe fn pushint(int: i32) { + pushstring(int.to_string()) +} + +fn encode_wide(string: impl AsRef) -> Vec { + string.as_ref().encode_wide().chain(once(0)).collect() +} + +pub fn decode_wide(mut wide_c_string: &[u16]) -> OsString { + if let Some(null_pos) = wide_c_string.iter().position(|c| *c == 0) { + wide_c_string = &wide_c_string[..null_pos]; + } + + OsString::from_wide(wide_c_string) +}