diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..d92ae8838 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,43 @@ +name: Linux + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +concurrency: + group: linux-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - name: Install dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq ninja-build libwxgtk3.2-dev libssl-dev libgmp-dev libglu1-mesa-dev xvfb xauth + - name: Configure + run: cmake -S . -B build -G Ninja -DMFCWX_TESTS=ON -DCRYPTOOL_THIRDPARTY_TESTS=ON + - name: Build + run: ninja -C build + - name: Test + run: xvfb-run -a ctest --test-dir build --output-on-failure --timeout 300 + - name: Start CrypTool + env: + MFCWX_SNAPSHOT_DIR: ${{ runner.temp }}/snapshots + MFCWX_SNAPSHOT_COUNT: 3 + MFCWX_SNAPSHOT_DISMISS: 1 + MFCWX_SNAPSHOT_INTERVAL: 3000 + run: | + mkdir -p "$MFCWX_SNAPSHOT_DIR" + timeout 120 xvfb-run -a -s "-screen 0 1600x1000x24" build/port/app/CrypTool + ls "$MFCWX_SNAPSHOT_DIR"/*.png + - uses: actions/upload-artifact@v7 + if: always() + with: + name: linux-snapshots + path: ${{ runner.temp }}/snapshots + if-no-files-found: ignore diff --git a/.github/workflows/port-status.yml b/.github/workflows/port-status.yml new file mode 100644 index 000000000..c4aeb0bfd --- /dev/null +++ b/.github/workflows/port-status.yml @@ -0,0 +1,43 @@ +name: Port status + +on: + push: + branches: [xplat-port] + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: port-status + cancel-in-progress: true + +jobs: + status: + runs-on: macos-latest + steps: + - uses: actions/checkout@v5 + - name: Install dependencies + run: brew install wxwidgets@3.2 openssl@3 gmp ninja cmake + - name: Measure + run: python3 port/tools/port_status.py + - name: Publish to the port-status branch + run: | + pub="$RUNNER_TEMP/port-status" + git init -q "$pub" + cd "$pub" + git config user.name "port-status-bot" + git config user.email "port-status-bot@users.noreply.github.com" + git remote add origin "$(git -C "$GITHUB_WORKSPACE" config --get remote.origin.url)" + git -C "$GITHUB_WORKSPACE" config --get-regexp '^http\..*\.extraheader$' | while read -r key value; do + git config "$key" "$value" + done + if git fetch -q --depth 1 origin port-status; then + git checkout -q -b port-status FETCH_HEAD + else + git checkout -q --orphan port-status + fi + cp "$GITHUB_WORKSPACE"/port/status/* . + git add badge.json status.json STATUS.md + git diff --cached --quiet || git commit -m "chore(status): update port status for ${GITHUB_SHA::8}" + git push origin port-status diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..e68f702d1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,88 @@ +name: Release + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: write + +jobs: + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v5 + - name: Install dependencies + run: brew install wxwidgets@3.2 openssl@3 gmp ninja cmake + - name: Build + run: | + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release + ninja -C build + - name: Package + run: cd build && cpack -G DragNDrop + - uses: actions/upload-artifact@v7 + with: + name: macos + path: build/CrypTool-*.dmg + if-no-files-found: error + + linux: + strategy: + matrix: + runner: [ubuntu-24.04, ubuntu-24.04-arm] + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v5 + - name: Install dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq ninja-build libwxgtk3.2-dev libssl-dev libgmp-dev libglu1-mesa-dev xvfb xauth + - name: Build + run: | + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr + ninja -C build + - name: Start CrypTool + env: + MFCWX_SNAPSHOT_DIR: ${{ runner.temp }}/snapshots + MFCWX_SNAPSHOT_COUNT: 2 + MFCWX_SNAPSHOT_DISMISS: 1 + MFCWX_SNAPSHOT_INTERVAL: 3000 + run: | + mkdir -p "$MFCWX_SNAPSHOT_DIR" + timeout 120 xvfb-run -a build/port/app/CrypTool + ls "$MFCWX_SNAPSHOT_DIR"/*.png + - name: Package + run: cd build && cpack -G "DEB;TGZ" + - uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.runner }} + path: | + build/CrypTool-*.deb + build/CrypTool-*.tar.gz + if-no-files-found: error + + release: + needs: [macos, linux] + if: github.event_name != 'pull_request' + runs-on: ubuntu-24.04 + steps: + - uses: actions/download-artifact@v8 + with: + path: dist + merge-multiple: true + - uses: actions/checkout@v5 + with: + sparse-checkout: CMakeLists.txt + sparse-checkout-cone-mode: false + path: src + - name: Create the release + env: + GH_TOKEN: ${{ github.token }} + run: | + version=$(sed -n 's/^project([^ ]* VERSION \([0-9.]*\).*/\1/p' src/CMakeLists.txt) + tag="v${version}-build.${GITHUB_RUN_NUMBER}" + ls -la dist + gh release create "$tag" dist/* --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" \ + --title "CrypTool ${version} (build ${GITHUB_RUN_NUMBER})" --generate-notes diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..d64bc8a6e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +build/ +build-*/ +port/secude/build*/ +port/thirdparty/build*/ +port/rc/test/build*/ +__pycache__/ +port/status/ +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..3810ed603 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.20) + +project(CrypTool1 VERSION 1.4.43 LANGUAGES C CXX) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type" FORCE) +endif() + +set(REPO_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) +enable_testing() + +if(APPLE) + foreach(prefix /opt/homebrew/opt /usr/local/opt) + if(EXISTS ${prefix}/wxwidgets@3.2/bin/wx-config-3.2 AND NOT wxWidgets_CONFIG_EXECUTABLE) + set(wxWidgets_CONFIG_EXECUTABLE ${prefix}/wxwidgets@3.2/bin/wx-config-3.2) + endif() + if(EXISTS ${prefix}/openssl@3 AND NOT OPENSSL_ROOT_DIR) + set(OPENSSL_ROOT_DIR ${prefix}/openssl@3) + endif() + endforeach() +endif() + +find_package(wxWidgets 3.2 REQUIRED COMPONENTS stc aui html gl adv xml core base) +find_package(OpenSSL 3 REQUIRED) +find_package(OpenGL REQUIRED) +find_package(Threads REQUIRED) + +add_subdirectory(port/thirdparty) +add_subdirectory(port/secude) +if(TARGET secude_compat) + # The application is C++14; the library may use a newer standard internally. + set_property(TARGET secude_compat PROPERTY INTERFACE_COMPILE_FEATURES "") +endif() +add_subdirectory(port/mfcwx) +add_subdirectory(port/app) + +option(CRYPTOOL_DIALOG_GALLERY "Build the dialog snapshot tool" OFF) +if(CRYPTOOL_DIALOG_GALLERY) + add_subdirectory(port/tools/gallery) +endif() diff --git a/ChallengeResponse/ChallengeResponseDlg.cpp b/ChallengeResponse/ChallengeResponseDlg.cpp index 0dfac2d27..d395339d4 100644 --- a/ChallengeResponse/ChallengeResponseDlg.cpp +++ b/ChallengeResponse/ChallengeResponseDlg.cpp @@ -72,30 +72,30 @@ BEGIN_MESSAGE_MAP(CChallengeResponseDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_CREATE() - ON_BN_CLICKED(IDC_EXIT_BUTTON, OnExitButton) - ON_BN_CLICKED(IDC_START_RADIO, OnModeRadioButtons) + ON_BN_CLICKED(IDC_EXIT_BUTTON, &CChallengeResponseDlg::OnExitButton) + ON_BN_CLICKED(IDC_START_RADIO, &CChallengeResponseDlg::OnModeRadioButtons) ON_WM_MOUSEMOVE() - ON_BN_CLICKED(IDC_ACTION_ATTACK_RADIO, OnChangeAction) + ON_BN_CLICKED(IDC_ACTION_ATTACK_RADIO, &CChallengeResponseDlg::OnChangeAction) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() - ON_BN_CLICKED(IDC_AUTHENTICATE_CLIENT_BUTTON, OnAuthenticateClientButton) + ON_BN_CLICKED(IDC_AUTHENTICATE_CLIENT_BUTTON, &CChallengeResponseDlg::OnAuthenticateClientButton) ON_WM_DESTROY() ON_WM_TIMER() - ON_BN_CLICKED(IDC_AUTHENTICATE_ATTACKER_BUTTON, OnAuthenticateAttackerButton) - ON_BN_CLICKED(IDC_CHECK_MASK, OnCheckMask) - ON_BN_CLICKED(IDC_SCENARIO_HELP_BUTTON, OnScenarioHelpButton) - ON_BN_CLICKED(IDC_RESET_BUTTON, OnResetButton) - ON_BN_CLICKED(IDC_HELP, OnHelp) - ON_BN_CLICKED(IDC_EINFUEHRUNG_RADIO, OnModeRadioButtons) - ON_BN_CLICKED(IDC_PASSWORT_RADIO, OnModeRadioButtons) - ON_BN_CLICKED(IDC_EINMALPASSWOERTER, OnModeRadioButtons) - ON_BN_CLICKED(IDC_CHALLENGERESPONSE1_RADIO, OnModeRadioButtons) - ON_BN_CLICKED(IDC_CHALLENGERESPONSE2_RADIO, OnModeRadioButtons) - ON_BN_CLICKED(IDC_WECHSELSEITIG_RADIO, OnModeRadioButtons) - ON_BN_CLICKED(IDC_ACTION_CONNECT_RADIO, OnChangeAction) - ON_BN_CLICKED(IDC_ACTION_DISCONNECT_RADIO, OnChangeAction) - ON_BN_CLICKED(IDC_ACTION_NOTHING_RADIO, OnChangeAction) - ON_BN_CLICKED(IDC_ACTION_REMOVE_ATTACK_RADIO, OnChangeAction) + ON_BN_CLICKED(IDC_AUTHENTICATE_ATTACKER_BUTTON, &CChallengeResponseDlg::OnAuthenticateAttackerButton) + ON_BN_CLICKED(IDC_CHECK_MASK, &CChallengeResponseDlg::OnCheckMask) + ON_BN_CLICKED(IDC_SCENARIO_HELP_BUTTON, &CChallengeResponseDlg::OnScenarioHelpButton) + ON_BN_CLICKED(IDC_RESET_BUTTON, &CChallengeResponseDlg::OnResetButton) + ON_BN_CLICKED((UINT)(UINT_PTR)IDC_HELP, &CChallengeResponseDlg::OnHelp) + ON_BN_CLICKED(IDC_EINFUEHRUNG_RADIO, &CChallengeResponseDlg::OnModeRadioButtons) + ON_BN_CLICKED(IDC_PASSWORT_RADIO, &CChallengeResponseDlg::OnModeRadioButtons) + ON_BN_CLICKED(IDC_EINMALPASSWOERTER, &CChallengeResponseDlg::OnModeRadioButtons) + ON_BN_CLICKED(IDC_CHALLENGERESPONSE1_RADIO, &CChallengeResponseDlg::OnModeRadioButtons) + ON_BN_CLICKED(IDC_CHALLENGERESPONSE2_RADIO, &CChallengeResponseDlg::OnModeRadioButtons) + ON_BN_CLICKED(IDC_WECHSELSEITIG_RADIO, &CChallengeResponseDlg::OnModeRadioButtons) + ON_BN_CLICKED(IDC_ACTION_CONNECT_RADIO, &CChallengeResponseDlg::OnChangeAction) + ON_BN_CLICKED(IDC_ACTION_DISCONNECT_RADIO, &CChallengeResponseDlg::OnChangeAction) + ON_BN_CLICKED(IDC_ACTION_NOTHING_RADIO, &CChallengeResponseDlg::OnChangeAction) + ON_BN_CLICKED(IDC_ACTION_REMOVE_ATTACK_RADIO, &CChallengeResponseDlg::OnChangeAction) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -234,9 +234,9 @@ void CChallengeResponseDlg::OnMouseMove(UINT nFlags, CPoint point) if (scenario.isMouseOverObject(m_action,point)){ - ::SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)hCmark); + ::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,(LONG_PTR)hCmark); }else{ - ::SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)hCstandard); + ::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,(LONG_PTR)hCstandard); } CDialog::OnMouseMove(nFlags, point); } diff --git a/ChallengeResponse/Computer.cpp b/ChallengeResponse/Computer.cpp index 5a947629b..be14836b6 100644 --- a/ChallengeResponse/Computer.cpp +++ b/ChallengeResponse/Computer.cpp @@ -58,7 +58,7 @@ bool CComputer::isMouseOverObject(CPoint &point) } -void CComputer::setParameters(int x1, int y1, int x2, int y2, int borderWidth, CString &name, int textPosition, int dataPosition, bool isAttacker) +void CComputer::setParameters(int x1, int y1, int x2, int y2, int borderWidth, const CString &name, int textPosition, int dataPosition, bool isAttacker) { setParametersSO(x1,y1,x2,y2,borderWidth); this->name=name; @@ -95,8 +95,8 @@ void CComputer::draw(CClientDC &dc) drawDataText(dc); - dc.SelectObject(&originalFont); - dc.SelectObject(&originalPen); + dc.SelectObject(originalFont); + dc.SelectObject(originalPen); } void CComputer::drawDataText(CClientDC &dc) @@ -123,7 +123,7 @@ void CComputer::eraseDataText(CClientDC &dc) dc.SetTextColor(white); originalFont = dc.SelectObject(&dataFont); drawDataText(dc); - dc.SelectObject(&originalFont); + dc.SelectObject(originalFont); } int CComputer::getX1() diff --git a/ChallengeResponse/Computer.h b/ChallengeResponse/Computer.h index a5b82b003..9aad3c3a0 100644 --- a/ChallengeResponse/Computer.h +++ b/ChallengeResponse/Computer.h @@ -43,7 +43,7 @@ class CComputer : CScenarioObject void draw(CClientDC& dc); - void setParameters(int x1,int y1, int x2, int y2, int borderwidth, CString& name, int textposition, int dataposition, bool isAttacker); + void setParameters(int x1,int y1, int x2, int y2, int borderwidth, const CString& name, int textposition, int dataposition, bool isAttacker); bool isMouseOverObject(CPoint &point); // eigene Variablen & Methoden diff --git a/ChallengeResponse/Packet.cpp b/ChallengeResponse/Packet.cpp index f294adcb4..281501b56 100644 --- a/ChallengeResponse/Packet.cpp +++ b/ChallengeResponse/Packet.cpp @@ -59,7 +59,7 @@ void CPacket::draw(CClientDC &dc) dc.MoveTo(x1+1,y2-1); dc.LineTo(x2-1,y1+1); - dc.SelectObject(&originalPen); + dc.SelectObject(originalPen); } void CPacket::erase(CClientDC &dc) @@ -73,7 +73,7 @@ void CPacket::erase(CClientDC &dc) dc.MoveTo(x1,y2); dc.LineTo(x2,y1); - dc.SelectObject(&originalPen); + dc.SelectObject(originalPen); } diff --git a/ChallengeResponse/Scenario.cpp b/ChallengeResponse/Scenario.cpp index ed8986040..d32fe2f8e 100644 --- a/ChallengeResponse/Scenario.cpp +++ b/ChallengeResponse/Scenario.cpp @@ -25,7 +25,7 @@ #include "stdafx.h" #include "Scenario.h" #include "ScenarioObject.h" -#include "wire.h" +#include "Wire.h" #include "resource.h" #ifdef _DEBUG diff --git a/ChallengeResponse/Wire.cpp b/ChallengeResponse/Wire.cpp index d53cc4bab..c14213776 100644 --- a/ChallengeResponse/Wire.cpp +++ b/ChallengeResponse/Wire.cpp @@ -137,7 +137,7 @@ void CWire::draw(CClientDC& dc) } } - dc.SelectObject(&originalPen); + dc.SelectObject(originalPen); } diff --git a/CrypTool/3DVisOpt.cpp b/CrypTool/3DVisOpt.cpp index ac33b93ee..92c0f0569 100644 --- a/CrypTool/3DVisOpt.cpp +++ b/CrypTool/3DVisOpt.cpp @@ -81,13 +81,13 @@ void C3DVisOpt::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(C3DVisOpt, CDialog) //{{AFX_MSG_MAP(C3DVisOpt) - ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_RESOLUTION, OnReleasedcaptureSliderResolution) - ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_DENSITY, OnReleasedcaptureSliderDensity) - ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_SHIFT, OnReleasedcaptureSliderShift) - ON_BN_CLICKED(IDC_RADIO_WORDSIZE_1, OnRadioWordsize1) - ON_BN_CLICKED(IDC_RADIO_WORDSIZE_2, OnRadioWordsize2) - ON_BN_CLICKED(IDC_RADIO_WORDSIZE_4, OnRadioWordsize4) - ON_BN_CLICKED(IDC_BUTTON_RESET, OnButtonReset) + ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_RESOLUTION, &C3DVisOpt::OnReleasedcaptureSliderResolution) + ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_DENSITY, &C3DVisOpt::OnReleasedcaptureSliderDensity) + ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_SHIFT, &C3DVisOpt::OnReleasedcaptureSliderShift) + ON_BN_CLICKED(IDC_RADIO_WORDSIZE_1, &C3DVisOpt::OnRadioWordsize1) + ON_BN_CLICKED(IDC_RADIO_WORDSIZE_2, &C3DVisOpt::OnRadioWordsize2) + ON_BN_CLICKED(IDC_RADIO_WORDSIZE_4, &C3DVisOpt::OnRadioWordsize4) + ON_BN_CLICKED(IDC_BUTTON_RESET, &C3DVisOpt::OnButtonReset) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/ASN1Decoder.h b/CrypTool/ASN1Decoder.h index 240c326f3..1654b2ff4 100644 --- a/CrypTool/ASN1Decoder.h +++ b/CrypTool/ASN1Decoder.h @@ -38,7 +38,16 @@ using namespace std; #endif -class ASN1Error; +// Klasse zur Ausnahmebehandlung/Fehlerbehandlung +class ASN1Error +{ +private: + long ErrorCode; +public: + ASN1Error(long e){ ErrorCode = e;}; + virtual ~ASN1Error() { }; + long GetErrorCode() const { return ErrorCode; }; +}; class ASN1Decoder { @@ -63,17 +72,6 @@ class ASN1Decoder void StoreCertDump(std::string, std::string) throw (ASN1Error); }; -// Klasse zur Ausnahmebehandlung/Fehlerbehandlung -class ASN1Error -{ -private: - long ErrorCode; -public: - ASN1Error(long e){ ErrorCode = e;}; - virtual ~ASN1Error() { }; - long GetErrorCode() const { return ErrorCode; }; -}; - // Fehlermeldungen #define E_INVALID_FILENAME 1 #define E_NO_VALID_ASN1_STRUCTURE 2 diff --git a/CrypTool/AlphabetTextEdit.cpp b/CrypTool/AlphabetTextEdit.cpp index 4a136af24..f956fd336 100644 --- a/CrypTool/AlphabetTextEdit.cpp +++ b/CrypTool/AlphabetTextEdit.cpp @@ -42,10 +42,10 @@ CAlphabetTextEdit::~CAlphabetTextEdit() { BEGIN_MESSAGE_MAP(CAlphabetTextEdit, CEdit) ON_WM_CHAR() ON_WM_KEYDOWN() - ON_COMMAND(ID_EDIT_CUT, onEditCut) - ON_COMMAND(ID_EDIT_COPY, onEditCopy) - ON_COMMAND(ID_EDIT_PASTE, onEditPaste) - ON_COMMAND(ID_EDIT_SELECT_ALL, onEditSelectAll) + ON_COMMAND(ID_EDIT_CUT, &CAlphabetTextEdit::onEditCut) + ON_COMMAND(ID_EDIT_COPY, &CAlphabetTextEdit::onEditCopy) + ON_COMMAND(ID_EDIT_PASTE, &CAlphabetTextEdit::onEditPaste) + ON_COMMAND(ID_EDIT_SELECT_ALL, &CAlphabetTextEdit::onEditSelectAll) END_MESSAGE_MAP() void CAlphabetTextEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { diff --git a/CrypTool/AppDocument.cpp b/CrypTool/AppDocument.cpp index 04fe4f32f..1279aa08e 100644 --- a/CrypTool/AppDocument.cpp +++ b/CrypTool/AppDocument.cpp @@ -21,7 +21,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "AppDocument.h" -#include "Windows.h" +#include "windows.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -57,8 +57,8 @@ CAppDocument::~CAppDocument() BEGIN_MESSAGE_MAP(CAppDocument, CDocument) //{{AFX_MSG_MAP(CAppDocument) - ON_UPDATE_COMMAND_UI(ID_GOTO_VATER, OnUpdateGotoVater) - ON_UPDATE_COMMAND_UI(ID_SHOW_KEY, OnUpdateShowKey) + ON_UPDATE_COMMAND_UI(ID_GOTO_VATER, &CAppDocument::OnUpdateGotoVater) + ON_UPDATE_COMMAND_UI(ID_SHOW_KEY, &CAppDocument::OnUpdateShowKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/AutomaticAnalysis.cpp b/CrypTool/AutomaticAnalysis.cpp index cb868dfb1..9bed7132d 100644 --- a/CrypTool/AutomaticAnalysis.cpp +++ b/CrypTool/AutomaticAnalysis.cpp @@ -76,7 +76,7 @@ void CaesarAuto(const char *infile, const char *OldTitle) HistogramASCII(theApp.TextOptions.getReferenceFilePath(), theApp.TextOptions.getReferenceFileName()); HistogramASCII(infile, OldTitle); LoadString(AfxGetInstanceHandle(),IDS_STRING_MSG_CMP_CIPHER_REFERENCE,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(line, pc_str, theApp.TextOptions.getReferenceFileName()); + sprintf(line, pc_str, (LPCTSTR)theApp.TextOptions.getReferenceFileName()); LoadString(AfxGetInstanceHandle(),IDS_STRING_ANALYSE_CAESAR,pc_str1,STR_LAENGE_STRING_TABLE); theApp.m_MainWnd->MessageBox(line, pc_str1, MB_OK); } @@ -115,7 +115,7 @@ void CaesarAuto(const char *infile, const char *OldTitle) LoadString(AfxGetInstanceHandle(),IDS_STRING_CORRELATION,pc_str,STR_LAENGE_STRING_TABLE); MakeNewName2(line,sizeof(line),pc_str,theApp.TextOptions.getReferenceFileName(), OldTitle); - c.Show(OStream(name)<< OStream::Title(0) << OStream::Description(0) << OStream::Summary(0)); + { OStream os(name); c.Show(os << OStream::Title(0) << OStream::Description(0) << OStream::Summary(0)); } // == get the tmp name without file extension strcpy(name2, name); @@ -308,9 +308,9 @@ UINT VigenereAuto(PVOID p) // Ausgabe der Korrelation zwischen deutschem Text und dem Chiffrat GetTmpName(name,"cry",".plt"); LoadString(AfxGetInstanceHandle(),IDS_STRING_MSG_CORRELATION_CAESAR_REFERENCE,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(line,pc_str,i+1, theApp.TextOptions.getReferenceFileName()); + sprintf(line,pc_str,i+1, (LPCTSTR)theApp.TextOptions.getReferenceFileName()); - c.Show(OStream(name)<< OStream::Title(0) << OStream::Description(0) << OStream::Summary(0)); + { OStream os(name); c.Show(os << OStream::Title(0) << OStream::Description(0) << OStream::Summary(0)); } // get the tmp name without file extension strcpy(name2, name); diff --git a/CrypTool/Ber_Ell_Kurve.h b/CrypTool/Ber_Ell_Kurve.h index 198663344..6f919eb1c 100644 --- a/CrypTool/Ber_Ell_Kurve.h +++ b/CrypTool/Ber_Ell_Kurve.h @@ -25,7 +25,7 @@ #if !defined(AFX_BER_ELL_KURVE_H__DED21344_096E_11D5_8899_00062919F268__INCLUDED_) #define AFX_BER_ELL_KURVE_H__DED21344_096E_11D5_8899_00062919F268__INCLUDED_ -#include "..\LIBMIRACL\INCLUDE\BIG.H" // Hinzugefügt von der Klassenansicht +#include "big.h" // Hinzugefügt von der Klassenansicht #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 @@ -35,10 +35,10 @@ #define RAISE '^' #include -#include "elliptic.h" -#include "comflash.h" -#include "fpoly.h" -#include "poly.h" +#include "ELLIPTIC.H" +#include "COMFLASH.H" +#include "FPOLY.H" +#include "POLY.H" #include #if defined(_MSC_VER) || _MSC_VER <= 1200 diff --git a/CrypTool/BloemerMayAttack.h b/CrypTool/BloemerMayAttack.h index 88bd8178e..0fd71043b 100644 --- a/CrypTool/BloemerMayAttack.h +++ b/CrypTool/BloemerMayAttack.h @@ -95,7 +95,7 @@ class BloemerMayAttack bool FindRoots(ZZX f, vec_ZZ& r); ZZXY *polyPowers; // represent the f(xX,yX)^k polynomials mat_ZZ Lattice; // the lattice to be reduced - ZZ BloemerMayAttack::binom(int i, int j); + ZZ binom(int i, int j); static long StopLLL(const vec_ZZ& z); diff --git a/CrypTool/BruteForceHeap.cpp b/CrypTool/BruteForceHeap.cpp index c6f959edf..dcb9fa17a 100644 --- a/CrypTool/BruteForceHeap.cpp +++ b/CrypTool/BruteForceHeap.cpp @@ -18,7 +18,8 @@ **************************************************************************/ -#include ".\bruteforceheap.h" +#include "BruteForceHeap.h" +#include diff --git a/CrypTool/COMFLASH.CPP b/CrypTool/COMFLASH.CPP index 3a50262db..e5265efd7 100644 --- a/CrypTool/COMFLASH.CPP +++ b/CrypTool/COMFLASH.CPP @@ -18,7 +18,7 @@ **************************************************************************/ -#include "comflash.h" +#include "COMFLASH.H" Complex& Complex::operator=(const Complex& a) diff --git a/CrypTool/COMFLASH.H b/CrypTool/COMFLASH.H index a7ad02dcf..8828a1010 100644 --- a/CrypTool/COMFLASH.H +++ b/CrypTool/COMFLASH.H @@ -33,7 +33,7 @@ #include using namespace std; #endif -#include "flash.h" +#include "FLASH.H" class Complex { diff --git a/CrypTool/CoreCryptography.cpp b/CrypTool/CoreCryptography.cpp index 27d0d6064..c3916c28e 100644 --- a/CrypTool/CoreCryptography.cpp +++ b/CrypTool/CoreCryptography.cpp @@ -19,11 +19,11 @@ **************************************************************************/ #include "CoreCryptography.h" -#include "..\AES\mars\mars.h" -#include "..\AES\RC6\RC6.h" -#include "..\AES\Rijndael\Rijndael-api-fst.h" -#include "..\AES\Serpent\Serpent.h" -#include "..\AES\Twofish\Twofish.h" +#include "mars.h" +#include "RC6.h" +#include "Rijndael-api-fst.h" +#include "Serpent.h" +#include "Twofish.h" #include "DESXL.h" #include "resource.h" diff --git a/CrypTool/CrypToolApp.cpp b/CrypTool/CrypToolApp.cpp index 25b7f6c08..663933ca3 100644 --- a/CrypTool/CrypToolApp.cpp +++ b/CrypTool/CrypToolApp.cpp @@ -89,10 +89,10 @@ #include "DlgComputeMersenneNumbers.h" // #if !defined(_MSC_VER) || _MSC_VER <= 1200 -#include "RSABloemerMayDlg.h" -#include "RSAStereotypedMSGDlg.h" -#include "RSAFactorHintDlg.h" -#include ".\cryptoolapp.h" +#include "rsabloemermaydlg.h" +#include "rsastereotypedmsgdlg.h" +#include "rsafactorhintdlg.h" +#include "CrypToolApp.h" #include "CrypToolTools.h" // #endif @@ -144,79 +144,79 @@ CCrypToolApp NEAR theApp; BEGIN_MESSAGE_MAP(CCrypToolApp, CWinApp) //{{AFX_MSG_MAP(CCrypToolApp) - ON_COMMAND(ID_APP_ABOUT, OnAppAbout) - ON_COMMAND(ID_OPTIONS_ANALYSIS, OnOptionsAnalysis) - ON_COMMAND(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll) - ON_COMMAND(ID_OPTTEXT, OnOpttext) - ON_UPDATE_COMMAND_UI(ID_CRYPT_KeyGen, OnUpdateNeedSecudeTicket) - ON_COMMAND(ID_SHOW_ALL_EC_KEYS, OnShowKeys) - ON_COMMAND(ID_CRYPT_KeyGen, OnKeyGen) - ON_COMMAND(ID_EINZELVERFAHREN_TUTORIAL_PRIMZAHLENGENERIEREN, OnEinzelverfahrenTutorialPrimzahlengenerieren) - ON_COMMAND(ID_EINZELVERFAHREN_TUTORIAL_RSAALGORITHMUS, OnEinzelverfahrenTutorialRsaalgorithmus) - ON_COMMAND(ID_EINZELVERFAHREN_TUTORIALFRKLEINEZAHLEN_FAKTORISIERENIFP, OnEinzelverfahrenTutorialfrkleinezahlenFaktorisieren) - ON_COMMAND(ID_EINZELVERFAHREN_SCHLUESSELGENERIEREN, OnEinzelverfahrenSchluesselgenerieren) - ON_COMMAND(ID_ZUFALL_GENERATOREN, OnGenRandomData) - ON_COMMAND(ID_HASH_OFAFILE, OnHashOfAFile) - ON_COMMAND(ID_EINZELVERFAHREN_SIGN, OnEinzelverfahrenTutorialSignaturerzeugung) - ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, OnVerentschlsselnHybridverfahrenHybridverschlsselung) - ON_COMMAND(ID_OPTIONS_STARTOPTIONS, OnOptionsStartoptions) - ON_COMMAND(ID_HILFE_INDEX, OnHilfeIndex) - ON_COMMAND(ID_HILFE_STARTSEITE, OnHilfeStartseite) - ON_COMMAND(ID_HILFE_SZENARIEN, OnHilfeSzenarien) - ON_COMMAND(ID_SIGNATUR_ATTACK, OnSignaturAttack) - ON_COMMAND(ID_EINZELVERFAHREN_DIFFIEHELLMANDEMO, OnEinzelverfahrenDiffiehellmandemo) - ON_COMMAND(ID_SIGATTMODIFICDEMO, OnSigattmodificdemo) - ON_COMMAND(ID_LOAD_README, OnLoadReadme) - ON_COMMAND(ID_SCRIPT, OnScript) - ON_COMMAND(ID_HELP_PRESENTATION, OnPresentation) - ON_COMMAND(ID_EINZELVERFAHREN_SIDECHANNELATTACK_ON_HYBRIDENCRYPTION, OnEinzelverfahrenSidechannelattackOnHybridencryption) - ON_COMMAND(ID_PASSWORDQUALITYMETER, OnPasswordQualityMeter) - ON_COMMAND(ID_PASSWORDENTROPY, OnPasswordEntropy) - ON_COMMAND(ID_LENGTHOFANUMBER, OnLengthOfANumber) - ON_COMMAND(ID_CHALLENGE_RESPONSE, OnChallengeResponse) - ON_COMMAND(ID_RSA_FACTORHINT, OnRsaFactorhint) - ON_COMMAND(ID_RSA_STEREOTYPED, OnRsaStereotyped) - ON_COMMAND(ID_RSA_BLOEMERMAY, OnRsaBloemermay) - ON_COMMAND(ID_HELP_ANIMAL_CAESAR, OnAnimalCaesar) - ON_COMMAND(ID_HELP_ANIMAL_VIGENERE, OnAnimalVigenere) - ON_COMMAND(ID_HELP_ANIMAL_NIHILIST, OnAnimalNihilist) - ON_COMMAND(ID_HELP_ANIMAL_DES, OnAnimalDes) - ON_COMMAND(ID_INDIV_CRT_PLANET, OnIndivCrtPlanet) - ON_COMMAND(ID_INDIV_CRT_DEMO, OnIndivCrtDemo) - ON_COMMAND(ID_INDIV_CRT_SECRETSHARING, OnIndivCrtSecretsharing) - ON_COMMAND(ID_NUMBERSHARK, OnNumberShark) - ON_UPDATE_COMMAND_UI(ID_NUMBERSHARK, OnUpdateNumberShark) - ON_UPDATE_COMMAND_UI(ID_SHOW_ALL_EC_KEYS, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_CRYPT_KeyGen, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDENTSCHLSSELUNG, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_HASH_OFAFILE, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_SIGN, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_SCHLUESSELGENERIEREN, OnUpdateNeedSecudeTicket) - ON_COMMAND(ID_INDIVIDUAL_PROCEDURES_SECRETSHARING, OnIndividualProceduresSecretsharing) - ON_COMMAND(ID_GENERATION_TADIC_NAF_KEYS, OnGenerationTAdicNAFKeys) + ON_COMMAND(ID_APP_ABOUT, &CCrypToolApp::OnAppAbout) + ON_COMMAND(ID_OPTIONS_ANALYSIS, &CCrypToolApp::OnOptionsAnalysis) + ON_COMMAND(ID_WINDOW_CLOSE_ALL, &CCrypToolApp::OnWindowCloseAll) + ON_COMMAND(ID_OPTTEXT, &CCrypToolApp::OnOpttext) + ON_UPDATE_COMMAND_UI(ID_CRYPT_KeyGen, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_COMMAND(ID_SHOW_ALL_EC_KEYS, &CCrypToolApp::OnShowKeys) + ON_COMMAND(ID_CRYPT_KeyGen, &CCrypToolApp::OnKeyGen) + ON_COMMAND(ID_EINZELVERFAHREN_TUTORIAL_PRIMZAHLENGENERIEREN, &CCrypToolApp::OnEinzelverfahrenTutorialPrimzahlengenerieren) + ON_COMMAND(ID_EINZELVERFAHREN_TUTORIAL_RSAALGORITHMUS, &CCrypToolApp::OnEinzelverfahrenTutorialRsaalgorithmus) + ON_COMMAND(ID_EINZELVERFAHREN_TUTORIALFRKLEINEZAHLEN_FAKTORISIERENIFP, &CCrypToolApp::OnEinzelverfahrenTutorialfrkleinezahlenFaktorisieren) + ON_COMMAND(ID_EINZELVERFAHREN_SCHLUESSELGENERIEREN, &CCrypToolApp::OnEinzelverfahrenSchluesselgenerieren) + ON_COMMAND(ID_ZUFALL_GENERATOREN, &CCrypToolApp::OnGenRandomData) + ON_COMMAND(ID_HASH_OFAFILE, &CCrypToolApp::OnHashOfAFile) + ON_COMMAND(ID_EINZELVERFAHREN_SIGN, &CCrypToolApp::OnEinzelverfahrenTutorialSignaturerzeugung) + ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, &CCrypToolApp::OnVerentschlsselnHybridverfahrenHybridverschlsselung) + ON_COMMAND(ID_OPTIONS_STARTOPTIONS, &CCrypToolApp::OnOptionsStartoptions) + ON_COMMAND(ID_HILFE_INDEX, &CCrypToolApp::OnHilfeIndex) + ON_COMMAND(ID_HILFE_STARTSEITE, &CCrypToolApp::OnHilfeStartseite) + ON_COMMAND(ID_HILFE_SZENARIEN, &CCrypToolApp::OnHilfeSzenarien) + ON_COMMAND(ID_SIGNATUR_ATTACK, &CCrypToolApp::OnSignaturAttack) + ON_COMMAND(ID_EINZELVERFAHREN_DIFFIEHELLMANDEMO, &CCrypToolApp::OnEinzelverfahrenDiffiehellmandemo) + ON_COMMAND(ID_SIGATTMODIFICDEMO, &CCrypToolApp::OnSigattmodificdemo) + ON_COMMAND(ID_LOAD_README, &CCrypToolApp::OnLoadReadme) + ON_COMMAND(ID_SCRIPT, &CCrypToolApp::OnScript) + ON_COMMAND(ID_HELP_PRESENTATION, &CCrypToolApp::OnPresentation) + ON_COMMAND(ID_EINZELVERFAHREN_SIDECHANNELATTACK_ON_HYBRIDENCRYPTION, &CCrypToolApp::OnEinzelverfahrenSidechannelattackOnHybridencryption) + ON_COMMAND(ID_PASSWORDQUALITYMETER, &CCrypToolApp::OnPasswordQualityMeter) + ON_COMMAND(ID_PASSWORDENTROPY, &CCrypToolApp::OnPasswordEntropy) + ON_COMMAND(ID_LENGTHOFANUMBER, &CCrypToolApp::OnLengthOfANumber) + ON_COMMAND(ID_CHALLENGE_RESPONSE, &CCrypToolApp::OnChallengeResponse) + ON_COMMAND(ID_RSA_FACTORHINT, &CCrypToolApp::OnRsaFactorhint) + ON_COMMAND(ID_RSA_STEREOTYPED, &CCrypToolApp::OnRsaStereotyped) + ON_COMMAND(ID_RSA_BLOEMERMAY, &CCrypToolApp::OnRsaBloemermay) + ON_COMMAND(ID_HELP_ANIMAL_CAESAR, &CCrypToolApp::OnAnimalCaesar) + ON_COMMAND(ID_HELP_ANIMAL_VIGENERE, &CCrypToolApp::OnAnimalVigenere) + ON_COMMAND(ID_HELP_ANIMAL_NIHILIST, &CCrypToolApp::OnAnimalNihilist) + ON_COMMAND(ID_HELP_ANIMAL_DES, &CCrypToolApp::OnAnimalDes) + ON_COMMAND(ID_INDIV_CRT_PLANET, &CCrypToolApp::OnIndivCrtPlanet) + ON_COMMAND(ID_INDIV_CRT_DEMO, &CCrypToolApp::OnIndivCrtDemo) + ON_COMMAND(ID_INDIV_CRT_SECRETSHARING, &CCrypToolApp::OnIndivCrtSecretsharing) + ON_COMMAND(ID_NUMBERSHARK, &CCrypToolApp::OnNumberShark) + ON_UPDATE_COMMAND_UI(ID_NUMBERSHARK, &CCrypToolApp::OnUpdateNumberShark) + ON_UPDATE_COMMAND_UI(ID_SHOW_ALL_EC_KEYS, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_CRYPT_KeyGen, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDENTSCHLSSELUNG, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_HASH_OFAFILE, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_SIGN, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_SCHLUESSELGENERIEREN, &CCrypToolApp::OnUpdateNeedSecudeTicket) + ON_COMMAND(ID_INDIVIDUAL_PROCEDURES_SECRETSHARING, &CCrypToolApp::OnIndividualProceduresSecretsharing) + ON_COMMAND(ID_GENERATION_TADIC_NAF_KEYS, &CCrypToolApp::OnGenerationTAdicNAFKeys) //}}AFX_MSG_MAP //ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, OnVerentschlsselnHybridverfahrenHybridverschlsselung) - ON_COMMAND(ID_FILE_NEW, OnFileNew) // file commands... - ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) - ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) + ON_COMMAND(ID_FILE_NEW, &CCrypToolApp::OnFileNew) // file commands... + ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen) + ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup) // BEGINN Fuer Hilfe-Funktionalitaet eingefuegt // Globale Hilfebefehle - ON_COMMAND(ID_HELP_FINDER, CWinApp::OnHelpFinder) - ON_COMMAND(ID_HELP, CWinApp::OnHelp) - ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp) - ON_COMMAND(ID_DEFAULT_HELP, CWinApp::OnHelpFinder) + ON_COMMAND(ID_HELP_FINDER, &CWinApp::OnHelpFinder) + ON_COMMAND(ID_HELP, &CWinApp::OnHelp) + ON_COMMAND(ID_CONTEXT_HELP, &CWinApp::OnContextHelp) + ON_COMMAND(ID_DEFAULT_HELP, &CWinApp::OnHelpFinder) // ENDE - ON_COMMAND(ID_PRIMENUMBER_TEST, OnPrimenumberTest) - ON_COMMAND(ID_AES_SELFEXTRACT, OnAesSelfextract) - ON_COMMAND(ID_INDIV_POINTADDITIONONELLIPTICCURVES, OnIndivPointadditiononellipticcurves) - ON_COMMAND(ID_COMPUTE_MERSENNE_NUMBERS, OnComputeMersenneNumbers) - ON_COMMAND(ID_FLASH_AESDEMO, OnFlashAesdemo) - ON_COMMAND(ID_FLASH_RIJNDAEL_INSPECTOR, OnFlashRijndaelInspector) - ON_COMMAND(ID_FLASH_ENIGMADEMO, OnFlashEnigmademo) - ON_COMMAND(ID_INTERACTIVE_NUMBER_THEORY, OnInteractiveNumberTheory) + ON_COMMAND(ID_PRIMENUMBER_TEST, &CCrypToolApp::OnPrimenumberTest) + ON_COMMAND(ID_AES_SELFEXTRACT, &CCrypToolApp::OnAesSelfextract) + ON_COMMAND(ID_INDIV_POINTADDITIONONELLIPTICCURVES, &CCrypToolApp::OnIndivPointadditiononellipticcurves) + ON_COMMAND(ID_COMPUTE_MERSENNE_NUMBERS, &CCrypToolApp::OnComputeMersenneNumbers) + ON_COMMAND(ID_FLASH_AESDEMO, &CCrypToolApp::OnFlashAesdemo) + ON_COMMAND(ID_FLASH_RIJNDAEL_INSPECTOR, &CCrypToolApp::OnFlashRijndaelInspector) + ON_COMMAND(ID_FLASH_ENIGMADEMO, &CCrypToolApp::OnFlashEnigmademo) + ON_COMMAND(ID_INTERACTIVE_NUMBER_THEORY, &CCrypToolApp::OnInteractiveNumberTheory) ON_COMMAND(ID_PROTOKOL_SMIME, &CCrypToolApp::OnProtokolSMIME) ON_COMMAND(ID_AES_RIJNDAEL_FLOWVISUALISATION, &CCrypToolApp::OnAesRijndaelFlowvisualisation) ON_COMMAND(ID_KNOWN_ANALYSIS_SINGLE_PERMUTATION, &CCrypToolApp::OnKnownAnalysisSinglePermutation) @@ -410,7 +410,7 @@ BOOL CCrypToolApp::InitInstance() char buffer[1024], *p; int n; - #if !defined(_MSC_VER) || _MSC_VER <= 1200 + #if defined(_MSC_VER) && _MSC_VER <= 1200 // HTML Help for VC++ 6.0 // ... #else @@ -701,8 +701,8 @@ BOOL CCrypToolApp::InitInstance() } // Secude ptr fuer EC-Lib setzen -#define DoOneFn(a,b,c,d) ECSecudeLib.##c = SecudeLib.##c; -#define DoOneData(a,b) ECSecudeLib.##b = SecudeLib.##b; +#define DoOneFn(a,b,c,d) ECSecudeLib.c = SecudeLib.c; +#define DoOneData(a,b) ECSecudeLib.b = SecudeLib.b; DoECAll #undef DoOneFn #undef DoOneData @@ -843,7 +843,7 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_TIMER() - ON_COMMAND(ID_OPTIONS_PLOT, OnOptionsPlot) + ON_COMMAND(ID_OPTIONS_PLOT, &CMainFrame::OnOptionsPlot) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -1143,7 +1143,7 @@ void CCrypToolApp::OnEinzelverfahrenTutorialSignaturerzeugung() } -#if !defined(_MSC_VER) || _MSC_VER <= 1200 +#if defined(_MSC_VER) && _MSC_VER <= 1200 // HTML Help for VC++ 6.0 void CCrypToolApp::WinHelp( DWORD dwData, UINT nCmd) #else @@ -1159,8 +1159,8 @@ void CCrypToolApp::WinHelpInternal( DWORD_PTR dwData, UINT nCmd) for (it = m_menuItemStack.begin(); it != m_menuItemStack.end(); it++) { WCHAR mi[sizeof alinkid] = L""; TCHAR mo[sizeof alinkid]; - GetMenuStringW((*it).hmenu,(*it).index,mi,sizeof(mi)-1,MF_BYPOSITION); - mi[sizeof mi - 1] = '\0'; + GetMenuStringW((*it).hmenu,(*it).index,mi,sizeof(mi)/sizeof(mi[0])-1,MF_BYPOSITION); + mi[sizeof(mi)/sizeof(mi[0]) - 1] = '\0'; int i = 0, j = 0; WCHAR c; // remove from mi @@ -1200,7 +1200,7 @@ void CCrypToolApp::WinHelpInternal( DWORD_PTR dwData, UINT nCmd) link.pszWindow = NULL; link.fIndexOnFail = FALSE ; - callHtmlHelp(HH_ALINK_LOOKUP, (DWORD) &link); + callHtmlHelp(HH_ALINK_LOOKUP, (DWORD_PTR) &link); } else @@ -1319,7 +1319,7 @@ void CCrypToolApp::OnScript() //HINSTANCE hInst = ShellExecute(0, "open", readmePath, NULL, 0, SW_SHOW ); // does not work for BE - .NET 3.0 issue? HINSTANCE hInst = ShellExecute(0, NULL, readmePath, NULL, 0, SW_SHOW ); - if ( reinterpret_cast(hInst) <= 32 ) + if ( reinterpret_cast(hInst) <= 32 ) Message(IDS_ERROPEN_SCRIPT, MB_ICONSTOP); } @@ -1332,7 +1332,7 @@ void CCrypToolApp::OnPresentation() sprintf(presentationPath, pc_str, Pfad); HINSTANCE hInst = ShellExecute(0, NULL, presentationPath, NULL, 0, SW_SHOW); delete []presentationPath; - if(reinterpret_cast(hInst) <= 32) + if(reinterpret_cast(hInst) <= 32) Message(IDS_ERROR_OPENING_PRESENTATION, MB_ICONSTOP); } @@ -1416,7 +1416,7 @@ void CCrypToolApp::execAnimalVisualization(int _animalFileIdentifier) { animalPath = CString(Pfad) + animalPath; animalPath.Replace("/","\\"); HINSTANCE hInst = ShellExecute(NULL, NULL, animalExecutable, animalFile, animalPath, SW_HIDE); - if(reinterpret_cast(hInst) <= 32) { + if(reinterpret_cast(hInst) <= 32) { Message(IDS_ERROPEN_ANIM, MB_ICONSTOP); } } @@ -1467,9 +1467,9 @@ void CCrypToolApp::OnGenerationTAdicNAFKeys() { generationTAdicNAFKeysPath.Replace("/", "\\"); // try to open the executable, otherwise dump an error HINSTANCE hInst=ShellExecute(NULL, NULL, generationTAdicNAFKeysExecutable, NULL, generationTAdicNAFKeysPath, SW_HIDE); - if(reinterpret_cast(hInst) <= 32) { + if(reinterpret_cast(hInst) <= 32) { CString message; - message.Format(IDS_GENERATION_TADIC_NAF_KEYS_ERROR_EXECUTION, generationTAdicNAFKeysExecutable, generationTAdicNAFKeysPath); + message.Format(IDS_GENERATION_TADIC_NAF_KEYS_ERROR_EXECUTION, (LPCTSTR)generationTAdicNAFKeysExecutable, (LPCTSTR)generationTAdicNAFKeysPath); AfxMessageBox(message, MB_ICONSTOP); } } @@ -1478,7 +1478,7 @@ void CCrypToolApp::OnNumberShark() { // zahlenhai aufrufen CString str_m_NumberShark_Selfextract_EXE_Quoted = CString("\"") + CString(theApp.m_NumberShark_Selfextract_EXE) + CString("\""); - _spawnl(_P_NOWAIT, theApp.m_NumberShark_Selfextract_EXE, str_m_NumberShark_Selfextract_EXE_Quoted, NULL); + _spawnl(_P_NOWAIT, theApp.m_NumberShark_Selfextract_EXE, (LPCTSTR)str_m_NumberShark_Selfextract_EXE_Quoted, NULL); // FIXME: Interpret return value of _spawnl } @@ -1501,9 +1501,9 @@ BOOL CCrypToolApp::OnDDECommand(LPTSTR lpszCommand) } -void CCrypToolApp::callHtmlHelp(UINT uCommand, DWORD dwData) +void CCrypToolApp::callHtmlHelp(UINT uCommand, DWORD_PTR dwData) { -#if !defined(_MSC_VER) || _MSC_VER <= 1200 // HTML Help for VC++ 6.0 +#if defined(_MSC_VER) && _MSC_VER <= 1200 // HTML Help for VC++ 6.0 // creating the path to the help CString html_help_path = CString(m_pszHelpFilePath) + CString(">MainWindow"); @@ -1562,7 +1562,7 @@ void CCrypToolApp::OnAesSelfextract() { CString str_m_Selfextract_EXE_Quoted = CString("\"") + CString(theApp.m_Selfextract_EXE) + CString("\""); // int intptr_t = _spawnl(_P_NOWAIT, strmod, strmod, NULL, NULL); - int intptr_t = _spawnl(_P_NOWAIT, theApp.m_Selfextract_EXE, str_m_Selfextract_EXE_Quoted, NULL, NULL); + int intptr_t = _spawnl(_P_NOWAIT, theApp.m_Selfextract_EXE, (LPCTSTR)str_m_Selfextract_EXE_Quoted, NULL, NULL); // FIXME: Interpret return value of _spawnl } @@ -1591,7 +1591,7 @@ void CCrypToolApp::OnFlashAesdemo() HINSTANCE hInst = ShellExecute(NULL,NULL, AESDemoExecStr, " ", Pfad, SW_SHOW); - if ( reinterpret_cast(hInst) <= 32 ) { + if ( reinterpret_cast(hInst) <= 32 ) { // display error message stating where the desired executable is expected CString message; message.Format(IDS_ERROR_OPEN_FLASHAESDEMO, Pfad); @@ -1606,7 +1606,7 @@ void CCrypToolApp::OnFlashRijndaelInspector() HINSTANCE hInst = ShellExecute(NULL,NULL, RijndaelInspectorExecStr, " ", Pfad, SW_SHOW); - if ( reinterpret_cast(hInst) <= 32 ) { + if ( reinterpret_cast(hInst) <= 32 ) { // display error message stating where the desired executable is expected CString message; message.Format(IDS_ERROR_OPEN_RIJNDAELINSPECTOR, Pfad); @@ -1621,7 +1621,7 @@ void CCrypToolApp::OnInteractiveNumberTheory() HINSTANCE hInst = ShellExecute(NULL,NULL, InteractiveNTExecStr, " ", Pfad, SW_SHOW); - if ( reinterpret_cast(hInst) <= 32 ) { + if ( reinterpret_cast(hInst) <= 32 ) { // display error message stating where the desired executable is expected CString message; message.Format(IDS_ERROPEN_INTERACTIVE_NUMBER_THEORY, Pfad); @@ -1636,7 +1636,7 @@ void CCrypToolApp::OnFlashEnigmademo() HINSTANCE hInst = ShellExecute(NULL,NULL, EnigmaFlashExecStr, " ", Pfad, SW_SHOW); - if ( reinterpret_cast(hInst) <= 32 ) { + if ( reinterpret_cast(hInst) <= 32 ) { // display error message stating where the desired executable is expected CString message; message.Format(IDS_ERROPEN_ENIGMA_FLASH, Pfad); diff --git a/CrypTool/CrypToolApp.h b/CrypTool/CrypToolApp.h index 0a0c096c4..7560e620d 100644 --- a/CrypTool/CrypToolApp.h +++ b/CrypTool/CrypToolApp.h @@ -195,9 +195,9 @@ class CCrypToolApp : public CWinApp virtual void AddToRecentFileList(LPCTSTR lpszPathName); // WinHelp set public to get access from Challenge Response Demo - #if !defined(_MSC_VER) || _MSC_VER <= 1200 + #if defined(_MSC_VER) && _MSC_VER <= 1200 // HTML Help for VC++ 6.0 - virtual void CCrypToolApp::WinHelp( DWORD dwData, UINT nCmd = HELP_CONTEXT); + virtual void WinHelp( DWORD dwData, UINT nCmd = HELP_CONTEXT); #else // HTML Help for VC++ .NET virtual void WinHelpInternal( DWORD_PTR dwData, UINT nCmd = HELP_CONTEXT ); // overridden to handle F1 on menus with sub menus #endif @@ -212,7 +212,7 @@ class CCrypToolApp : public CWinApp void endLog(); private: - void callHtmlHelp(UINT uCommand, DWORD dwData); + void callHtmlHelp(UINT uCommand, DWORD_PTR dwData); virtual int ExitInstance(); void execAnimalVisualization(int _animalFileIdentifier); public: diff --git a/CrypTool/CrypToolTools.cpp b/CrypTool/CrypToolTools.cpp index 80b55cfe9..5fb22f419 100644 --- a/CrypTool/CrypToolTools.cpp +++ b/CrypTool/CrypToolTools.cpp @@ -534,7 +534,7 @@ void ShellExecuteJava(const CString &_javaProgram, const CString &_javaProgramCo struct stat javaProgramFileInformation; if(stat(javaProgram.GetBuffer(), &javaProgramFileInformation) != 0) { CString message; - message.Format(IDS_STRING_JAVA_PROGRAM_NOT_FOUND, javaProgram); + message.Format(IDS_STRING_JAVA_PROGRAM_NOT_FOUND, (LPCTSTR)javaProgram); AfxMessageBox(message, MB_ICONINFORMATION); return; } @@ -542,7 +542,7 @@ void ShellExecuteJava(const CString &_javaProgram, const CString &_javaProgramCo memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); CString command; - command.Format("java %s", javaProgramCompleteCall); + command.Format("java %s", (LPCTSTR)javaProgramCompleteCall); if(!CreateProcess(NULL, (LPSTR)(LPCTSTR)(command), NULL, NULL, false, CREATE_NO_WINDOW, NULL, (LPCTSTR)(path), &si, &pi)) { CString message; message.LoadStringA(IDS_STRING_JAVA_PROGRAM_EXECUTION_FAILED); @@ -800,7 +800,7 @@ bool copyKeyToClipboard(const int keyTypeIdentifier, const CString &key) { CString stringKeyTypeIdentifier; stringKeyTypeIdentifier.LoadString(keyTypeIdentifier); CString text; - text.Format("%s:%s", stringKeyTypeIdentifier, key); + text.Format("%s:%s", (LPCTSTR)stringKeyTypeIdentifier, (LPCTSTR)key); return copyTextToClipboard(text); } diff --git a/CrypTool/CrypToolView.cpp b/CrypTool/CrypToolView.cpp index c6205ae28..ce1e59920 100644 --- a/CrypTool/CrypToolView.cpp +++ b/CrypTool/CrypToolView.cpp @@ -56,13 +56,13 @@ BEGIN_MESSAGE_MAP(CCrypToolView, CView) ON_WM_CONTEXTMENU() ON_WM_SETFOCUS() #if 0 - ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) - ON_COMMAND(ID_VIEW_ENDOFLINE, OnViewEndOfLine) - ON_UPDATE_COMMAND_UI(ID_VIEW_ENDOFLINE, OnUpdateViewEndOfLine) - ON_COMMAND(ID_VIEW_LINEWRAP, OnViewLineWrap) - ON_UPDATE_COMMAND_UI(ID_VIEW_LINEWRAP, OnUpdateViewLineWrap) - ON_COMMAND(ID_VIEW_WHITESPACE, OnViewWhitespace) - ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACE, OnUpdateViewWhitespace) + ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) + ON_COMMAND(ID_VIEW_ENDOFLINE, &CCrypToolView::OnViewEndOfLine) + ON_UPDATE_COMMAND_UI(ID_VIEW_ENDOFLINE, &CCrypToolView::OnUpdateViewEndOfLine) + ON_COMMAND(ID_VIEW_LINEWRAP, &CCrypToolView::OnViewLineWrap) + ON_UPDATE_COMMAND_UI(ID_VIEW_LINEWRAP, &CCrypToolView::OnUpdateViewLineWrap) + ON_COMMAND(ID_VIEW_WHITESPACE, &CCrypToolView::OnViewWhitespace) + ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACE, &CCrypToolView::OnUpdateViewWhitespace) #endif //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/CrypToolVolRen.cpp b/CrypTool/CrypToolVolRen.cpp index b9cff0931..e976561f4 100644 --- a/CrypTool/CrypToolVolRen.cpp +++ b/CrypTool/CrypToolVolRen.cpp @@ -20,7 +20,7 @@ #include "stdafx.h" #include "CrypToolVolRen.h" -#include +#include #include #include diff --git a/CrypTool/CryptDoc.cpp b/CrypTool/CryptDoc.cpp index 58c4f513b..bbfb9d2de 100644 --- a/CrypTool/CryptDoc.cpp +++ b/CrypTool/CryptDoc.cpp @@ -48,7 +48,7 @@ #include "DlgStatRandTests.h" #include "DlgHybridEncryptionDemo.h" #include "DlgHybridDecryptionDemo.h" -#include +#include #include "DialogeMessage.h" #include "ASN1Decoder.h" #include "DlgDiffieHellmanVisualization.h" @@ -64,11 +64,11 @@ #include "DlgShowKey.h" #include "DlgSolitaireAnalyse.h" #include "ECIESMain.h" -#include "bruteforceheap.h" +#include "BruteForceHeap.h" #include "DlgFormatTextDocument.h" #include "DlgSimpleTranspositions.h" #include "DlgAutomatedPermAnalysis.h" -#include "keyHillBase.h" +#include "KeyHillBase.h" extern char *CaPseDatei, *CaPseVerzeichnis, *Pfad, *PseVerzeichnis; @@ -140,145 +140,145 @@ void CCryptDoc::SymCryptBruteForce( int AlgID, cryptProvider provider, int keyle BEGIN_MESSAGE_MAP(CCryptDoc, CAppDocument) //{{AFX_MSG_MAP(CCryptDoc) - ON_COMMAND(ID_ADD_BIN, OnAddBin) - ON_COMMAND(ID_PLAYFAIR_BIN, OnPlayfairBin) - ON_COMMAND(ID_PLAYFAIR_ANALYSE, OnPlayfairAnalyse) - ON_COMMAND(ID_CAESAR_ASC, OnCaesarAsc) - ON_COMMAND(ID_VIGENERE_ASC, OnVigenereAsc) - ON_COMMAND(ID_XOR_BIN, OnXorBin) - ON_COMMAND(ID_AUTO, OnAuto) - ON_COMMAND(ID_ENTROPY, OnEntropy) - ON_COMMAND(ID_HISTOGRAM, OnHistogram) - ON_COMMAND(ID_CRYPT_IDEA, OnCryptIdea) - ON_COMMAND(ID_CRYPT_RC2, OnCryptRc2) - ON_COMMAND(ID_CRYPT_DES_DESECB, OnCryptDesDesecb) - ON_COMMAND(ID_CRYPT_HASH_MD5, OnCryptHashMd5) - ON_COMMAND(ID_CRYPT_HASH_MD2, OnCryptHashMd2) - ON_COMMAND(ID_CRYPT_HASH_MD4, OnCryptHashMd4) - ON_COMMAND(ID_CRYPT_HASH_RIPEMD160, OnCryptHashRipemd160) - ON_COMMAND(ID_CRYPT_HASH_SHA, OnCryptHashSha) - ON_COMMAND(ID_CRYPT_HASH_SHA1, OnCryptHashSha1) - ON_COMMAND(ID_CRYPT_HASH_SHA256, OnCryptHashSha256) - ON_COMMAND(ID_CRYPT_HASH_SHA512, OnCryptHashSha512) - ON_COMMAND(ID_VERNAM_BIN, OnVernamBin) - ON_COMMAND(ID_CRYPT_3DES_CBC, OnCrypt3desCbc) - ON_COMMAND(ID_CRYPT_3DES_ECB, OnCrypt3desEcb) - ON_COMMAND(ID_CRYPT_RC4, OnCryptRc4) - ON_COMMAND(ID_CRYPT_DES_DESCBC, OnCryptDesDescbc) - ON_COMMAND(ID_CAESAR_AUTO, OnCaesarAuto) - ON_COMMAND(ID_VIGENERE_AUTO, OnVigenereAuto) - ON_COMMAND(ID_ANALYSIS_VIGENERE_SCHROEDEL, OnVigenereAnalysisSchroedel) - ON_COMMAND(ID_HILL_AUTO, OnHillPlain) - ON_COMMAND(ID_ADD_AUTO, OnAddAuto) - ON_COMMAND(ID_XOR_AUTO, OnXorAuto) - ON_COMMAND(ID_HILL, OnHill) - ON_COMMAND(ID_ZIP, OnZip) - ON_COMMAND(ID_UNZIP, OnUnzip) - ON_COMMAND(ID_CRYPT_RsaDec, OnCRYPTRsaDec) - ON_COMMAND(ID_CRYPT_RsaEnc, OnCRYPTRsaEnc) - ON_COMMAND(ID_CryptMono, OnCryptMono) - ON_COMMAND(ID_CRYPT_SIGN, OnCryptSign) - ON_COMMAND(ID_CRYPT_VERIFY, OnCryptVerify) - ON_COMMAND(ID_CRYPT_EXTRACT, OnCryptExtract) - ON_COMMAND(ID_ANALYZE_SUBST, OnAnalyzeSubst) - ON_COMMAND(ID_FLOATING, OnFloating) - ON_UPDATE_COMMAND_UI(ID_CRYPT_3DES_CBC, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_EXTRACT, OnUpdateNeedSecudeTicket) - ON_COMMAND(ID_ANALYSE_DESCBC, OnAnalyseDescbc) - ON_COMMAND(ID_ANALYSE_DESECB, OnAnalyseDesecb) - ON_COMMAND(ID_ANALYSE_IDEA, OnAnalyseIdea) - ON_COMMAND(ID_ANALYSE_RC2, OnAnalyseRc2) - ON_COMMAND(ID_ANALYSE_RC4, OnAnalyseRc4) - ON_COMMAND(ID_ANALYSE_TRIPLEDESCBC, OnAnalyseTripledescbc) - ON_COMMAND(ID_ANALYSE_TRIPLEDESECB, OnAnalyseTripledesecb) - ON_COMMAND(ID_CRYPT_AES_MARS, OnCryptAesMars) - ON_COMMAND(ID_CRYPT_AES_RC6, OnCryptAesRc6) - ON_COMMAND(ID_CRYPT_AES_RIJNDAEL, OnCryptAesRijndael) - ON_COMMAND(ID_CRYPT_AES_SERPENT, OnCryptAesSerpent) - ON_COMMAND(ID_CRYPT_AES_TWOFISH, OnCryptAesTwofish) - ON_COMMAND(ID_ANALYSE_AES_MARS, OnAnalyseAesMars) - ON_COMMAND(ID_ANALYSE_AES_RC6, OnAnalyseAesRc6) - ON_COMMAND(ID_ANALYSE_AES_RIJNDAEL, OnAnalyseAesRijndael) - ON_COMMAND(ID_ANALYSE_AES_SERPENT, OnAnalyseAesSerpent) - ON_COMMAND(ID_ANALYSE_AES_TWOFISH, OnAnalyseAesTwofish) - ON_COMMAND(ID_ANALYSE_VITANY, OnVitanyAnalyse) - ON_COMMAND(ID_ANALYSE_PERIOD, OnPeriod) - ON_COMMAND(ID_HOMOPHONE_ASC, OnHomophone) - ON_COMMAND(ID_ANALYSE_NGRAM, OnAnalyseNGram) - ON_COMMAND(ID_ANALYSE_NGRAM_BIN, OnAnalyseNGramBin) - ON_COMMAND(ID_PERMUTATION, OnPermutation) - ON_COMMAND(ID_AES_SELFEXTRACT, OnAesSelfextract) - ON_UPDATE_COMMAND_UI(ID_AES_SELFEXTRACT, OnUpdateAesSelfextract) - ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_FREQUENCYTEST, OnAnalyseZufallstestsFrequencytest) - ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_SERIALTEST, OnAnalyseZufallstestsSerialtest) - ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_RUNS, OnAnalyseZufallstestsRuns) - ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_POKERTEST, OnAnalyseZufallstestsPokertest) - ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_FIPSPUB1401, OnAnalyseZufallstestsFipspub1401) - ON_COMMAND(ID_EINZELVERFAHREN_HASHWERTE_HASHDEMO, OnEinzelverfahrenHashwerteHashdemo) - ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, OnEinzelverfahrenHybridverfahrenHybridverschlsselung) - ON_COMMAND(ID_EINZELVERFAHREN_SIGN_DOC, OnEinzelverfahrenSignDoc) - ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDENTSCHLSSELUNG, OnEinzelverfahrenHybridverfahrenHybridentschlsselung) - ON_COMMAND(ID_EINZELVERFAHREN_ASN1DECODIEREN, OnEinzelverfahrenAsn1decodieren) - ON_COMMAND(ID_SIGATTMODIFICDEMO, OnSigattmodificdemo) - ON_COMMAND(ID_SIGNATUR_ATTACK, OnSignaturAttack) - ON_COMMAND(ID_EINZELVERFAHREN_SIDECHANNELATTACK_ON_HYBRIDENCRYPTION, OnEinzelverfahrenSidechannelattackOnHybridencryption) - ON_COMMAND(ID_FILEPROPERTIES, OnFileProperties) - ON_COMMAND(ID_GENERATE_MACS, OnMessageauthenticationcode) - ON_COMMAND(ID_ENCRYPT_ADFGVX, OnEncryptAdfgvx) - ON_COMMAND(ID_ANALYSE_SYMCLASSIC_ADFGVX, OnAnalyseSymmclassicAdfgvx) - ON_COMMAND(ID_CIPHERTEXT_ONLY_SUBSTITUTION, OnCiphertextOnlySubstitution) - ON_COMMAND(ID_SHOW_KEY, OnShowKey) - ON_COMMAND(ID_GOTO_VATER, OnGotoVater) - ON_COMMAND(ID_ANALYSIS_RANDOM_3D_VISUALIZATION, OnAnalysisRandom3dVisualization) - ON_COMMAND(ID_SYMCLASSIC_SOLITAIRE, OnSymclassicSolitaire) - ON_COMMAND(ID_ENCRYPTION_SIMPLE_TRANSPOSITIONS, OnEncryptionSimpleTranspositions) - ON_UPDATE_COMMAND_UI(ID_CRYPT_3DES_ECB, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_DES_DESCBC, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_DES_DESECB, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_MD2, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_MD4, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_MD5, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_RIPEMD160, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_SHA, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_SHA1, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_IDEA, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_RC4, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_RC2, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_CRYPT_RsaDec, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_CRYPT_RsaEnc, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_CRYPT_SIGN, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_CRYPT_VERIFY, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_DESCBC, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_DESECB, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_IDEA, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_RC2, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_RC4, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_TRIPLEDESCBC, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_ANALYSE_TRIPLEDESECB, OnUpdateNeedSecudeTicket) - ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDENTSCHLSSELUNG, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_SIGN_DOC, OnUpdateNeedSecude) - ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_HASHWERTE_HASHDEMO, OnUpdateNeedSecude) - ON_COMMAND(ID_CIPHERTEXT_ONLY_SUBSTITUTION, OnCiphertextOnlySubstitution) - ON_COMMAND(ID_ROT13CAESAR_ASC, OnRot13caesarAsc) - ON_COMMAND(ID_ANALYSE_SYMCLASSIC_CIPHERTEXTONLY_SOLITAIRE, OnAnalyseSymmclassicCiphertextolySolitaire) - ON_COMMAND(ID_ENCODE_BASE64, OnIndivproceduresBase64Encode) - ON_COMMAND(ID_DECODE_BASE64, OnIndivproceduresBase64Decode) - ON_COMMAND(ID_ENCODE_UU, OnEncodeUu) - ON_COMMAND(ID_DECODE_UU, OnDecodeUu) - ON_COMMAND(ID_CRYPT_DESL, OnCryptDESL) - ON_COMMAND(ID_CRYPT_DESX, OnCryptDESX) - ON_COMMAND(ID_CRYPT_DESXL, OnCryptDESXL) - ON_COMMAND(ID_ANALYSE_DESL, OnAnalyseDESL) - ON_COMMAND(ID_ANALYSE_DESX, OnAnalyseDESX) - ON_COMMAND(ID_ANALYSE_DESXL, OnAnalyseDESXL) - ON_COMMAND(ID_FORMAT_TEXT_DOCUMENT, OnFormatTextDocument) + ON_COMMAND(ID_ADD_BIN, &CCryptDoc::OnAddBin) + ON_COMMAND(ID_PLAYFAIR_BIN, &CCryptDoc::OnPlayfairBin) + ON_COMMAND(ID_PLAYFAIR_ANALYSE, &CCryptDoc::OnPlayfairAnalyse) + ON_COMMAND(ID_CAESAR_ASC, &CCryptDoc::OnCaesarAsc) + ON_COMMAND(ID_VIGENERE_ASC, &CCryptDoc::OnVigenereAsc) + ON_COMMAND(ID_XOR_BIN, &CCryptDoc::OnXorBin) + ON_COMMAND(ID_AUTO, &CCryptDoc::OnAuto) + ON_COMMAND(ID_ENTROPY, &CCryptDoc::OnEntropy) + ON_COMMAND(ID_HISTOGRAM, &CCryptDoc::OnHistogram) + ON_COMMAND(ID_CRYPT_IDEA, &CCryptDoc::OnCryptIdea) + ON_COMMAND(ID_CRYPT_RC2, &CCryptDoc::OnCryptRc2) + ON_COMMAND(ID_CRYPT_DES_DESECB, &CCryptDoc::OnCryptDesDesecb) + ON_COMMAND(ID_CRYPT_HASH_MD5, &CCryptDoc::OnCryptHashMd5) + ON_COMMAND(ID_CRYPT_HASH_MD2, &CCryptDoc::OnCryptHashMd2) + ON_COMMAND(ID_CRYPT_HASH_MD4, &CCryptDoc::OnCryptHashMd4) + ON_COMMAND(ID_CRYPT_HASH_RIPEMD160, &CCryptDoc::OnCryptHashRipemd160) + ON_COMMAND(ID_CRYPT_HASH_SHA, &CCryptDoc::OnCryptHashSha) + ON_COMMAND(ID_CRYPT_HASH_SHA1, &CCryptDoc::OnCryptHashSha1) + ON_COMMAND(ID_CRYPT_HASH_SHA256, &CCryptDoc::OnCryptHashSha256) + ON_COMMAND(ID_CRYPT_HASH_SHA512, &CCryptDoc::OnCryptHashSha512) + ON_COMMAND(ID_VERNAM_BIN, &CCryptDoc::OnVernamBin) + ON_COMMAND(ID_CRYPT_3DES_CBC, &CCryptDoc::OnCrypt3desCbc) + ON_COMMAND(ID_CRYPT_3DES_ECB, &CCryptDoc::OnCrypt3desEcb) + ON_COMMAND(ID_CRYPT_RC4, &CCryptDoc::OnCryptRc4) + ON_COMMAND(ID_CRYPT_DES_DESCBC, &CCryptDoc::OnCryptDesDescbc) + ON_COMMAND(ID_CAESAR_AUTO, &CCryptDoc::OnCaesarAuto) + ON_COMMAND(ID_VIGENERE_AUTO, &CCryptDoc::OnVigenereAuto) + ON_COMMAND(ID_ANALYSIS_VIGENERE_SCHROEDEL, &CCryptDoc::OnVigenereAnalysisSchroedel) + ON_COMMAND(ID_HILL_AUTO, &CCryptDoc::OnHillPlain) + ON_COMMAND(ID_ADD_AUTO, &CCryptDoc::OnAddAuto) + ON_COMMAND(ID_XOR_AUTO, &CCryptDoc::OnXorAuto) + ON_COMMAND(ID_HILL, &CCryptDoc::OnHill) + ON_COMMAND(ID_ZIP, &CCryptDoc::OnZip) + ON_COMMAND(ID_UNZIP, &CCryptDoc::OnUnzip) + ON_COMMAND(ID_CRYPT_RsaDec, &CCryptDoc::OnCRYPTRsaDec) + ON_COMMAND(ID_CRYPT_RsaEnc, &CCryptDoc::OnCRYPTRsaEnc) + ON_COMMAND(ID_CryptMono, &CCryptDoc::OnCryptMono) + ON_COMMAND(ID_CRYPT_SIGN, &CCryptDoc::OnCryptSign) + ON_COMMAND(ID_CRYPT_VERIFY, &CCryptDoc::OnCryptVerify) + ON_COMMAND(ID_CRYPT_EXTRACT, &CCryptDoc::OnCryptExtract) + ON_COMMAND(ID_ANALYZE_SUBST, &CCryptDoc::OnAnalyzeSubst) + ON_COMMAND(ID_FLOATING, &CCryptDoc::OnFloating) + ON_UPDATE_COMMAND_UI(ID_CRYPT_3DES_CBC, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_EXTRACT, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_COMMAND(ID_ANALYSE_DESCBC, &CCryptDoc::OnAnalyseDescbc) + ON_COMMAND(ID_ANALYSE_DESECB, &CCryptDoc::OnAnalyseDesecb) + ON_COMMAND(ID_ANALYSE_IDEA, &CCryptDoc::OnAnalyseIdea) + ON_COMMAND(ID_ANALYSE_RC2, &CCryptDoc::OnAnalyseRc2) + ON_COMMAND(ID_ANALYSE_RC4, &CCryptDoc::OnAnalyseRc4) + ON_COMMAND(ID_ANALYSE_TRIPLEDESCBC, &CCryptDoc::OnAnalyseTripledescbc) + ON_COMMAND(ID_ANALYSE_TRIPLEDESECB, &CCryptDoc::OnAnalyseTripledesecb) + ON_COMMAND(ID_CRYPT_AES_MARS, &CCryptDoc::OnCryptAesMars) + ON_COMMAND(ID_CRYPT_AES_RC6, &CCryptDoc::OnCryptAesRc6) + ON_COMMAND(ID_CRYPT_AES_RIJNDAEL, &CCryptDoc::OnCryptAesRijndael) + ON_COMMAND(ID_CRYPT_AES_SERPENT, &CCryptDoc::OnCryptAesSerpent) + ON_COMMAND(ID_CRYPT_AES_TWOFISH, &CCryptDoc::OnCryptAesTwofish) + ON_COMMAND(ID_ANALYSE_AES_MARS, &CCryptDoc::OnAnalyseAesMars) + ON_COMMAND(ID_ANALYSE_AES_RC6, &CCryptDoc::OnAnalyseAesRc6) + ON_COMMAND(ID_ANALYSE_AES_RIJNDAEL, &CCryptDoc::OnAnalyseAesRijndael) + ON_COMMAND(ID_ANALYSE_AES_SERPENT, &CCryptDoc::OnAnalyseAesSerpent) + ON_COMMAND(ID_ANALYSE_AES_TWOFISH, &CCryptDoc::OnAnalyseAesTwofish) + ON_COMMAND(ID_ANALYSE_VITANY, &CCryptDoc::OnVitanyAnalyse) + ON_COMMAND(ID_ANALYSE_PERIOD, &CCryptDoc::OnPeriod) + ON_COMMAND(ID_HOMOPHONE_ASC, &CCryptDoc::OnHomophone) + ON_COMMAND(ID_ANALYSE_NGRAM, &CCryptDoc::OnAnalyseNGram) + ON_COMMAND(ID_ANALYSE_NGRAM_BIN, &CCryptDoc::OnAnalyseNGramBin) + ON_COMMAND(ID_PERMUTATION, &CCryptDoc::OnPermutation) + ON_COMMAND(ID_AES_SELFEXTRACT, &CCryptDoc::OnAesSelfextract) + ON_UPDATE_COMMAND_UI(ID_AES_SELFEXTRACT, &CCryptDoc::OnUpdateAesSelfextract) + ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_FREQUENCYTEST, &CCryptDoc::OnAnalyseZufallstestsFrequencytest) + ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_SERIALTEST, &CCryptDoc::OnAnalyseZufallstestsSerialtest) + ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_RUNS, &CCryptDoc::OnAnalyseZufallstestsRuns) + ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_POKERTEST, &CCryptDoc::OnAnalyseZufallstestsPokertest) + ON_COMMAND(ID_ANALYSE_ZUFALLSTESTS_FIPSPUB1401, &CCryptDoc::OnAnalyseZufallstestsFipspub1401) + ON_COMMAND(ID_EINZELVERFAHREN_HASHWERTE_HASHDEMO, &CCryptDoc::OnEinzelverfahrenHashwerteHashdemo) + ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, &CCryptDoc::OnEinzelverfahrenHybridverfahrenHybridverschlsselung) + ON_COMMAND(ID_EINZELVERFAHREN_SIGN_DOC, &CCryptDoc::OnEinzelverfahrenSignDoc) + ON_COMMAND(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDENTSCHLSSELUNG, &CCryptDoc::OnEinzelverfahrenHybridverfahrenHybridentschlsselung) + ON_COMMAND(ID_EINZELVERFAHREN_ASN1DECODIEREN, &CCryptDoc::OnEinzelverfahrenAsn1decodieren) + ON_COMMAND(ID_SIGATTMODIFICDEMO, &CCryptDoc::OnSigattmodificdemo) + ON_COMMAND(ID_SIGNATUR_ATTACK, &CCryptDoc::OnSignaturAttack) + ON_COMMAND(ID_EINZELVERFAHREN_SIDECHANNELATTACK_ON_HYBRIDENCRYPTION, &CCryptDoc::OnEinzelverfahrenSidechannelattackOnHybridencryption) + ON_COMMAND(ID_FILEPROPERTIES, &CCryptDoc::OnFileProperties) + ON_COMMAND(ID_GENERATE_MACS, &CCryptDoc::OnMessageauthenticationcode) + ON_COMMAND(ID_ENCRYPT_ADFGVX, &CCryptDoc::OnEncryptAdfgvx) + ON_COMMAND(ID_ANALYSE_SYMCLASSIC_ADFGVX, &CCryptDoc::OnAnalyseSymmclassicAdfgvx) + ON_COMMAND(ID_CIPHERTEXT_ONLY_SUBSTITUTION, &CCryptDoc::OnCiphertextOnlySubstitution) + ON_COMMAND(ID_SHOW_KEY, &CCryptDoc::OnShowKey) + ON_COMMAND(ID_GOTO_VATER, &CCryptDoc::OnGotoVater) + ON_COMMAND(ID_ANALYSIS_RANDOM_3D_VISUALIZATION, &CCryptDoc::OnAnalysisRandom3dVisualization) + ON_COMMAND(ID_SYMCLASSIC_SOLITAIRE, &CCryptDoc::OnSymclassicSolitaire) + ON_COMMAND(ID_ENCRYPTION_SIMPLE_TRANSPOSITIONS, &CCryptDoc::OnEncryptionSimpleTranspositions) + ON_UPDATE_COMMAND_UI(ID_CRYPT_3DES_ECB, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_DES_DESCBC, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_DES_DESECB, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_MD2, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_MD4, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_MD5, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_RIPEMD160, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_SHA, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_HASH_SHA1, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_IDEA, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_RC4, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_RC2, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_CRYPT_RsaDec, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_CRYPT_RsaEnc, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_CRYPT_SIGN, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_CRYPT_VERIFY, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_DESCBC, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_DESECB, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_IDEA, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_RC2, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_RC4, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_TRIPLEDESCBC, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_ANALYSE_TRIPLEDESECB, &CCryptDoc::OnUpdateNeedSecudeTicket) + ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDVERSCHLSSELUNG, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_VERENTSCHLSSELN_HYBRIDVERFAHREN_HYBRIDENTSCHLSSELUNG, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_SIGN_DOC, &CCryptDoc::OnUpdateNeedSecude) + ON_UPDATE_COMMAND_UI(ID_EINZELVERFAHREN_HASHWERTE_HASHDEMO, &CCryptDoc::OnUpdateNeedSecude) + ON_COMMAND(ID_CIPHERTEXT_ONLY_SUBSTITUTION, &CCryptDoc::OnCiphertextOnlySubstitution) + ON_COMMAND(ID_ROT13CAESAR_ASC, &CCryptDoc::OnRot13caesarAsc) + ON_COMMAND(ID_ANALYSE_SYMCLASSIC_CIPHERTEXTONLY_SOLITAIRE, &CCryptDoc::OnAnalyseSymmclassicCiphertextolySolitaire) + ON_COMMAND(ID_ENCODE_BASE64, &CCryptDoc::OnIndivproceduresBase64Encode) + ON_COMMAND(ID_DECODE_BASE64, &CCryptDoc::OnIndivproceduresBase64Decode) + ON_COMMAND(ID_ENCODE_UU, &CCryptDoc::OnEncodeUu) + ON_COMMAND(ID_DECODE_UU, &CCryptDoc::OnDecodeUu) + ON_COMMAND(ID_CRYPT_DESL, &CCryptDoc::OnCryptDESL) + ON_COMMAND(ID_CRYPT_DESX, &CCryptDoc::OnCryptDESX) + ON_COMMAND(ID_CRYPT_DESXL, &CCryptDoc::OnCryptDESXL) + ON_COMMAND(ID_ANALYSE_DESL, &CCryptDoc::OnAnalyseDESL) + ON_COMMAND(ID_ANALYSE_DESX, &CCryptDoc::OnAnalyseDESX) + ON_COMMAND(ID_ANALYSE_DESXL, &CCryptDoc::OnAnalyseDESXL) + ON_COMMAND(ID_FORMAT_TEXT_DOCUMENT, &CCryptDoc::OnFormatTextDocument) //}}AFX_MSG_MAP - ON_COMMAND(ID_HYBRID_ECCENC, OnHybridEccEnc) - ON_COMMAND(ID_HYBRID_ECCDEC, OnHybridEccDec) - ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat) - ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateEditRepeat) + ON_COMMAND(ID_HYBRID_ECCENC, &CCryptDoc::OnHybridEccEnc) + ON_COMMAND(ID_HYBRID_ECCDEC, &CCryptDoc::OnHybridEccDec) + ON_COMMAND(ID_EDIT_REPEAT, &CCryptDoc::OnEditRepeat) + ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, &CCryptDoc::OnUpdateEditRepeat) ON_COMMAND(ID_KNOWN_ANALYSIS_SINGLE_PERMUTATION, &CCryptDoc::OnKnownAnalysisSinglePermutation) END_MESSAGE_MAP() @@ -417,9 +417,9 @@ CHexDoc::~CHexDoc() BEGIN_MESSAGE_MAP(CHexDoc, CCryptDoc) //{{AFX_MSG_MAP(CHexDoc) - ON_COMMAND(ID_ENTROPY, OnEntropy) - ON_COMMAND(ID_HISTOGRAM, OnHistogram) - ON_COMMAND(ID_AUTO, OnAuto) + ON_COMMAND(ID_ENTROPY, &CHexDoc::OnEntropy) + ON_COMMAND(ID_HISTOGRAM, &CHexDoc::OnHistogram) + ON_COMMAND(ID_AUTO, &CHexDoc::OnAuto) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -483,9 +483,9 @@ void CAscDoc::Serialize(CArchive& ar) BEGIN_MESSAGE_MAP(CAscDoc, CCryptDoc) //{{AFX_MSG_MAP(CAscDoc) - ON_COMMAND(ID_ENTROPY, OnEntropy) - ON_COMMAND(ID_HISTOGRAM, OnHistogram) - ON_COMMAND(ID_AUTO, OnAuto) + ON_COMMAND(ID_ENTROPY, &CAscDoc::OnEntropy) + ON_COMMAND(ID_HISTOGRAM, &CAscDoc::OnHistogram) + ON_COMMAND(ID_AUTO, &CAscDoc::OnAuto) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -1307,7 +1307,7 @@ void CCryptDoc::OnAnalyseZufallstestsFrequencytest() int tempStringLength = strlen(pc_str) + strlen(GetTitle()) + 1; char *tempString = new char[tempStringLength]; memset(tempString, 0, tempStringLength); - sprintf(tempString, pc_str, GetTitle()); + sprintf(tempString, pc_str, (LPCTSTR)GetTitle()); FREQT.SetAlternativeWindowText(tempString); if ( FREQT.LoadAlphaList() ) FREQT.DoModal(); @@ -1341,7 +1341,7 @@ void CCryptDoc::OnAnalyseZufallstestsSerialtest() int tempStringLength = strlen(pc_str) + strlen(GetTitle()) + 1; char *tempString = new char[tempStringLength]; memset(tempString, 0, tempStringLength); - sprintf(tempString, pc_str, GetTitle()); + sprintf(tempString, pc_str, (LPCTSTR)GetTitle()); SERT.SetAlternativeWindowText(tempString); if ( SERT.LoadAlphaList() ) SERT.DoModal(); @@ -1371,7 +1371,7 @@ void CCryptDoc::OnAnalyseZufallstestsRuns() int tempStringLength = strlen(pc_str) + strlen(GetTitle()) + 1; char *tempString = new char[tempStringLength]; memset(tempString, 0, tempStringLength); - sprintf(tempString, pc_str, GetTitle()); + sprintf(tempString, pc_str, (LPCTSTR)GetTitle()); LRT.SetAlternativeWindowText( tempString ); if ( LRT.LoadAlphaList() ) @@ -1406,7 +1406,7 @@ void CCryptDoc::OnAnalyseZufallstestsPokertest() int tempStringLength = strlen(pc_str) + strlen(GetTitle()) + 1; char *tempString = new char[tempStringLength]; memset(tempString, 0, tempStringLength); - sprintf(tempString, pc_str, GetTitle()); + sprintf(tempString, pc_str, (LPCTSTR)GetTitle()); POKT.SetAlternativeWindowText(tempString); if ( POKT.LoadAlphaList() ) @@ -1448,7 +1448,7 @@ void CCryptDoc::OnAnalyseZufallstestsFipspub1401() int tempStringLength = strlen(pc_str) + strlen(GetTitle()) + 1; char *tempString = new char[tempStringLength]; memset(tempString, 0, tempStringLength); - sprintf(tempString, pc_str, GetTitle()); + sprintf(tempString, pc_str, (LPCTSTR)GetTitle()); FIPS.SetAlternativeWindowText(tempString); FIPS.DoModal(); delete tempString; @@ -1460,7 +1460,7 @@ void CCryptDoc::OnAesSelfextract() { UpdateContent(); CString str_m_Selfextract_EXE_Quoted = CString("\"") + CString(theApp.m_Selfextract_EXE) + CString("\""); - _spawnl(_P_NOWAIT, theApp.m_Selfextract_EXE, str_m_Selfextract_EXE_Quoted, ContentName, NULL); + _spawnl(_P_NOWAIT, theApp.m_Selfextract_EXE, (LPCTSTR)str_m_Selfextract_EXE_Quoted, ContentName, NULL); // FIXME: Interpret return value of _spawnl } @@ -1760,7 +1760,7 @@ void CCryptDoc::OnAnalysisRandom3dVisualization() f.Close(); LoadString(AfxGetInstanceHandle(), IDS_TITLE_3D_VISUALISATION, pc_str, STR_LAENGE_STRING_TABLE); - sprintf(title, pc_str, GetTitle()); + sprintf(title, pc_str, (LPCTSTR)GetTitle()); theApp.ThreadOpenDocumentFileNoMRU(name,title); } diff --git a/CrypTool/CryptDoc.h b/CrypTool/CryptDoc.h index 1840b4f5a..8f5753352 100644 --- a/CrypTool/CryptDoc.h +++ b/CrypTool/CryptDoc.h @@ -21,7 +21,7 @@ #ifndef _CRYPTDOC_H_ #define _CRYPTDOC_H_ -#include "symEncBase.h" +#include "SymEncBase.h" #include "CrypToolApp.h" ////////////////////////////////////////////////////////////////// @@ -207,7 +207,7 @@ class CHexDoc : public CCryptDoc // Attributes public: -BOOL CHexDoc::UpdateContent( void ); +BOOL UpdateContent( void ); // Operations public: diff --git a/CrypTool/CryptDocTemplate.h b/CrypTool/CryptDocTemplate.h index 27c98ee94..893e6ddd5 100644 --- a/CrypTool/CryptDocTemplate.h +++ b/CrypTool/CryptDocTemplate.h @@ -18,7 +18,7 @@ **************************************************************************/ -#include +#include class CCryptDocTemplate : public CMultiDocTemplate { diff --git a/CrypTool/Cryptography.cpp b/CrypTool/Cryptography.cpp index 05252356b..42035ac96 100644 --- a/CrypTool/Cryptography.cpp +++ b/CrypTool/Cryptography.cpp @@ -75,7 +75,7 @@ using namespace std; #include "DlgKeyHexFixedLen.h" #include "DlgBruteForceAES.h" #include "ListResults.h" -#include "bruteforceheap.h" +#include "BruteForceHeap.h" #include #include @@ -1152,7 +1152,7 @@ void HistogramASCII(const char *infile, const char *OldTitle) LoadString(AfxGetInstanceHandle(),IDS_STRING_ASCII_HISTOGRAM_OF,pc_str,STR_LAENGE_STRING_TABLE); MakeNewName2(line,sizeof(line),pc_str,_itoa(len, numbuff, 10),OldTitle); - distr.Show(OStream(name)<< OStream::Title(0) << OStream::Description(0) << OStream::Summary(0) << OStream::Percent()); + { OStream os(name); distr.Show(os << OStream::Title(0) << OStream::Description(0) << OStream::Summary(0) << OStream::Percent()); } // get the tmp name without file extension strcpy(name2, name); name2[strlen(name)-4] = 0x0; @@ -1195,7 +1195,7 @@ void HistogramBin(const char *infile, const char *OldTitle) int len = text.GetSize(); LoadString(AfxGetInstanceHandle(),IDS_STRING_BINARY_HISTOGRAM_OF,pc_str,STR_LAENGE_STRING_TABLE); MakeNewName2(line,sizeof(line),pc_str,_itoa(len, numbuff, 10),OldTitle); - distr.Show(OStream(name)<< OStream::Title(0) << OStream::Description(0) << OStream::Summary(0) << OStream::Percent()); + { OStream os(name); distr.Show(os << OStream::Title(0) << OStream::Description(0) << OStream::Summary(0) << OStream::Percent()); } // get the tmp name without file extension strcpy(name2, name); @@ -2748,10 +2748,10 @@ void HomophonicSubstitutionAsc(const char *infile, const char *title) { stringTitle = title; stringKey = dlg.getKeyAsString(); if(result == IDENCRYPT) { - documentTitle.Format(IDS_STRING_ENCRYPTION_OF_USING_KEY, stringAlgorithm, stringTitle, stringKey); + documentTitle.Format(IDS_STRING_ENCRYPTION_OF_USING_KEY, (LPCTSTR)stringAlgorithm, (LPCTSTR)stringTitle, (LPCTSTR)stringKey); } if(result == IDDECRYPT) { - documentTitle.Format(IDS_STRING_DECRYPTION_OF_USING_KEY, stringAlgorithm, stringTitle, stringKey); + documentTitle.Format(IDS_STRING_DECRYPTION_OF_USING_KEY, (LPCTSTR)stringAlgorithm, (LPCTSTR)stringTitle, (LPCTSTR)stringKey); } document->SetTitle(documentTitle); } @@ -3046,11 +3046,11 @@ void Permutation(const char *infileName, const char *OldTitle, BOOL TEXTMODE) strcpy(dType , (Perm.m_DataType) ? TEXT_TOKEN : BINARY_TOKEN ); if(Perm.m_P2len) - sprintf(key,"%s;%s %s%s%s%i,%i,%i,%i,%i,%i", Perm.m_Perm1, Perm.m_Perm2, PARAM_TOKEN, dType, Invert, + sprintf(key,"%s;%s %s%s%s%i,%i,%i,%i,%i,%i", (LPCTSTR)Perm.m_Perm1, (LPCTSTR)Perm.m_Perm2, PARAM_TOKEN, dType, Invert, Perm.m_P1InSeq, Perm.m_P1Perm, Perm.m_P1OutSeq, Perm.m_P2InSeq, Perm.m_P2Perm, Perm.m_P2OutSeq); else - sprintf(key,"%s %s%s%s%i,%i,%i,%i,%i,%i", Perm.m_Perm1, PARAM_TOKEN, dType, Invert, + sprintf(key,"%s %s%s%s%i,%i,%i,%i,%i,%i", (LPCTSTR)Perm.m_Perm1, PARAM_TOKEN, dType, Invert, Perm.m_P1InSeq, Perm.m_P1Perm, Perm.m_P1OutSeq, Perm.m_P2InSeq, Perm.m_P2Perm, Perm.m_P2OutSeq); CAppDocument *NewDoc; @@ -3278,7 +3278,7 @@ void SymmetricEncryption(int AlgId, cryptProvider provider, char keybuffhex[256/4+1]; unsigned char keybuffbin[256/8]; - Title.Format(IDS_STRING_KEYINPUT_SYMMETRIC, AlgString); + Title.Format(IDS_STRING_KEYINPUT_SYMMETRIC, (LPCTSTR)AlgString); CDlgKeyHexFixedLen KeyDialog; if ( !fixed_keylength ) switch (AlgId) @@ -3437,7 +3437,7 @@ UINT SymmetricBruteForce(PVOID p) // start progress dialog CString title; - title.Format(IDS_STRING_ANALYSE_ON,AlgTitle); + title.Format(IDS_STRING_ANALYSE_ON,(LPCTSTR)AlgTitle); if(par->flags & CRYPT_DO_PROGRESS) { CString message; @@ -3794,7 +3794,7 @@ int RailFenceEncryption(const char *infile, const char *oldTitle, int key, int o if(encrypt) LoadString(AfxGetInstanceHandle(), IDS_STRING_RAIL_FENCE_ENCRYPTION_OF, pc_str, STR_LAENGE_STRING_TABLE); else LoadString(AfxGetInstanceHandle(), IDS_STRING_RAIL_FENCE_DECRYPTION_OF, pc_str, STR_LAENGE_STRING_TABLE); // now add the old title and the key into the new title - sprintf(title, pc_str, oldTitle, stringCompleteKey); + sprintf(title, pc_str, oldTitle, (LPCTSTR)stringCompleteKey); // set the new document title document->SetTitle(title); } @@ -4007,7 +4007,7 @@ int ScytaleEncryption(const char *infile, const char *oldTitle, int key, int off if(encrypt) LoadString(AfxGetInstanceHandle(), IDS_STRING_SCYTALE_ENCRYPTION_OF, pc_str, STR_LAENGE_STRING_TABLE); else LoadString(AfxGetInstanceHandle(), IDS_STRING_SCYTALE_DECRYPTION_OF, pc_str, STR_LAENGE_STRING_TABLE); // now add the old title and the key into the new title - sprintf(title, pc_str, oldTitle, stringCompleteKey); + sprintf(title, pc_str, oldTitle, (LPCTSTR)stringCompleteKey); // set the new document title document->SetTitle(title); } @@ -4026,7 +4026,8 @@ void Solitaire(const char *infile, const char *OldTitle) SHOW_HOUR_GLASS GetTmpName(outfile,"cry",".txt"); - crypt_solitaire( mySol.sol_action, infile, outfile, CString(mySol.InitialDeck) ); + CString initialDeck(mySol.InitialDeck); + crypt_solitaire( mySol.sol_action, infile, outfile, initialDeck ); // == Open the new document OpenNewDoc( outfile, mySol.InitialDeck, OldTitle, IDS_CRYPT_SOLITAIRE, ( mySol.sol_action ) ? 0 : 1 ); diff --git a/CrypTool/Cryptography.h b/CrypTool/Cryptography.h index c0c3c5c5c..590c89430 100644 --- a/CrypTool/Cryptography.h +++ b/CrypTool/Cryptography.h @@ -23,7 +23,7 @@ #include "DlgShowProgress.h" #include "MakeNewName.h" -#include "symEncBase.h" +#include "SymEncBase.h" #define _CRT_SECURE_NO_WARNINGS diff --git a/CrypTool/DESXL.cpp b/CrypTool/DESXL.cpp index d0643102d..76a4566c2 100644 --- a/CrypTool/DESXL.cpp +++ b/CrypTool/DESXL.cpp @@ -27,7 +27,7 @@ // at the Ruhr-University Bochum (http://www.crypto.rub.de) ////////////////////////////////////////////////////////////////// -#include ".\DESXL.h" +#include "DESXL.h" DESXL::DESXL(void) { diff --git a/CrypTool/DialogLaengeBin.cpp b/CrypTool/DialogLaengeBin.cpp index de7bdd3a9..8e4ddf7c2 100644 --- a/CrypTool/DialogLaengeBin.cpp +++ b/CrypTool/DialogLaengeBin.cpp @@ -60,8 +60,8 @@ void CDlgBinKeyLength::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgBinKeyLength, CDialog) //{{AFX_MSG_MAP(CDlgBinKeyLength) - ON_EN_CHANGE(IDC_EDIT2, OnChangeEdit2) - ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit2) + ON_EN_CHANGE(IDC_EDIT2, &CDlgBinKeyLength::OnChangeEdit2) + ON_EN_CHANGE(IDC_EDIT1, &CDlgBinKeyLength::OnChangeEdit2) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DiffieHellmanLogFile.cpp b/CrypTool/DiffieHellmanLogFile.cpp index eae0571f8..5c697fe21 100644 --- a/CrypTool/DiffieHellmanLogFile.cpp +++ b/CrypTool/DiffieHellmanLogFile.cpp @@ -21,7 +21,7 @@ // DiffieHellmanLogFile.cpp #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DiffieHellmanLogFile.h" diff --git a/CrypTool/DiffieHellmanParty.cpp b/CrypTool/DiffieHellmanParty.cpp index 8d8c444d0..a5836a378 100644 --- a/CrypTool/DiffieHellmanParty.cpp +++ b/CrypTool/DiffieHellmanParty.cpp @@ -95,7 +95,7 @@ std::string DiffieHellmanParty::GetSessionKey(std::string k)throw(DHError) // Diese Funktion setzt das Geheimnis (ein zufälliges Geheimnis wird erzeugt) // Parameter: keine -void DiffieHellmanParty::SetSecret() +void DiffieHellmanParty::SetSecret()throw(DHError) { // Geheimnis "ausdenken" irand((long)time(NULL)); diff --git a/CrypTool/DiffieHellmanParty.h b/CrypTool/DiffieHellmanParty.h index 7ba5857a5..e6d460ab1 100644 --- a/CrypTool/DiffieHellmanParty.h +++ b/CrypTool/DiffieHellmanParty.h @@ -34,11 +34,21 @@ /*****************************************************************/ // Miracl-Bibliothek (für große Zahlen) -#include "../libmiracl/include/BIG.H" +#include "big.h" #include -class DHError; +// Klasse zur Ausnahmebehandlung/Fehlerbehandlung +class DHError +{ +private: + long ErrorCode; + +public: + DHError(long e) { ErrorCode = e; }; + + long GetErrorCode() { return ErrorCode; }; +}; class DiffieHellmanParty { @@ -85,18 +95,6 @@ class DiffieHellmanParty bool HasSecret() { return bHasSecret; }; }; -// Klasse zur Ausnahmebehandlung/Fehlerbehandlung -class DHError -{ -private: - long ErrorCode; - -public: - DHError(long e) { ErrorCode = e; }; - - long GetErrorCode() { return ErrorCode; }; -}; - // Fehlercodes #define E_GENERATOR_INVALID 1 #define E_PRIME_INVALID 2 diff --git a/CrypTool/DlgADFGVX.cpp b/CrypTool/DlgADFGVX.cpp index 3ce8f9b13..80ab64528 100644 --- a/CrypTool/DlgADFGVX.cpp +++ b/CrypTool/DlgADFGVX.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgADFGVX.h" -#include ".\dlgadfgvx.h" +#include "DlgADFGVX.h" #include "DlgAdfgvxStringBox.h" #include "adfgvx.h" #include "FileTools.h" @@ -157,55 +157,55 @@ void CDlgADFGVX::DoDataExchange(CDataExchange* pDX) } BEGIN_MESSAGE_MAP(CDlgADFGVX, CDialog) - ON_BN_CLICKED(IDC_BUTTON_ENCRYPT, OnBnClickedButtonEncrypt) - ON_BN_CLICKED(IDC_BUTTON_DECRYPT, OnBnClickedButtonDecrypt) - ON_BN_CLICKED(IDC_BUTTON_INSERT_KEY, OnBnClickedButtonInsertKey) - ON_BN_CLICKED(IDC_MATRIX_SHUFFLE, OnBnClickedMatrixShuffle) - ON_BN_CLICKED(IDC_MATRIX_STANDARD, OnBnClickedMatrixStandard) - ON_BN_CLICKED(IDC_CANCEL, OnBnClickedCancel) - ON_EN_CHANGE(IDC_M00, OnEnChangeM00) - ON_EN_CHANGE(IDC_M01, OnEnChangeM01) - ON_EN_CHANGE(IDC_M02, OnEnChangeM02) - ON_EN_CHANGE(IDC_M03, OnEnChangeM03) - ON_EN_CHANGE(IDC_M04, OnEnChangeM04) - ON_EN_CHANGE(IDC_M05, OnEnChangeM05) - ON_EN_CHANGE(IDC_M10, OnEnChangeM10) - ON_EN_CHANGE(IDC_M11, OnEnChangeM11) - ON_EN_CHANGE(IDC_M12, OnEnChangeM12) - ON_EN_CHANGE(IDC_M13, OnEnChangeM13) - ON_EN_CHANGE(IDC_M14, OnEnChangeM14) - ON_EN_CHANGE(IDC_M15, OnEnChangeM15) - ON_EN_CHANGE(IDC_M20, OnEnChangeM20) - ON_EN_CHANGE(IDC_M21, OnEnChangeM21) - ON_EN_CHANGE(IDC_M22, OnEnChangeM22) - ON_EN_CHANGE(IDC_M23, OnEnChangeM23) - ON_EN_CHANGE(IDC_M24, OnEnChangeM24) - ON_EN_CHANGE(IDC_M25, OnEnChangeM25) - ON_EN_CHANGE(IDC_M30, OnEnChangeM30) - ON_EN_CHANGE(IDC_M31, OnEnChangeM31) - ON_EN_CHANGE(IDC_M32, OnEnChangeM32) - ON_EN_CHANGE(IDC_M33, OnEnChangeM33) - ON_EN_CHANGE(IDC_M34, OnEnChangeM34) - ON_EN_CHANGE(IDC_M35, OnEnChangeM35) - ON_EN_CHANGE(IDC_M40, OnEnChangeM40) - ON_EN_CHANGE(IDC_M41, OnEnChangeM41) - ON_EN_CHANGE(IDC_M42, OnEnChangeM42) - ON_EN_CHANGE(IDC_M43, OnEnChangeM43) - ON_EN_CHANGE(IDC_M44, OnEnChangeM44) - ON_EN_CHANGE(IDC_M45, OnEnChangeM45) - ON_EN_CHANGE(IDC_M50, OnEnChangeM50) - ON_EN_CHANGE(IDC_M51, OnEnChangeM51) - ON_EN_CHANGE(IDC_M52, OnEnChangeM52) - ON_EN_CHANGE(IDC_M53, OnEnChangeM53) - ON_EN_CHANGE(IDC_M54, OnEnChangeM54) - ON_EN_CHANGE(IDC_M55, OnEnChangeM55) - ON_EN_CHANGE(IDC_TEXTFIELD_PASSWORD, OnChangedTranspositionPassword) - ON_BN_CLICKED(IDC_CHECK_OUTPUT, OnBnClickedCheckOutputStage1) - ON_BN_CLICKED(IDC_ERASEMATRIX, OnBnClickedErasematrix) - ON_BN_CLICKED(IDC_CHECK_BLOCK_STAGE2, OnBnClickedCheckBlockStage2) - ON_BN_CLICKED(IDC_CHECK_BLOCK_STAGE1, OnBnClickedCheckBlockStage1) - ON_BN_CLICKED(IDC_BUTTON_STRINGBOX, OnBnClickedButtonStringbox) - ON_BN_CLICKED(IDC_BUTTON_TEXT_OPTIONS, OnBnClickedButtonTextOptions) + ON_BN_CLICKED(IDC_BUTTON_ENCRYPT, &CDlgADFGVX::OnBnClickedButtonEncrypt) + ON_BN_CLICKED(IDC_BUTTON_DECRYPT, &CDlgADFGVX::OnBnClickedButtonDecrypt) + ON_BN_CLICKED(IDC_BUTTON_INSERT_KEY, &CDlgADFGVX::OnBnClickedButtonInsertKey) + ON_BN_CLICKED(IDC_MATRIX_SHUFFLE, &CDlgADFGVX::OnBnClickedMatrixShuffle) + ON_BN_CLICKED(IDC_MATRIX_STANDARD, &CDlgADFGVX::OnBnClickedMatrixStandard) + ON_BN_CLICKED(IDC_CANCEL, &CDlgADFGVX::OnBnClickedCancel) + ON_EN_CHANGE(IDC_M00, &CDlgADFGVX::OnEnChangeM00) + ON_EN_CHANGE(IDC_M01, &CDlgADFGVX::OnEnChangeM01) + ON_EN_CHANGE(IDC_M02, &CDlgADFGVX::OnEnChangeM02) + ON_EN_CHANGE(IDC_M03, &CDlgADFGVX::OnEnChangeM03) + ON_EN_CHANGE(IDC_M04, &CDlgADFGVX::OnEnChangeM04) + ON_EN_CHANGE(IDC_M05, &CDlgADFGVX::OnEnChangeM05) + ON_EN_CHANGE(IDC_M10, &CDlgADFGVX::OnEnChangeM10) + ON_EN_CHANGE(IDC_M11, &CDlgADFGVX::OnEnChangeM11) + ON_EN_CHANGE(IDC_M12, &CDlgADFGVX::OnEnChangeM12) + ON_EN_CHANGE(IDC_M13, &CDlgADFGVX::OnEnChangeM13) + ON_EN_CHANGE(IDC_M14, &CDlgADFGVX::OnEnChangeM14) + ON_EN_CHANGE(IDC_M15, &CDlgADFGVX::OnEnChangeM15) + ON_EN_CHANGE(IDC_M20, &CDlgADFGVX::OnEnChangeM20) + ON_EN_CHANGE(IDC_M21, &CDlgADFGVX::OnEnChangeM21) + ON_EN_CHANGE(IDC_M22, &CDlgADFGVX::OnEnChangeM22) + ON_EN_CHANGE(IDC_M23, &CDlgADFGVX::OnEnChangeM23) + ON_EN_CHANGE(IDC_M24, &CDlgADFGVX::OnEnChangeM24) + ON_EN_CHANGE(IDC_M25, &CDlgADFGVX::OnEnChangeM25) + ON_EN_CHANGE(IDC_M30, &CDlgADFGVX::OnEnChangeM30) + ON_EN_CHANGE(IDC_M31, &CDlgADFGVX::OnEnChangeM31) + ON_EN_CHANGE(IDC_M32, &CDlgADFGVX::OnEnChangeM32) + ON_EN_CHANGE(IDC_M33, &CDlgADFGVX::OnEnChangeM33) + ON_EN_CHANGE(IDC_M34, &CDlgADFGVX::OnEnChangeM34) + ON_EN_CHANGE(IDC_M35, &CDlgADFGVX::OnEnChangeM35) + ON_EN_CHANGE(IDC_M40, &CDlgADFGVX::OnEnChangeM40) + ON_EN_CHANGE(IDC_M41, &CDlgADFGVX::OnEnChangeM41) + ON_EN_CHANGE(IDC_M42, &CDlgADFGVX::OnEnChangeM42) + ON_EN_CHANGE(IDC_M43, &CDlgADFGVX::OnEnChangeM43) + ON_EN_CHANGE(IDC_M44, &CDlgADFGVX::OnEnChangeM44) + ON_EN_CHANGE(IDC_M45, &CDlgADFGVX::OnEnChangeM45) + ON_EN_CHANGE(IDC_M50, &CDlgADFGVX::OnEnChangeM50) + ON_EN_CHANGE(IDC_M51, &CDlgADFGVX::OnEnChangeM51) + ON_EN_CHANGE(IDC_M52, &CDlgADFGVX::OnEnChangeM52) + ON_EN_CHANGE(IDC_M53, &CDlgADFGVX::OnEnChangeM53) + ON_EN_CHANGE(IDC_M54, &CDlgADFGVX::OnEnChangeM54) + ON_EN_CHANGE(IDC_M55, &CDlgADFGVX::OnEnChangeM55) + ON_EN_CHANGE(IDC_TEXTFIELD_PASSWORD, &CDlgADFGVX::OnChangedTranspositionPassword) + ON_BN_CLICKED(IDC_CHECK_OUTPUT, &CDlgADFGVX::OnBnClickedCheckOutputStage1) + ON_BN_CLICKED(IDC_ERASEMATRIX, &CDlgADFGVX::OnBnClickedErasematrix) + ON_BN_CLICKED(IDC_CHECK_BLOCK_STAGE2, &CDlgADFGVX::OnBnClickedCheckBlockStage2) + ON_BN_CLICKED(IDC_CHECK_BLOCK_STAGE1, &CDlgADFGVX::OnBnClickedCheckBlockStage1) + ON_BN_CLICKED(IDC_BUTTON_STRINGBOX, &CDlgADFGVX::OnBnClickedButtonStringbox) + ON_BN_CLICKED(IDC_BUTTON_TEXT_OPTIONS, &CDlgADFGVX::OnBnClickedButtonTextOptions) END_MESSAGE_MAP() BOOL CDlgADFGVX::OnInitDialog() diff --git a/CrypTool/DlgADFGVX.h b/CrypTool/DlgADFGVX.h index d5417253c..c629c7b84 100644 --- a/CrypTool/DlgADFGVX.h +++ b/CrypTool/DlgADFGVX.h @@ -42,9 +42,9 @@ class CDlgADFGVX : public CDialog CString pwdString; CString matrix[6][6]; CToolTipButton buttonInsertKey; - void CDlgADFGVX::OnOK(); - void CDlgADFGVX::Decrypt(); - void CDlgADFGVX::Encrypt(); + void OnOK(); + void Decrypt(); + void Encrypt(); bool restart; BOOL printStage1; BOOL newLineStage2, newLineStage1; @@ -111,9 +111,9 @@ class CDlgADFGVX : public CDialog afx_msg void OnBnClickedErasematrix(); afx_msg void OnBnClickedCheckBlockStage2(); afx_msg void OnBnClickedCheckBlockStage1(); - BOOL CDlgADFGVX::OnInitDialog(); - CString CDlgADFGVX::CheckInput(CString oldEntry, CString input); - void CDlgADFGVX::CheckProgress(); + BOOL OnInitDialog(); + CString CheckInput(CString oldEntry, CString input); + void CheckProgress(); CString numberedPassword; BOOL boxBlockOutput2; BOOL boxBlockOutput1; diff --git a/CrypTool/DlgAbout.cpp b/CrypTool/DlgAbout.cpp index d58c7d7d0..046dd180e 100644 --- a/CrypTool/DlgAbout.cpp +++ b/CrypTool/DlgAbout.cpp @@ -31,7 +31,7 @@ #include "DlgTranslations.h" // für NTL Bibliothek -#include "..\libNTL\include\NTL\version.h" +#include namespace OPENSSL { #include "crypto.h" // clashes with secude.h } @@ -82,8 +82,8 @@ void CDlgAbout::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgAbout, CDialog) //{{AFX_MSG_MAP(CDlgAbout) ON_WM_PAINT() - ON_BN_CLICKED(ID_CONTRIBUTORS, OnBnClickedContributors) - ON_BN_CLICKED(ID_TRANSLATIONS, OnBnClickedTranslations) + ON_BN_CLICKED(ID_CONTRIBUTORS, &CDlgAbout::OnBnClickedContributors) + ON_BN_CLICKED(ID_TRANSLATIONS, &CDlgAbout::OnBnClickedTranslations) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -148,10 +148,16 @@ BOOL CDlgAbout::OnInitDialog() CString buildDate; buildDate.Format(theApp.getBuildTime()); CString buildVersion; +#if defined(_MSC_VER) buildVersion.Format("MSC %d.%02d",_MSC_VER/100,_MSC_VER%100); +#elif defined(__clang__) + buildVersion.Format("clang %d.%d.%d",__clang_major__,__clang_minor__,__clang_patchlevel__); +#elif defined(__GNUC__) + buildVersion.Format("GCC %d.%d.%d",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__); +#endif // construct release information CString stringReleaseInformation; - stringReleaseInformation.Format(IDS_CRYPTOOL_RELEASE_INFORMATION, stringCrypToolVersion, buildSvnRevision, buildDate, buildVersion); + stringReleaseInformation.Format(IDS_CRYPTOOL_RELEASE_INFORMATION, (LPCTSTR)stringCrypToolVersion, (LPCTSTR)buildSvnRevision, (LPCTSTR)buildDate, (LPCTSTR)buildVersion); stringReleaseInformation.Append(strVersionApfloat); stringReleaseInformation.Append(", "); stringReleaseInformation.Append(strVersionCracklib); stringReleaseInformation.Append(", "); stringReleaseInformation.Append(strVersionCryptovision); stringReleaseInformation.Append(", "); @@ -237,7 +243,11 @@ void CDlgAbout::determineLibraryVersions() // GMP (dynamisch) CString StrGMPWindowText; +#ifdef __MPIR_VERSION StrGMPWindowText.Format("MPIR %s", mpir_version); +#else + StrGMPWindowText.Format("GMP %s", gmp_version); +#endif this->strVersionGMP = StrGMPWindowText; // CRACKLIB (statisch) diff --git a/CrypTool/DlgAdfgvxIntro.cpp b/CrypTool/DlgAdfgvxIntro.cpp index 3c89aa478..d62d8d3a1 100644 --- a/CrypTool/DlgAdfgvxIntro.cpp +++ b/CrypTool/DlgAdfgvxIntro.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgAdfgvxIntro.h" -#include ".\dlgadfgvxintro.h" +#include "DlgAdfgvxIntro.h" #include "CrypToolTools.h" @@ -49,7 +49,7 @@ void DlgAdfgvxIntro::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(DlgAdfgvxIntro, CDialog) - ON_BN_CLICKED(IDC_CHECK1, OnBnClickedCheck1) + ON_BN_CLICKED(IDC_CHECK1, &DlgAdfgvxIntro::OnBnClickedCheck1) END_MESSAGE_MAP() @@ -61,7 +61,7 @@ void DlgAdfgvxIntro::OnBnClickedCheck1() if ( CT_OPEN_REGISTRY_SETTINGS( KEY_WRITE, IDS_REGISTRY_SETTINGS, "ADFGVX" ) == ERROR_SUCCESS ) { - CT_WRITE_REGISTRY(unsigned long(noIntro), "ShowIntro"); + CT_WRITE_REGISTRY((unsigned long)(noIntro), "ShowIntro"); CT_CLOSE_REGISTRY(); } else diff --git a/CrypTool/DlgAdfgvxManual.cpp b/CrypTool/DlgAdfgvxManual.cpp index 364da4017..cbd0e0133 100644 --- a/CrypTool/DlgAdfgvxManual.cpp +++ b/CrypTool/DlgAdfgvxManual.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgAdfgvxManual.h" -#include ".\dlgadfgvxmanual.h" +#include "DlgAdfgvxManual.h" #include "DlgAdfgvxIntro.h" #include "DlgAdfgvxStringBox.h" #include "FileTools.h" @@ -217,54 +217,54 @@ void CDlgAdfgvxManual::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgAdfgvxManual, CDialog) //{{AFX_MSG_MAP(CDlgAdfgvxManual) - ON_BN_CLICKED(IDC_NEXT_PERMUTATION, OnBnClickedNextPermutation) - ON_EN_CHANGE(IDC_M00, OnEnChangeM00) - ON_EN_CHANGE(IDC_M01, OnEnChangeM01) - ON_EN_CHANGE(IDC_M02, OnEnChangeM02) - ON_EN_CHANGE(IDC_M03, OnEnChangeM03) - ON_EN_CHANGE(IDC_M04, OnEnChangeM04) - ON_EN_CHANGE(IDC_M05, OnEnChangeM05) - ON_EN_CHANGE(IDC_M10, OnEnChangeM10) - ON_EN_CHANGE(IDC_M11, OnEnChangeM11) - ON_EN_CHANGE(IDC_M12, OnEnChangeM12) - ON_EN_CHANGE(IDC_M13, OnEnChangeM13) - ON_EN_CHANGE(IDC_M14, OnEnChangeM14) - ON_EN_CHANGE(IDC_M15, OnEnChangeM15) - ON_EN_CHANGE(IDC_M20, OnEnChangeM20) - ON_EN_CHANGE(IDC_M21, OnEnChangeM21) - ON_EN_CHANGE(IDC_M22, OnEnChangeM22) - ON_EN_CHANGE(IDC_M23, OnEnChangeM23) - ON_EN_CHANGE(IDC_M24, OnEnChangeM24) - ON_EN_CHANGE(IDC_M25, OnEnChangeM25) - ON_EN_CHANGE(IDC_M30, OnEnChangeM30) - ON_EN_CHANGE(IDC_M31, OnEnChangeM31) - ON_EN_CHANGE(IDC_M32, OnEnChangeM32) - ON_EN_CHANGE(IDC_M33, OnEnChangeM33) - ON_EN_CHANGE(IDC_M34, OnEnChangeM34) - ON_EN_CHANGE(IDC_M35, OnEnChangeM35) - ON_EN_CHANGE(IDC_M40, OnEnChangeM40) - ON_EN_CHANGE(IDC_M41, OnEnChangeM41) - ON_EN_CHANGE(IDC_M42, OnEnChangeM42) - ON_EN_CHANGE(IDC_M43, OnEnChangeM43) - ON_EN_CHANGE(IDC_M44, OnEnChangeM44) - ON_EN_CHANGE(IDC_M45, OnEnChangeM45) - ON_EN_CHANGE(IDC_M50, OnEnChangeM50) - ON_EN_CHANGE(IDC_M51, OnEnChangeM51) - ON_EN_CHANGE(IDC_M52, OnEnChangeM52) - ON_EN_CHANGE(IDC_M53, OnEnChangeM53) - ON_EN_CHANGE(IDC_M54, OnEnChangeM54) - ON_EN_CHANGE(IDC_M55, OnEnChangeM55) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_CBN_SELCHANGE(IDC_MAXLENGTH, OnCbnSelchangeMaxlength) - ON_CBN_SELCHANGE(IDC_MINLENGTH, OnCbnSelchangeMinlength) - ON_BN_CLICKED(IDC_BUTTON_FORCE, OnBnClickedButtonForce) - ON_BN_CLICKED(IDC_RESET_MATRIX, OnBnClickedResetMatrix) + ON_BN_CLICKED(IDC_NEXT_PERMUTATION, &CDlgAdfgvxManual::OnBnClickedNextPermutation) + ON_EN_CHANGE(IDC_M00, &CDlgAdfgvxManual::OnEnChangeM00) + ON_EN_CHANGE(IDC_M01, &CDlgAdfgvxManual::OnEnChangeM01) + ON_EN_CHANGE(IDC_M02, &CDlgAdfgvxManual::OnEnChangeM02) + ON_EN_CHANGE(IDC_M03, &CDlgAdfgvxManual::OnEnChangeM03) + ON_EN_CHANGE(IDC_M04, &CDlgAdfgvxManual::OnEnChangeM04) + ON_EN_CHANGE(IDC_M05, &CDlgAdfgvxManual::OnEnChangeM05) + ON_EN_CHANGE(IDC_M10, &CDlgAdfgvxManual::OnEnChangeM10) + ON_EN_CHANGE(IDC_M11, &CDlgAdfgvxManual::OnEnChangeM11) + ON_EN_CHANGE(IDC_M12, &CDlgAdfgvxManual::OnEnChangeM12) + ON_EN_CHANGE(IDC_M13, &CDlgAdfgvxManual::OnEnChangeM13) + ON_EN_CHANGE(IDC_M14, &CDlgAdfgvxManual::OnEnChangeM14) + ON_EN_CHANGE(IDC_M15, &CDlgAdfgvxManual::OnEnChangeM15) + ON_EN_CHANGE(IDC_M20, &CDlgAdfgvxManual::OnEnChangeM20) + ON_EN_CHANGE(IDC_M21, &CDlgAdfgvxManual::OnEnChangeM21) + ON_EN_CHANGE(IDC_M22, &CDlgAdfgvxManual::OnEnChangeM22) + ON_EN_CHANGE(IDC_M23, &CDlgAdfgvxManual::OnEnChangeM23) + ON_EN_CHANGE(IDC_M24, &CDlgAdfgvxManual::OnEnChangeM24) + ON_EN_CHANGE(IDC_M25, &CDlgAdfgvxManual::OnEnChangeM25) + ON_EN_CHANGE(IDC_M30, &CDlgAdfgvxManual::OnEnChangeM30) + ON_EN_CHANGE(IDC_M31, &CDlgAdfgvxManual::OnEnChangeM31) + ON_EN_CHANGE(IDC_M32, &CDlgAdfgvxManual::OnEnChangeM32) + ON_EN_CHANGE(IDC_M33, &CDlgAdfgvxManual::OnEnChangeM33) + ON_EN_CHANGE(IDC_M34, &CDlgAdfgvxManual::OnEnChangeM34) + ON_EN_CHANGE(IDC_M35, &CDlgAdfgvxManual::OnEnChangeM35) + ON_EN_CHANGE(IDC_M40, &CDlgAdfgvxManual::OnEnChangeM40) + ON_EN_CHANGE(IDC_M41, &CDlgAdfgvxManual::OnEnChangeM41) + ON_EN_CHANGE(IDC_M42, &CDlgAdfgvxManual::OnEnChangeM42) + ON_EN_CHANGE(IDC_M43, &CDlgAdfgvxManual::OnEnChangeM43) + ON_EN_CHANGE(IDC_M44, &CDlgAdfgvxManual::OnEnChangeM44) + ON_EN_CHANGE(IDC_M45, &CDlgAdfgvxManual::OnEnChangeM45) + ON_EN_CHANGE(IDC_M50, &CDlgAdfgvxManual::OnEnChangeM50) + ON_EN_CHANGE(IDC_M51, &CDlgAdfgvxManual::OnEnChangeM51) + ON_EN_CHANGE(IDC_M52, &CDlgAdfgvxManual::OnEnChangeM52) + ON_EN_CHANGE(IDC_M53, &CDlgAdfgvxManual::OnEnChangeM53) + ON_EN_CHANGE(IDC_M54, &CDlgAdfgvxManual::OnEnChangeM54) + ON_EN_CHANGE(IDC_M55, &CDlgAdfgvxManual::OnEnChangeM55) + ON_BN_CLICKED(IDOK, &CDlgAdfgvxManual::OnBnClickedOk) + ON_CBN_SELCHANGE(IDC_MAXLENGTH, &CDlgAdfgvxManual::OnCbnSelchangeMaxlength) + ON_CBN_SELCHANGE(IDC_MINLENGTH, &CDlgAdfgvxManual::OnCbnSelchangeMinlength) + ON_BN_CLICKED(IDC_BUTTON_FORCE, &CDlgAdfgvxManual::OnBnClickedButtonForce) + ON_BN_CLICKED(IDC_RESET_MATRIX, &CDlgAdfgvxManual::OnBnClickedResetMatrix) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_MATRIX_STANDARD, OnBnClickedMatrixStandard) - ON_BN_CLICKED(IDC_BUTTON_STRINGBOX, OnBnClickedButtonStringbox) - ON_EN_CHANGE(IDC_EDIT_PASSWORD, OnChangedTranspositionPassword) - ON_BN_CLICKED(IDC_BUTTON_TEXT_OPTIONS, OnBnClickedButtonTextOptions) - ON_BN_CLICKED(IDC_INSERT_KEY, OnBnClickedInsertKey) + ON_BN_CLICKED(IDC_MATRIX_STANDARD, &CDlgAdfgvxManual::OnBnClickedMatrixStandard) + ON_BN_CLICKED(IDC_BUTTON_STRINGBOX, &CDlgAdfgvxManual::OnBnClickedButtonStringbox) + ON_EN_CHANGE(IDC_EDIT_PASSWORD, &CDlgAdfgvxManual::OnChangedTranspositionPassword) + ON_BN_CLICKED(IDC_BUTTON_TEXT_OPTIONS, &CDlgAdfgvxManual::OnBnClickedButtonTextOptions) + ON_BN_CLICKED(IDC_INSERT_KEY, &CDlgAdfgvxManual::OnBnClickedInsertKey) END_MESSAGE_MAP() diff --git a/CrypTool/DlgAdfgvxManual.h b/CrypTool/DlgAdfgvxManual.h index bd434284b..998583b25 100644 --- a/CrypTool/DlgAdfgvxManual.h +++ b/CrypTool/DlgAdfgvxManual.h @@ -23,7 +23,7 @@ #include "adfgvx.h" #include "afxwin.h" #include -#include +#include "AlphabetTextEdit.h" #include "ToolTipButton.h" // CDlgAdfgvxManual-Dialogfeld @@ -34,7 +34,7 @@ class CDlgAdfgvxManual : public CDialog DECLARE_DYNAMIC(CDlgAdfgvxManual) public: - CDlgAdfgvxManual::CDlgAdfgvxManual(char* infile, CString oldTitle, CWnd* pParent); + CDlgAdfgvxManual(char* infile, CString oldTitle, CWnd* pParent); //CDlgAdfgvxManual(CWnd* pParent = NULL); // Standardkonstruktor virtual ~CDlgAdfgvxManual(); @@ -119,7 +119,7 @@ class CDlgAdfgvxManual : public CDialog CString oldTitle; CString oldEntry; basic_string ::iterator strIterTyp; - CString CDlgAdfgvxManual::CheckInput(CString oldEntry, CString input); + CString CheckInput(CString oldEntry, CString input); CString numberedPassword; bool analysed; int validCiphertext; @@ -136,8 +136,8 @@ class CDlgAdfgvxManual : public CDialog CAlphabetTextEdit editTranspositionPassword; public: - BOOL CDlgAdfgvxManual::OnInitDialog(); - void CDlgAdfgvxManual::Permutate(); + BOOL OnInitDialog(); + void Permutate(); afx_msg void OnBnClickedButtonStringbox(); diff --git a/CrypTool/DlgAdfgvxStringBox.cpp b/CrypTool/DlgAdfgvxStringBox.cpp index cc9a207cc..99d0399fc 100644 --- a/CrypTool/DlgAdfgvxStringBox.cpp +++ b/CrypTool/DlgAdfgvxStringBox.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgAdfgvxStringBox.h" -#include ".\dlgadfgvxstringbox.h" +#include "DlgAdfgvxStringBox.h" // DlgAdfgvxStringBox-Dialogfeld @@ -49,7 +49,7 @@ void DlgAdfgvxStringBox::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(DlgAdfgvxStringBox, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDOK, &DlgAdfgvxStringBox::OnBnClickedOk) END_MESSAGE_MAP() BOOL DlgAdfgvxStringBox::OnInitDialog() diff --git a/CrypTool/DlgAdfgvxStringBox.h b/CrypTool/DlgAdfgvxStringBox.h index 814806c02..2605e55c0 100644 --- a/CrypTool/DlgAdfgvxStringBox.h +++ b/CrypTool/DlgAdfgvxStringBox.h @@ -45,6 +45,6 @@ class DlgAdfgvxStringBox : public CDialog private: CString input; - void DlgAdfgvxStringBox::OnOK(); - BOOL DlgAdfgvxStringBox::OnInitDialog(); + void OnOK(); + BOOL OnInitDialog(); }; diff --git a/CrypTool/DlgAutoSubstitutionAnalysis.cpp b/CrypTool/DlgAutoSubstitutionAnalysis.cpp index 3ef3f89bf..30b960621 100644 --- a/CrypTool/DlgAutoSubstitutionAnalysis.cpp +++ b/CrypTool/DlgAutoSubstitutionAnalysis.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "DlgAutoSubstitutionAnalysis.h" #ifdef _DEBUG @@ -72,10 +72,10 @@ void CDlgAutoSubstitutionAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgAutoSubstitutionAnalysis, CDialog) //{{AFX_MSG_MAP(CDlgAutoSubstitutionAnalysis) - ON_BN_CLICKED(ID_SUBST_Cancel, OnSUBSTCancel) + ON_BN_CLICKED(ID_SUBST_Cancel, &CDlgAutoSubstitutionAnalysis::OnSUBSTCancel) ON_WM_TIMER() - ON_BN_CLICKED(IDC_COPY, OnKeyCopy) - ON_BN_CLICKED(IDC_MANUAL, OnManualAnalysis) + ON_BN_CLICKED(IDC_COPY, &CDlgAutoSubstitutionAnalysis::OnKeyCopy) + ON_BN_CLICKED(IDC_MANUAL, &CDlgAutoSubstitutionAnalysis::OnManualAnalysis) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgAutoSubstitutionAnalysis.h b/CrypTool/DlgAutoSubstitutionAnalysis.h index fc36744bd..574ff2904 100644 --- a/CrypTool/DlgAutoSubstitutionAnalysis.h +++ b/CrypTool/DlgAutoSubstitutionAnalysis.h @@ -36,21 +36,21 @@ class CDlgAutoSubstitutionAnalysis : public CDialog public: CDlgAutoSubstitutionAnalysis(CWnd* pParent = NULL); // Standardkonstruktor - void CDlgAutoSubstitutionAnalysis::setText(char *text); - CString CDlgAutoSubstitutionAnalysis::getText(); - void CDlgAutoSubstitutionAnalysis::setLanguageInfo(char *text); - void CDlgAutoSubstitutionAnalysis::setKey(char *text); - CString CDlgAutoSubstitutionAnalysis::getKey(); - void CDlgAutoSubstitutionAnalysis::setCharacterNumber(char *text); - void CDlgAutoSubstitutionAnalysis::setSpaceInAlphabet(bool value); - - void CDlgAutoSubstitutionAnalysis::setThreadFinished(bool value); - bool CDlgAutoSubstitutionAnalysis::getThreadFinished(); - void CDlgAutoSubstitutionAnalysis::setGuiFinished(bool value); - bool CDlgAutoSubstitutionAnalysis::getGuiFinished(); - void CDlgAutoSubstitutionAnalysis::setThreadFailed(bool value); - bool CDlgAutoSubstitutionAnalysis::getThreadFailed(); - bool CDlgAutoSubstitutionAnalysis::getManualAnalysis(); + void setText(char *text); + CString getText(); + void setLanguageInfo(char *text); + void setKey(char *text); + CString getKey(); + void setCharacterNumber(char *text); + void setSpaceInAlphabet(bool value); + + void setThreadFinished(bool value); + bool getThreadFinished(); + void setGuiFinished(bool value); + bool getGuiFinished(); + void setThreadFailed(bool value); + bool getThreadFailed(); + bool getManualAnalysis(); // Dialogfelddaten diff --git a/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.cpp b/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.cpp index 2484ce0ff..e46999d21 100644 --- a/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.cpp +++ b/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "DlgAutoSubstitutionAnalysisAlgorithmChoice.h" #ifdef _DEBUG @@ -54,8 +54,8 @@ void CDlgAutoSubstitutionAnalysisAlgorithmChoice::DoDataExchange(CDataExchange* BEGIN_MESSAGE_MAP(CDlgAutoSubstitutionAnalysisAlgorithmChoice, CDialog) //{{AFX_MSG_MAP(CDlgAutoSubstitutionAnalysisAlgorithmChoice) - ON_BN_CLICKED(IDC_ALG_DIGRAM, OnAlgDigram) - ON_BN_CLICKED(IDC_ALG_WORD, OnAlgWord) + ON_BN_CLICKED(IDC_ALG_DIGRAM, &CDlgAutoSubstitutionAnalysisAlgorithmChoice::OnAlgDigram) + ON_BN_CLICKED(IDC_ALG_WORD, &CDlgAutoSubstitutionAnalysisAlgorithmChoice::OnAlgWord) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -74,7 +74,7 @@ void CDlgAutoSubstitutionAnalysisAlgorithmChoice::OnAlgWord() CheckRadioButton (IDC_ALG_DIGRAM, IDC_ALG_WORD, IDC_ALG_WORD); } -int CDlgAutoSubstitutionAnalysisAlgorithmChoice::DoModal() +INT_PTR CDlgAutoSubstitutionAnalysisAlgorithmChoice::DoModal() { return CDialog::DoModal(); } diff --git a/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.h b/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.h index e32cb2bf1..3cda08074 100644 --- a/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.h +++ b/CrypTool/DlgAutoSubstitutionAnalysisAlgorithmChoice.h @@ -48,7 +48,7 @@ class CDlgAutoSubstitutionAnalysisAlgorithmChoice : public CDialog // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CDlgAutoSubstitutionAnalysisAlgorithmChoice) public: - virtual int DoModal(); + virtual INT_PTR DoModal(); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL diff --git a/CrypTool/DlgAutomatedPermAnalysis.cpp b/CrypTool/DlgAutomatedPermAnalysis.cpp index 3c800778b..dae22cc33 100644 --- a/CrypTool/DlgAutomatedPermAnalysis.cpp +++ b/CrypTool/DlgAutomatedPermAnalysis.cpp @@ -381,7 +381,7 @@ bool copy_perm_key::copy_key(long ndx) LoadString(AfxGetInstanceHandle(),IDS_CRYPT_PERMUTATION,pc_str,STR_LAENGE_STRING_TABLE); strKey.Format("%s %s%s%i,%i,%i,%i,%i,%i", - str, PARAM_TOKEN, (m_dataType) ? TEXT_TOKEN : BINARY_TOKEN, p->dirPlain, p->dirPerm, p->dirCipher, 0, 0, 0); + (LPCTSTR)str, PARAM_TOKEN, (m_dataType) ? TEXT_TOKEN : BINARY_TOKEN, p->dirPlain, p->dirPerm, p->dirCipher, 0, 0, 0); CopyKey ( pc_str, strKey ); return true; diff --git a/CrypTool/DlgBruteForceAES.cpp b/CrypTool/DlgBruteForceAES.cpp index 15da71da2..730f78166 100644 --- a/CrypTool/DlgBruteForceAES.cpp +++ b/CrypTool/DlgBruteForceAES.cpp @@ -29,7 +29,7 @@ #include "Cryptography.h" #include "HexEdit.h" #include "DlgBruteForceAES.h" -#include ".\dlgbruteforceaes.h" +#include "DlgBruteForceAES.h" // nibble i contains a parity bit if m_parity == CRYPT_PARITY_DES*: in low nibble (i & 1) and for DESX* in the first 64 bit only #define parity_in_nibble(i) (m_parity_check && (i & 1) && (m_parity_check != CRYPT_PARITY_DESX || i < 64/4)) @@ -67,11 +67,11 @@ void CDlgBruteForceAES::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgBruteForceAES, CDialog) //{{AFX_MSG_MAP(CDlgBruteForceAES) - ON_EN_UPDATE(IDC_EDIT1, OnUpdate) - ON_CBN_SELCHANGE(IDC_KEY_LEN, OnSelchangeKeyLen) - ON_EN_SETFOCUS(IDC_EDIT1, OnSetfocusHexEdit) + ON_EN_UPDATE(IDC_EDIT1, &CDlgBruteForceAES::OnUpdate) + ON_CBN_SELCHANGE(IDC_KEY_LEN, &CDlgBruteForceAES::OnSelchangeKeyLen) + ON_EN_SETFOCUS(IDC_EDIT1, &CDlgBruteForceAES::OnSetfocusHexEdit) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDOK2, OnBnClickedOk2) + ON_BN_CLICKED(IDOK2, &CDlgBruteForceAES::OnBnClickedOk2) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -222,7 +222,7 @@ BOOL CDlgBruteForceAES::OnInitDialog() { CDialog::OnInitDialog(); CString titel; - titel.Format(IDS_STRING_ANALYSE_ON,m_alg); + titel.Format(IDS_STRING_ANALYSE_ON,(LPCTSTR)m_alg); SetWindowText(titel); m_font.CreatePointFont(100,"Courier New"); m_text_ctl.SetFont(&m_font); diff --git a/CrypTool/DlgCaesarAnalysis.cpp b/CrypTool/DlgCaesarAnalysis.cpp index 9db95a338..3cd253843 100644 --- a/CrypTool/DlgCaesarAnalysis.cpp +++ b/CrypTool/DlgCaesarAnalysis.cpp @@ -61,7 +61,7 @@ void CDlgCaesarAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCaesarAnalysis, CDialog) //{{AFX_MSG_MAP(CDlgCaesarAnalysis) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1) + ON_EN_UPDATE(IDC_EDIT1, &CDlgCaesarAnalysis::OnUpdateEdit1) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgCertificateGeneration.cpp b/CrypTool/DlgCertificateGeneration.cpp index 726a143cc..4d59e44e1 100644 --- a/CrypTool/DlgCertificateGeneration.cpp +++ b/CrypTool/DlgCertificateGeneration.cpp @@ -81,10 +81,10 @@ void CDlgCertificateGeneration::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCertificateGeneration, CDialog) //{{AFX_MSG_MAP(CDlgCertificateGeneration) - ON_EN_CHANGE(IDC_EDIT_CERTNAME, OnChangeEdit) - ON_BN_CLICKED(IDC_PSE_IMPORT, OnPseImport) - ON_EN_CHANGE(IDC_EDIT_CERT_FIRSTNAME, OnChangeEdit) - ON_EN_CHANGE(IDC_EDIT_CERT_KEY_ID, OnChangeEdit) + ON_EN_CHANGE(IDC_EDIT_CERTNAME, &CDlgCertificateGeneration::OnChangeEdit) + ON_BN_CLICKED(IDC_PSE_IMPORT, &CDlgCertificateGeneration::OnPseImport) + ON_EN_CHANGE(IDC_EDIT_CERT_FIRSTNAME, &CDlgCertificateGeneration::OnChangeEdit) + ON_EN_CHANGE(IDC_EDIT_CERT_KEY_ID, &CDlgCertificateGeneration::OnChangeEdit) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgChangePIN.cpp b/CrypTool/DlgChangePIN.cpp index 44b2092ee..92639b82e 100644 --- a/CrypTool/DlgChangePIN.cpp +++ b/CrypTool/DlgChangePIN.cpp @@ -108,6 +108,7 @@ BEGIN_MESSAGE_MAP(CDlgChangePIN, CDialog) //}}AFX_MSG_MAP END_MESSAGE_MAP() +#ifdef _WIN32 BEGIN_DISPATCH_MAP(CDlgChangePIN, CDialog) //{{AFX_DISPATCH_MAP(CDlgChangePIN) // HINWEIS - Der Klassen-Assistent fügt hier Zuordnungsmakros ein und entfernt diese. @@ -125,6 +126,7 @@ static const IID IID_IPinAndNewPinDialog = BEGIN_INTERFACE_MAP(CDlgChangePIN, CDialog) INTERFACE_PART(CDlgChangePIN, IID_IPinAndNewPinDialog, Dispatch) END_INTERFACE_MAP() +#endif ///////////////////////////////////////////////////////////////////////////// // Behandlungsroutinen für Nachrichten CDlgChangePIN diff --git a/CrypTool/DlgChangePIN.h b/CrypTool/DlgChangePIN.h index f2a73fa9b..b72411fd1 100644 --- a/CrypTool/DlgChangePIN.h +++ b/CrypTool/DlgChangePIN.h @@ -102,8 +102,10 @@ class CDlgChangePIN : public CDialog //{{AFX_DISPATCH(CDlgChangePIN) // HINWEIS - Der Klassen-Assistent fügt hier Member-Funktionen ein und entfernt diese. //}}AFX_DISPATCH +#ifdef _WIN32 DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP() +#endif }; //{{AFX_INSERT_LOCATION}} diff --git a/CrypTool/DlgCrtAstronomy.cpp b/CrypTool/DlgCrtAstronomy.cpp index 99bc3d359..d7a29567f 100644 --- a/CrypTool/DlgCrtAstronomy.cpp +++ b/CrypTool/DlgCrtAstronomy.cpp @@ -23,7 +23,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgCrtAstronomy.h" -#include ".\dlgcrtastronomy.h" +#include "DlgCrtAstronomy.h" #include "big.h" #include "crt.h" #include "IntegerArithmetic.h" @@ -120,38 +120,38 @@ void CDlgCrtAstronomy::DoDataExchange(CDataExchange* pDX) } BEGIN_MESSAGE_MAP(CDlgCrtAstronomy, CDialog) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONSOLVE, OnBnClickedCrtAstronomyButtonsolve) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONRESET, OnBnClickedCrtAstronomyButtonreset) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONEND, OnBnClickedCrtAstronomyButtonend) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA0, OnEnChangeCrtAstronomyEdita0) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA1, OnEnChangeCrtAstronomyEdita1) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA2, OnEnChangeCrtAstronomyEdita2) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA3, OnEnChangeCrtAstronomyEdita3) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA4, OnEnChangeCrtAstronomyEdita4) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA5, OnEnChangeCrtAstronomyEdita5) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA6, OnEnChangeCrtAstronomyEdita6) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA7, OnEnChangeCrtAstronomyEdita7) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA8, OnEnChangeCrtAstronomyEdita8) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM0, OnEnChangeCrtAstronomyEditm0) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM1, OnEnChangeCrtAstronomyEditm1) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM2, OnEnChangeCrtAstronomyEditm2) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM3, OnEnChangeCrtAstronomyEditm3) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM4, OnEnChangeCrtAstronomyEditm4) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM5, OnEnChangeCrtAstronomyEditm5) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM6, OnEnChangeCrtAstronomyEditm6) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM7, OnEnChangeCrtAstronomyEditm7) - ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM8, OnEnChangeCrtAstronomyEditm8) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKMERCURY, OnBnClickedCrtAstronomyCheckmercury) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKVENUS, OnBnClickedCrtAstronomyCheckvenus) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKEARTH, OnBnClickedCrtAstronomyCheckearth) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKMARS, OnBnClickedCrtAstronomyCheckmars) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKJUPITER, OnBnClickedCrtAstronomyCheckjupiter) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKSATURN, OnBnClickedCrtAstronomyChecksaturn) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKURANUS, OnBnClickedCrtAstronomyCheckuranus) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKNEPTUN, OnBnClickedCrtAstronomyCheckneptun) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKPLUTO, OnBnClickedCrtAstronomyCheckpluto) - ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONRESET2, OnBnClickedCrtAstronomyButtonreset2) - ON_STN_CLICKED(IDC_Image, OnStnClickedImage) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONSOLVE, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyButtonsolve) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONRESET, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyButtonreset) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONEND, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyButtonend) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA0, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita0) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA1, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita1) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA2, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita2) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA3, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita3) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA4, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita4) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA5, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita5) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA6, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita6) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA7, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita7) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITA8, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEdita8) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM0, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm0) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM1, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm1) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM2, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm2) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM3, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm3) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM4, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm4) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM5, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm5) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM6, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm6) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM7, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm7) + ON_EN_CHANGE(IDC_CRT_ASTRONOMY_EDITM8, &CDlgCrtAstronomy::OnEnChangeCrtAstronomyEditm8) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKMERCURY, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckmercury) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKVENUS, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckvenus) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKEARTH, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckearth) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKMARS, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckmars) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKJUPITER, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckjupiter) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKSATURN, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyChecksaturn) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKURANUS, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckuranus) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKNEPTUN, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckneptun) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_CHECKPLUTO, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyCheckpluto) + ON_BN_CLICKED(IDC_CRT_ASTRONOMY_BUTTONRESET2, &CDlgCrtAstronomy::OnBnClickedCrtAstronomyButtonreset2) + ON_STN_CLICKED(IDC_Image, &CDlgCrtAstronomy::OnStnClickedImage) END_MESSAGE_MAP() @@ -217,7 +217,7 @@ bool CDlgCrtAstronomy::testeteilerfremd() CString planetall; planetall.LoadString(IDS_CRT_ASTRONOMY_PLANETALL); - ausgabe.Format(planetall,planet1,modul1,planet2,modul2); + ausgabe.Format(planetall,(LPCTSTR)planet1,(LPCTSTR)modul1,(LPCTSTR)planet2,(LPCTSTR)modul2); text=text+ausgabe; prim=false; } diff --git a/CrypTool/DlgCrtSecretSharing.cpp b/CrypTool/DlgCrtSecretSharing.cpp index 017265685..b79827f7c 100644 --- a/CrypTool/DlgCrtSecretSharing.cpp +++ b/CrypTool/DlgCrtSecretSharing.cpp @@ -25,7 +25,7 @@ #include "stdlib.h" #include "CrypToolApp.h" #include "DlgCrtSecretSharing.h" -#include ".\dlgcrtsecretsharing.h" +#include "DlgCrtSecretSharing.h" #include "DlgCrtSecretSharingOptions.h" #include "DlgCrtSecretSharing_Facts.h" #include "DlgCrtSecretSharing_Log.h" @@ -121,23 +121,23 @@ void CDlgCrtSecretSharing::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCrtSecretSharing, CDialog) - ON_BN_CLICKED(IDC_SECRETSHARING_BUTTON1, OnBnClickedSecretsharingShare) - ON_BN_CLICKED(IDC_SECRETSHARING_BUTTON2, OnBnClickedSecretsharingReset) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSecretsharingSolve) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD1, OnBnClickedSecretsharingAdd1) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD2, OnBnClickedSecretsharingAdd2) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD3, OnBnClickedSecretsharingAdd3) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD4, OnBnClickedSecretsharingAdd4) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD5, OnBnClickedSecretsharingAdd5) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD6, OnBnClickedSecretsharingAdd6) - ON_BN_CLICKED(IDC_SECRETSHARING_ADD7, OnBnClickedSecretsharingAdd7) - ON_BN_CLICKED(IDC_SECRETSHARING_ALGO, OnBnClickedSecretsharingEnd) - ON_BN_CLICKED(IDC_BUTTON4, OnBnClickedSecretsharingOptions) - ON_BN_CLICKED(IDC_SECRETSHARING_FACTS, OnBnClickedSecretsharingFacts) - ON_BN_CLICKED(IDC_SECRETSHARING_LOG, OnBnClickedSecretsharingLog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDC_CRT_Radio_AUT, OnBnClickedCrtRadioAut) - ON_BN_CLICKED(IDC_CRT_RADIO_MAN, OnBnClickedCrtRadioMan) + ON_BN_CLICKED(IDC_SECRETSHARING_BUTTON1, &CDlgCrtSecretSharing::OnBnClickedSecretsharingShare) + ON_BN_CLICKED(IDC_SECRETSHARING_BUTTON2, &CDlgCrtSecretSharing::OnBnClickedSecretsharingReset) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgCrtSecretSharing::OnBnClickedSecretsharingSolve) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD1, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd1) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD2, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd2) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD3, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd3) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD4, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd4) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD5, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd5) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD6, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd6) + ON_BN_CLICKED(IDC_SECRETSHARING_ADD7, &CDlgCrtSecretSharing::OnBnClickedSecretsharingAdd7) + ON_BN_CLICKED(IDC_SECRETSHARING_ALGO, &CDlgCrtSecretSharing::OnBnClickedSecretsharingEnd) + ON_BN_CLICKED(IDC_BUTTON4, &CDlgCrtSecretSharing::OnBnClickedSecretsharingOptions) + ON_BN_CLICKED(IDC_SECRETSHARING_FACTS, &CDlgCrtSecretSharing::OnBnClickedSecretsharingFacts) + ON_BN_CLICKED(IDC_SECRETSHARING_LOG, &CDlgCrtSecretSharing::OnBnClickedSecretsharingLog) + ON_BN_CLICKED(IDOK, &CDlgCrtSecretSharing::OnBnClickedOk) + ON_BN_CLICKED(IDC_CRT_Radio_AUT, &CDlgCrtSecretSharing::OnBnClickedCrtRadioAut) + ON_BN_CLICKED(IDC_CRT_RADIO_MAN, &CDlgCrtSecretSharing::OnBnClickedCrtRadioMan) END_MESSAGE_MAP() // CDlgCrtAstronomy-Meldungshandler @@ -1135,12 +1135,12 @@ void CDlgCrtSecretSharing::OnBnClickedSecretsharingSolve() CString Ctemp3; BigToCString(remainingPossibilities, Ctemp3, 10); dum.LoadString(IDS_CRT_SECRETSHARING_REK6); - helper.Format(dum, anzahl, m_need, Ctemp3); + helper.Format(dum, anzahl, m_need, (LPCTSTR)Ctemp3); AfxMessageBox(helper, MB_ICONINFORMATION); // Log-Datei helpme.LoadString(IDS_CRT_SECRETSHARING_REK7); - helper.Format(helpme,Ctemp3); + helper.Format(helpme,(LPCTSTR)Ctemp3); m_log=m_log+helper; } @@ -1162,10 +1162,10 @@ void CDlgCrtSecretSharing::OnBnClickedSecretsharingSolve() BigToCString(s,dummy,10); HIDE_HOUR_GLASS // deaktiviert die Sanduhr helpme.LoadString(IDS_CRT_SECRETSHARING_REK8); - helping.Format(helpme,dummy); + helping.Format(helpme,(LPCTSTR)dummy); AfxMessageBox(helping, MB_ICONINFORMATION ); helping.LoadString(IDS_CRT_SECRETSHARING_SUCCESS); - helper.Format(helping, dummy); + helper.Format(helping, (LPCTSTR)dummy); m_log=m_log+helper; } diff --git a/CrypTool/DlgCrtSecretSharingOptions.cpp b/CrypTool/DlgCrtSecretSharingOptions.cpp index 7b8867078..f10c00879 100644 --- a/CrypTool/DlgCrtSecretSharingOptions.cpp +++ b/CrypTool/DlgCrtSecretSharingOptions.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgCrtSecretSharingOptions.h" -#include ".\dlgcrtsecretsharingoptions.h" +#include "DlgCrtSecretSharingOptions.h" #include "DialogeMessage.h" #include "IntegerArithmetic.h" #include "big.h" @@ -59,8 +59,8 @@ void CDlgCrtSecretSharingOptions::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCrtSecretSharingOptions, CDialog) - ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel) - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDCANCEL, &CDlgCrtSecretSharingOptions::OnBnClickedCancel) + ON_BN_CLICKED(IDOK, &CDlgCrtSecretSharingOptions::OnBnClickedOk) END_MESSAGE_MAP() // CDlgCrtSecretSharingOptions-Meldungshandler diff --git a/CrypTool/DlgCrtSecretSharing_Facts.cpp b/CrypTool/DlgCrtSecretSharing_Facts.cpp index 3610b8fd0..8e2c4bc79 100644 --- a/CrypTool/DlgCrtSecretSharing_Facts.cpp +++ b/CrypTool/DlgCrtSecretSharing_Facts.cpp @@ -25,7 +25,7 @@ #include "stdlib.h" #include "CrypToolApp.h" #include "DlgCrtSecretSharing_Facts.h" -#include ".\dlgcrtsecretsharing_Facts.h" +#include "DlgCrtSecretSharing_Facts.h" #include "DlgCrtSecretSharing_Log.h" #include "DialogeMessage.h" @@ -66,8 +66,8 @@ void CDlgCrtSecretSharing_Facts::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCrtSecretSharing_Facts, CDialog) - ON_BN_CLICKED(IDC_CRT_SHOWLOG, OnBnClickedCrtShowlog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDC_CRT_SHOWLOG, &CDlgCrtSecretSharing_Facts::OnBnClickedCrtShowlog) + ON_BN_CLICKED(IDOK, &CDlgCrtSecretSharing_Facts::OnBnClickedOk) END_MESSAGE_MAP() diff --git a/CrypTool/DlgCrtSecretSharing_Info.cpp b/CrypTool/DlgCrtSecretSharing_Info.cpp index 741c65591..1711ab0e1 100644 --- a/CrypTool/DlgCrtSecretSharing_Info.cpp +++ b/CrypTool/DlgCrtSecretSharing_Info.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgCrtSecretSharing_Info.h" -#include ".\dlgcrtsecretsharing_info.h" +#include "DlgCrtSecretSharing_Info.h" // Aus DH-Intro.cpp eingefügt #ifdef _DEBUG diff --git a/CrypTool/DlgCrtSecretSharing_Log.cpp b/CrypTool/DlgCrtSecretSharing_Log.cpp index 25fc4634a..962140ff1 100644 --- a/CrypTool/DlgCrtSecretSharing_Log.cpp +++ b/CrypTool/DlgCrtSecretSharing_Log.cpp @@ -27,7 +27,7 @@ #include "FileTools.h" #include "CrypToolApp.h" #include "DlgCrtSecretSharing_Log.h" -#include ".\dlgcrtsecretsharing_log.h" +#include "DlgCrtSecretSharing_Log.h" // #include // CDlgCrtSecretSharing_Log-Dialogfeld @@ -51,8 +51,8 @@ void CDlgCrtSecretSharing_Log::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCrtSecretSharing_Log, baseCTestDlg) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) - ON_BN_CLICKED(IDC_CRT_SecretSharing_Log_Save, OnBnClickedCrtSecretsharingLogSave) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgCrtSecretSharing_Log::OnBnClickedButton1) + ON_BN_CLICKED(IDC_CRT_SecretSharing_Log_Save, &CDlgCrtSecretSharing_Log::OnBnClickedCrtSecretsharingLogSave) END_MESSAGE_MAP() diff --git a/CrypTool/DlgCrtTransformation.cpp b/CrypTool/DlgCrtTransformation.cpp index d0172d900..2ddb883bc 100644 --- a/CrypTool/DlgCrtTransformation.cpp +++ b/CrypTool/DlgCrtTransformation.cpp @@ -23,7 +23,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgCrtTransformation.h" -#include ".\dlgcrttransformation.h" +#include "DlgCrtTransformation.h" #include "big.h" #include "crt.h" #include "IntegerArithmetic.h" @@ -94,25 +94,25 @@ void CDlgCrtTransformation::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgCrtTransformation, CDialog) - ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_BUTTONSOLVE, OnBnClickedCrtTransformationButtonsolve) - ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_BUTTONRESET2, OnBnClickedCrtTransformationButtonreset) - ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_BUTTONEND2, OnBnClickedCrtTransformationButtonend) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITA0, OnEnChangeCrtTransformationEdita0) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITA1, OnEnChangeCrtTransformationEdita1) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM0, OnEnChangeCrtTransformationEditm0) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM1, OnEnChangeCrtTransformationEditm1) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM2, OnEnChangeCrtTransformationEditm2) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM3, OnEnChangeCrtTransformationEditm3) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM4, OnEnChangeCrtTransformationEditm4) - ON_BN_CLICKED(IDC_Generate1, OnBnClickedGenerate1) - ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_RADIO1, OnBnClickedCrtTransformationRadio1) - ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_RADIO2, OnBnClickedCrtTransformationRadio2) - ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_RADIO3, OnBnClickedCrtTransformationRadio3) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITANZAHL, OnEnChangeCrtTransformationEditanzahl) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITX, OnEnChangeCrtTransformationEditx) - ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITY, OnEnChangeCrtTransformationEdity) - ON_BN_CLICKED(IDC_GENERATERADIO1, OnBnClickedGenerateradio1) - ON_BN_CLICKED(IDC_GENERATERADIO2, OnBnClickedGenerateradio2) + ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_BUTTONSOLVE, &CDlgCrtTransformation::OnBnClickedCrtTransformationButtonsolve) + ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_BUTTONRESET2, &CDlgCrtTransformation::OnBnClickedCrtTransformationButtonreset) + ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_BUTTONEND2, &CDlgCrtTransformation::OnBnClickedCrtTransformationButtonend) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITA0, &CDlgCrtTransformation::OnEnChangeCrtTransformationEdita0) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITA1, &CDlgCrtTransformation::OnEnChangeCrtTransformationEdita1) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM0, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditm0) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM1, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditm1) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM2, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditm2) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM3, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditm3) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITM4, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditm4) + ON_BN_CLICKED(IDC_Generate1, &CDlgCrtTransformation::OnBnClickedGenerate1) + ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_RADIO1, &CDlgCrtTransformation::OnBnClickedCrtTransformationRadio1) + ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_RADIO2, &CDlgCrtTransformation::OnBnClickedCrtTransformationRadio2) + ON_BN_CLICKED(IDC_CRT_TRANSFORMATION_RADIO3, &CDlgCrtTransformation::OnBnClickedCrtTransformationRadio3) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITANZAHL, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditanzahl) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITX, &CDlgCrtTransformation::OnEnChangeCrtTransformationEditx) + ON_EN_CHANGE(IDC_CRT_TRANSFORMATION_EDITY, &CDlgCrtTransformation::OnEnChangeCrtTransformationEdity) + ON_BN_CLICKED(IDC_GENERATERADIO1, &CDlgCrtTransformation::OnBnClickedGenerateradio1) + ON_BN_CLICKED(IDC_GENERATERADIO2, &CDlgCrtTransformation::OnBnClickedGenerateradio2) END_MESSAGE_MAP() @@ -340,7 +340,7 @@ bool CDlgCrtTransformation::testeteilerfremd() CString planetall; planetall.LoadString(IDS_CRT_TRANSFORMATION_PLANETALL); - ausgabe.Format(planetall,planet1,modul1,planet2,modul2); + ausgabe.Format(planetall,(LPCTSTR)planet1,(LPCTSTR)modul1,(LPCTSTR)planet2,(LPCTSTR)modul2); text=text+ausgabe; prim=false; } @@ -455,10 +455,10 @@ void CDlgCrtTransformation::OnBnClickedCrtTransformationButtonsolve() CString anzeige; if (((a-b)<0)&&(m_radio==2)) { text.LoadString(IDS_CRT_TRANSFORMATION_NOTINRANGE2); - anzeige.Format(text,ergtext); + anzeige.Format(text,(LPCTSTR)ergtext); } else {text.LoadString(IDS_CRT_TRANSFORMATION_NOTINRANGE); - anzeige.Format(text,m_bereich,ergtext); + anzeige.Format(text,(LPCTSTR)m_bereich,(LPCTSTR)ergtext); } AfxMessageBox(anzeige, MB_ICONINFORMATION | MB_OK); } diff --git a/CrypTool/DlgDemoRSAKeyGeneration.cpp b/CrypTool/DlgDemoRSAKeyGeneration.cpp index 36f268895..33a0cc16b 100644 --- a/CrypTool/DlgDemoRSAKeyGeneration.cpp +++ b/CrypTool/DlgDemoRSAKeyGeneration.cpp @@ -81,11 +81,11 @@ void CDlgDemoRSAKeyGeneration::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgDemoRSAKeyGeneration, CDialog) //{{AFX_MSG_MAP(CDlgDemoRSAKeyGeneration) - ON_BN_CLICKED(IDC_GENERATE_PRIME, OnGeneratePrime) - ON_EN_UPDATE(IDC_EDIT_RSA_KEY_PUBLIC, OnUpdateParameter) - ON_BN_CLICKED(IDOK, OnOK) - ON_EN_UPDATE(IDC_EDIT_PRIME_P, OnUpdateParameter) - ON_EN_UPDATE(IDC_EDIT_PRIME_Q, OnUpdateParameter) + ON_BN_CLICKED(IDC_GENERATE_PRIME, &CDlgDemoRSAKeyGeneration::OnGeneratePrime) + ON_EN_UPDATE(IDC_EDIT_RSA_KEY_PUBLIC, &CDlgDemoRSAKeyGeneration::OnUpdateParameter) + ON_BN_CLICKED(IDOK, &CDlgDemoRSAKeyGeneration::OnOK) + ON_EN_UPDATE(IDC_EDIT_PRIME_P, &CDlgDemoRSAKeyGeneration::OnUpdateParameter) + ON_EN_UPDATE(IDC_EDIT_PRIME_Q, &CDlgDemoRSAKeyGeneration::OnUpdateParameter) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -241,7 +241,8 @@ void CDlgDemoRSAKeyGeneration::OnOK() } if( (m_sPrime_p != m_sPrime_p_OLD) || (m_sPrime_q != m_sPrime_q_OLD) || (m_sKeyPublic != m_sKeyPublic_OLD) ) { - m_Cert->SetName(static_cast(""), static_cast(""), static_cast("")); + CString emptyName, emptyFirstName, emptyKeyId; + m_Cert->SetName(emptyName, emptyFirstName, emptyKeyId); m_Cert->SetTime(0); m_Cert->SetPIN(static_cast("")); CDialog::OnOK(); diff --git a/CrypTool/DlgDiffieHellmanCreateSharedKey.cpp b/CrypTool/DlgDiffieHellmanCreateSharedKey.cpp index 7ebfb7556..1c46f0e86 100644 --- a/CrypTool/DlgDiffieHellmanCreateSharedKey.cpp +++ b/CrypTool/DlgDiffieHellmanCreateSharedKey.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanCreateSharedKey.h" #ifdef _DEBUG diff --git a/CrypTool/DlgDiffieHellmanExchangeSharedKeys.cpp b/CrypTool/DlgDiffieHellmanExchangeSharedKeys.cpp index b25598a94..9b3f00055 100644 --- a/CrypTool/DlgDiffieHellmanExchangeSharedKeys.cpp +++ b/CrypTool/DlgDiffieHellmanExchangeSharedKeys.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanExchangeSharedKeys.h" #ifdef _DEBUG diff --git a/CrypTool/DlgDiffieHellmanGenerateFinalKey.cpp b/CrypTool/DlgDiffieHellmanGenerateFinalKey.cpp index 2034dabab..7b17bf7ee 100644 --- a/CrypTool/DlgDiffieHellmanGenerateFinalKey.cpp +++ b/CrypTool/DlgDiffieHellmanGenerateFinalKey.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanGenerateFinalKey.h" #ifdef _DEBUG diff --git a/CrypTool/DlgDiffieHellmanIntro.cpp b/CrypTool/DlgDiffieHellmanIntro.cpp index e8f4ba169..47158bbc4 100644 --- a/CrypTool/DlgDiffieHellmanIntro.cpp +++ b/CrypTool/DlgDiffieHellmanIntro.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanIntro.h" #ifdef _DEBUG diff --git a/CrypTool/DlgDiffieHellmanKeyInformation.cpp b/CrypTool/DlgDiffieHellmanKeyInformation.cpp index ed21bc9f8..af6363988 100644 --- a/CrypTool/DlgDiffieHellmanKeyInformation.cpp +++ b/CrypTool/DlgDiffieHellmanKeyInformation.cpp @@ -71,8 +71,9 @@ CDlgDiffieHellmanKeyInformation::CDlgDiffieHellmanKeyInformation(std::string ake // Schlüssellängen berechnen // Die Funktion ceil() rundet die Werte auf einen "glatten" Wert, zumal Bitlängen der Form x.xxx // in der Realität nicht existieren können. - this->m_BitLengthAlice = ceil(BitLength((CString)akey.c_str(),10)); - this->m_BitLengthBob = ceil(BitLength((CString)bkey.c_str(),10)); + CString strAKey = akey.c_str(), strBKey = bkey.c_str(); + this->m_BitLengthAlice = ceil(BitLength(strAKey,10)); + this->m_BitLengthBob = ceil(BitLength(strBKey,10)); // Für a=1 oder b=1 gibt die Funktion BitLength() das falsche Ergebnis NULL zurück! if(a == 1) this->m_BitLengthAlice = 1; @@ -99,7 +100,7 @@ void CDlgDiffieHellmanKeyInformation::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgDiffieHellmanKeyInformation, CDialog) //{{AFX_MSG_MAP(CDlgDiffieHellmanKeyInformation) - ON_BN_CLICKED(IDC_SHOWLOGTEXT, OnShowlogtext) + ON_BN_CLICKED(IDC_SHOWLOGTEXT, &CDlgDiffieHellmanKeyInformation::OnShowlogtext) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgDiffieHellmanPublicParameters.cpp b/CrypTool/DlgDiffieHellmanPublicParameters.cpp index 999ea6268..078ae9a44 100644 --- a/CrypTool/DlgDiffieHellmanPublicParameters.cpp +++ b/CrypTool/DlgDiffieHellmanPublicParameters.cpp @@ -25,7 +25,7 @@ #include "NTL/ZZ.h" #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanPublicParameters.h" #include "DlgGenerateSavePrime.h" #include @@ -84,8 +84,8 @@ void CDlgDiffieHellmanPublicParameters::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgDiffieHellmanPublicParameters, CDialog) //{{AFX_MSG_MAP(CDlgDiffieHellmanPublicParameters) - ON_BN_CLICKED(IDC_GENERATE_PRIME, OnGeneratePrime) - ON_BN_CLICKED(IDC_GENERATE_GENERATOR, OnGenerateGenerator) + ON_BN_CLICKED(IDC_GENERATE_PRIME, &CDlgDiffieHellmanPublicParameters::OnGeneratePrime) + ON_BN_CLICKED(IDC_GENERATE_GENERATOR, &CDlgDiffieHellmanPublicParameters::OnGenerateGenerator) //}}AFX_MSG_MAP ON_EN_CHANGE(IDC_PRIME, &CDlgDiffieHellmanPublicParameters::OnEnChangePrime) END_MESSAGE_MAP() diff --git a/CrypTool/DlgDiffieHellmanSecretInput.cpp b/CrypTool/DlgDiffieHellmanSecretInput.cpp index 96c91987d..72704bb9d 100644 --- a/CrypTool/DlgDiffieHellmanSecretInput.cpp +++ b/CrypTool/DlgDiffieHellmanSecretInput.cpp @@ -22,9 +22,9 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" +#include "DlgDiffieHellmanSecretInput.h" #include "DlgDiffieHellmanSecretInput.h" -#include ".\dlgdiffiehellmansecretinput.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -79,9 +79,9 @@ void CDlgDiffieHellmanSecretInput::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgDiffieHellmanSecretInput, CDialog) //{{AFX_MSG_MAP(CDlgDiffieHellmanSecretInput) - ON_BN_CLICKED(IDC_GENERATE_SECRET, OnGenerateSecret) + ON_BN_CLICKED(IDC_GENERATE_SECRET, &CDlgDiffieHellmanSecretInput::OnGenerateSecret) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDOK, &CDlgDiffieHellmanSecretInput::OnBnClickedOk) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// diff --git a/CrypTool/DlgDiffieHellmanSetPublicParameters.cpp b/CrypTool/DlgDiffieHellmanSetPublicParameters.cpp index c93c28b4a..7fb42dad4 100644 --- a/CrypTool/DlgDiffieHellmanSetPublicParameters.cpp +++ b/CrypTool/DlgDiffieHellmanSetPublicParameters.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanSetPublicParameters.h" #ifdef _DEBUG diff --git a/CrypTool/DlgDiffieHellmanSetSecrets.cpp b/CrypTool/DlgDiffieHellmanSetSecrets.cpp index c80571023..61f7bcedb 100644 --- a/CrypTool/DlgDiffieHellmanSetSecrets.cpp +++ b/CrypTool/DlgDiffieHellmanSetSecrets.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanSetSecrets.h" #ifdef _DEBUG diff --git a/CrypTool/DlgDiffieHellmanVisualization.cpp b/CrypTool/DlgDiffieHellmanVisualization.cpp index a20306150..253fd8589 100644 --- a/CrypTool/DlgDiffieHellmanVisualization.cpp +++ b/CrypTool/DlgDiffieHellmanVisualization.cpp @@ -21,7 +21,7 @@ // DlgDiffieHellmanVisualization.cpp #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgDiffieHellmanVisualization.h" #include "DlgDiffieHellmanPublicParameters.h" @@ -111,20 +111,20 @@ void CDlgDiffieHellmanVisualization::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgDiffieHellmanVisualization, CDialog) //{{AFX_MSG_MAP(CDlgDiffieHellmanVisualization) - ON_BN_CLICKED(IDC_SETPUBLICPARAMETERS, OnSetPublicParameters) - ON_BN_CLICKED(IDC_SETSECRETS, OnSetsecrets) - ON_BN_CLICKED(IDC_CREATESHAREDKEY, OnCreatesharedkey) - ON_BN_CLICKED(IDC_EXCHANGESHAREDKEYS, OnExchangesharedkeys) - ON_BN_CLICKED(IDC_GENERATEFINALKEY, OnGeneratefinalkey) - ON_BN_CLICKED(IDC_BUTTONALICE1, OnButtonalice1) - ON_BN_CLICKED(IDC_BUTTONBOB1, OnButtonbob1) - ON_BN_CLICKED(IDC_BUTTONALICE2, OnButtonalice2) - ON_BN_CLICKED(IDC_BUTTONBOB2, OnButtonbob2) - ON_BN_CLICKED(IDC_BUTTONALICE3, OnButtonalice3) - ON_BN_CLICKED(IDC_BUTTONBOB3, OnButtonbob3) - ON_BN_CLICKED(IDC_CHECK_DISABLEHELP, OnCheckDisablehelp) - ON_BN_CLICKED(IDC_CHECK_DISABLEINTRODUCTION, OnCheckDisableIntroDialog) - ON_BN_CLICKED(IDC_KEY, OnKey) + ON_BN_CLICKED(IDC_SETPUBLICPARAMETERS, &CDlgDiffieHellmanVisualization::OnSetPublicParameters) + ON_BN_CLICKED(IDC_SETSECRETS, &CDlgDiffieHellmanVisualization::OnSetsecrets) + ON_BN_CLICKED(IDC_CREATESHAREDKEY, &CDlgDiffieHellmanVisualization::OnCreatesharedkey) + ON_BN_CLICKED(IDC_EXCHANGESHAREDKEYS, &CDlgDiffieHellmanVisualization::OnExchangesharedkeys) + ON_BN_CLICKED(IDC_GENERATEFINALKEY, &CDlgDiffieHellmanVisualization::OnGeneratefinalkey) + ON_BN_CLICKED(IDC_BUTTONALICE1, &CDlgDiffieHellmanVisualization::OnButtonalice1) + ON_BN_CLICKED(IDC_BUTTONBOB1, &CDlgDiffieHellmanVisualization::OnButtonbob1) + ON_BN_CLICKED(IDC_BUTTONALICE2, &CDlgDiffieHellmanVisualization::OnButtonalice2) + ON_BN_CLICKED(IDC_BUTTONBOB2, &CDlgDiffieHellmanVisualization::OnButtonbob2) + ON_BN_CLICKED(IDC_BUTTONALICE3, &CDlgDiffieHellmanVisualization::OnButtonalice3) + ON_BN_CLICKED(IDC_BUTTONBOB3, &CDlgDiffieHellmanVisualization::OnButtonbob3) + ON_BN_CLICKED(IDC_CHECK_DISABLEHELP, &CDlgDiffieHellmanVisualization::OnCheckDisablehelp) + ON_BN_CLICKED(IDC_CHECK_DISABLEINTRODUCTION, &CDlgDiffieHellmanVisualization::OnCheckDisableIntroDialog) + ON_BN_CLICKED(IDC_KEY, &CDlgDiffieHellmanVisualization::OnKey) ON_WM_PAINT() ON_WM_CTLCOLOR() //}}AFX_MSG_MAP diff --git a/CrypTool/DlgECCDecReceiver.cpp b/CrypTool/DlgECCDecReceiver.cpp index dd091da4f..37215d07e 100644 --- a/CrypTool/DlgECCDecReceiver.cpp +++ b/CrypTool/DlgECCDecReceiver.cpp @@ -74,10 +74,10 @@ void CDlgECCDecReceiver::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgECCDecReceiver, CDialog) //{{AFX_MSG_MAP(CDlgECCDecReceiver) - ON_NOTIFY(NM_CLICK, IDC_LIST_KEYS, OnClickListKeys) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST_KEYS, OnItemclickListKeys) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_KEYS, OnColumnclickListKeys) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_KEYS, OnKeydownListKeys) + ON_NOTIFY(NM_CLICK, IDC_LIST_KEYS, &CDlgECCDecReceiver::OnClickListKeys) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST_KEYS, &CDlgECCDecReceiver::OnItemclickListKeys) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_KEYS, &CDlgECCDecReceiver::OnColumnclickListKeys) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_KEYS, &CDlgECCDecReceiver::OnKeydownListKeys) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgECCEncReceiver.cpp b/CrypTool/DlgECCEncReceiver.cpp index be1dabde2..45a76b5f7 100644 --- a/CrypTool/DlgECCEncReceiver.cpp +++ b/CrypTool/DlgECCEncReceiver.cpp @@ -76,12 +76,12 @@ void CDlgECCEncReceiver::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgECCEncReceiver, CDialog) //{{AFX_MSG_MAP(CDlgECCEncReceiver) - ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList1) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnclickList1) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST1, OnItemclickList1) + ON_NOTIFY(NM_CLICK, IDC_LIST1, &CDlgECCEncReceiver::OnClickList1) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, &CDlgECCEncReceiver::OnColumnclickList1) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, &CDlgECCEncReceiver::OnKeydownList1) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST1, &CDlgECCEncReceiver::OnItemclickList1) //}}AFX_MSG_MAP - ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnLvnItemchangedList1) + ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CDlgECCEncReceiver::OnLvnItemchangedList1) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// diff --git a/CrypTool/DlgECGeneration.cpp b/CrypTool/DlgECGeneration.cpp index 2d0cbe878..99f95f210 100644 --- a/CrypTool/DlgECGeneration.cpp +++ b/CrypTool/DlgECGeneration.cpp @@ -76,10 +76,10 @@ void CDlgECGeneration::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgECGeneration, CDialog) //{{AFX_MSG_MAP(CDlgECGeneration) /* - ON_BN_CLICKED(IDC_CHECK1, OnCheck1) - ON_BN_CLICKED(IDC_BUTTON_GEN, OnButtonGen) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1) - ON_EN_UPDATE(IDC_EDIT2, OnUpdateEdit2) + ON_BN_CLICKED(IDC_CHECK1, &CDlgECGeneration::OnCheck1) + ON_BN_CLICKED(IDC_BUTTON_GEN, &CDlgECGeneration::OnButtonGen) + ON_EN_UPDATE(IDC_EDIT1, &CDlgECGeneration::OnUpdateEdit1) + ON_EN_UPDATE(IDC_EDIT2, &CDlgECGeneration::OnUpdateEdit2) */ //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgECSignatureStepByStep.cpp b/CrypTool/DlgECSignatureStepByStep.cpp index 3aea81165..d2770a5ec 100644 --- a/CrypTool/DlgECSignatureStepByStep.cpp +++ b/CrypTool/DlgECSignatureStepByStep.cpp @@ -102,7 +102,7 @@ void CDlgECSignatureStepByStep::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgECSignatureStepByStep, CDialog) //{{AFX_MSG_MAP(CDlgECSignatureStepByStep) - ON_BN_CLICKED(IDC_BUTTON_CONTINUE, OnButtonContinue) + ON_BN_CLICKED(IDC_BUTTON_CONTINUE, &CDlgECSignatureStepByStep::OnButtonContinue) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -323,7 +323,7 @@ int CDlgECSignatureStepByStep::UpdateDataDisplay() return -1; } LoadString(AfxGetInstanceHandle(),IDS_STRING_DOMAIN_PARAMETER_TO_USE,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_DataDisplay += (CString) pc_str1 + nl + nl; m_DataDisplay += ( sp2 + ((CString)"a = ") + DomParamAcString.a + nl ); m_DataDisplay += ( sp2 + ((CString)"b = ") + DomParamAcString.b + nl ); @@ -339,7 +339,7 @@ int CDlgECSignatureStepByStep::UpdateDataDisplay() // Signaturverfahren und Hashfunktion LoadString(AfxGetInstanceHandle(),IDS_STRING_SEL_SIGNATURE_HASH_FUNCTION,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, SigAlg, HashAlg); + sprintf(pc_str1, pc_str, (LPCTSTR)SigAlg, (LPCTSTR)HashAlg); m_DataDisplay += ( ((CString)pc_str1) + nl + nl); // Länge der zu signierenden Nachricht in Byte @@ -356,7 +356,7 @@ int CDlgECSignatureStepByStep::UpdateDataDisplay() char *fstr; // message Representative f LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_HASHING,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, HashAlg); + sprintf(pc_str1, pc_str, (LPCTSTR)HashAlg); m_DataDisplay += ( ((CString)pc_str1) + nl + nl); err = ln_to_string (MsgRepData.f, &fstr, base); if (err > 0) @@ -388,7 +388,7 @@ int CDlgECSignatureStepByStep::UpdateDataDisplay() { // one-time key pair LoadString(AfxGetInstanceHandle(),IDS_STRING_CREATE_RANDOM_ASYMKEY,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_DataDisplay += ( ((CString)pc_str1) + nl + nl); m_DataDisplay += ( sp2 + ((CString)"u = ") + DsaSignDataStrings.u + nl); m_DataDisplay += ( sp2 + ((CString)"Vx = ") + DsaSignDataStrings.Vx + nl); @@ -450,7 +450,7 @@ int CDlgECSignatureStepByStep::UpdateDataDisplay() { // one-time key pair LoadString(AfxGetInstanceHandle(),IDS_STRING_CREATE_RANDOM_ASYMKEY,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_DataDisplay += ( ((CString)pc_str1) + nl + nl); m_DataDisplay += ( sp2 + ((CString)"u = ") + NrSignDataStrings.u + nl); diff --git a/CrypTool/DlgEntropyInfo.cpp b/CrypTool/DlgEntropyInfo.cpp index 9c4609fff..0e09bdb51 100644 --- a/CrypTool/DlgEntropyInfo.cpp +++ b/CrypTool/DlgEntropyInfo.cpp @@ -71,7 +71,7 @@ BOOL CDlgEntropyInfo::OnInitDialog() CDialog::OnInitDialog(); CString title; - title.Format(IDS_ENTROPY_TITLE,m_oldtitle); + title.Format(IDS_ENTROPY_TITLE,(LPCTSTR)m_oldtitle); SetWindowText((LPCTSTR)title); LOGFONT logFont; diff --git a/CrypTool/DlgExtractSignature.cpp b/CrypTool/DlgExtractSignature.cpp index 8e018aff7..9f7c84d76 100644 --- a/CrypTool/DlgExtractSignature.cpp +++ b/CrypTool/DlgExtractSignature.cpp @@ -114,10 +114,10 @@ void CDlgExtractSignature::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgExtractSignature, CDialog) //{{AFX_MSG_MAP(CDlgExtractSignature) - ON_BN_CLICKED(IDC_RADIO1, OnRadioOctets) - ON_BN_CLICKED(IDC_RADIO2, OnRadioOktal) - ON_BN_CLICKED(IDC_RADIO3, OnRadioDezimal) - ON_BN_CLICKED(IDC_RADIO4, OnRadioHexadezimal) + ON_BN_CLICKED(IDC_RADIO1, &CDlgExtractSignature::OnRadioOctets) + ON_BN_CLICKED(IDC_RADIO2, &CDlgExtractSignature::OnRadioOktal) + ON_BN_CLICKED(IDC_RADIO3, &CDlgExtractSignature::OnRadioDezimal) + ON_BN_CLICKED(IDC_RADIO4, &CDlgExtractSignature::OnRadioHexadezimal) //}}AFX_MSG_MAP ON_BN_CLICKED(ID_EXTRACT_SIGNATURE_VERIFY, &CDlgExtractSignature::OnBnClickedExtractSignatureVerify) END_MESSAGE_MAP() @@ -238,7 +238,7 @@ BOOL CDlgExtractSignature::OnInitDialog() // Infos über Schlüssel LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_DATE,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1,((CString)keyType)+kInfo,((CString)creattime)); + sprintf(pc_str, pc_str1,(LPCTSTR)(((CString)keyType)+kInfo),(LPCTSTR)((CString)creattime)); m_KeyInfo = (CString) pc_str; // Benutzter Schlüssel: } else @@ -269,7 +269,7 @@ BOOL CDlgExtractSignature::OnInitDialog() // Benutzter Signaturalgorithmus LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_HASH_FUNCTION,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1, SigAlg, HashAlg); + sprintf(pc_str, pc_str1, (LPCTSTR)SigAlg, (LPCTSTR)HashAlg); m_SigHashAlg = (CString) pc_str; UpdateData(FALSE); @@ -302,7 +302,7 @@ BOOL CDlgExtractSignature::OnInitDialog() char buffer[30]; _itoa( message.noctets, buffer, 10 ); LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_MESSAGE_LENGTH,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1,((CString)buffer)); + sprintf(pc_str, pc_str1,(LPCTSTR)((CString)buffer)); m_MessageLength = (CString) pc_str; UpdateData(FALSE); @@ -317,7 +317,7 @@ BOOL CDlgExtractSignature::OnInitDialog() char buffer[30]; _itoa( signlength, buffer, 10 ); LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_LENGTH,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1,((CString)buffer)); + sprintf(pc_str, pc_str1,(LPCTSTR)((CString)buffer)); m_SignatureLength = (CString) pc_str; UpdateData(FALSE); @@ -348,7 +348,7 @@ BOOL CDlgExtractSignature::OnInitDialog() char buffer[30]; _itoa( Signatur.signature.nbits, buffer, 10 ); LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_LENGTH,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1,((CString)buffer)); + sprintf(pc_str, pc_str1,(LPCTSTR)((CString)buffer)); m_SignatureLength = (CString) pc_str; UpdateData(FALSE); } @@ -522,7 +522,7 @@ int CDlgExtractSignature::UpdateSigEditBox() char buffer[30]; _itoa( Signatur.signature.nbits, buffer, 10 ); LoadString(AfxGetInstanceHandle(),IDS_STRING_SIGNATURE_LENGTH,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1,((CString)buffer)); + sprintf(pc_str, pc_str1,(LPCTSTR)((CString)buffer)); m_SignatureLength = (CString) pc_str; UpdateData(FALSE); free(sigdata); diff --git a/CrypTool/DlgFactorisationDemo.cpp b/CrypTool/DlgFactorisationDemo.cpp index c462d7580..28a5d44ac 100644 --- a/CrypTool/DlgFactorisationDemo.cpp +++ b/CrypTool/DlgFactorisationDemo.cpp @@ -99,12 +99,12 @@ void CDlgFactorisationDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgFactorisationDemo, CDialog) //{{AFX_MSG_MAP(CDlgFactorisationDemo) - ON_BN_CLICKED(IDC_BUTTON_CANCEL, OnButtonEnd) - ON_BN_CLICKED(IDC_BUTTON_Faktorisieren, OnButtonFactorisation) - ON_BN_CLICKED(IDC_BUTTON_VOLLSTAENDIG_FAKTORISATION, OnButtonVollstaendigFaktorisation) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEditEingabe) - ON_BN_CLICKED(IDC_BUTTON1, OnShowFactorisationDetails) - ON_BN_CLICKED(IDC_BUTTON_LOAD_NUMBER, OnBnClickedLoadNumber) + ON_BN_CLICKED(IDC_BUTTON_CANCEL, &CDlgFactorisationDemo::OnButtonEnd) + ON_BN_CLICKED(IDC_BUTTON_Faktorisieren, &CDlgFactorisationDemo::OnButtonFactorisation) + ON_BN_CLICKED(IDC_BUTTON_VOLLSTAENDIG_FAKTORISATION, &CDlgFactorisationDemo::OnButtonVollstaendigFaktorisation) + ON_EN_UPDATE(IDC_EDIT1, &CDlgFactorisationDemo::OnUpdateEditEingabe) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgFactorisationDemo::OnShowFactorisationDetails) + ON_BN_CLICKED(IDC_BUTTON_LOAD_NUMBER, &CDlgFactorisationDemo::OnBnClickedLoadNumber) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -433,7 +433,7 @@ void CDlgFactorisationDemo::OnButtonFactorisation() int nfactors = 0; for (NumFactor *factor = factorList; factor ; factor = factor->next) nfactors += factor->exponent; - m_benoetigte_zeit_global.Format(IDS_FACTORS_FOUND, nfactors, timeStr1); + m_benoetigte_zeit_global.Format(IDS_FACTORS_FOUND, nfactors, (LPCTSTR)timeStr1); if ( zeit_condtruct2.day >= 1) { LoadString(AfxGetInstanceHandle(),IDS_STRING_FMT_DAYS,pc_str,STR_LAENGE_STRING_TABLE); diff --git a/CrypTool/DlgFactorisationList.cpp b/CrypTool/DlgFactorisationList.cpp index 206669e7d..dcdbd7205 100644 --- a/CrypTool/DlgFactorisationList.cpp +++ b/CrypTool/DlgFactorisationList.cpp @@ -72,7 +72,7 @@ void CDlgFactorisationList::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgFactorisationList, CDialog) //{{AFX_MSG_MAP(CDlgFactorisationList) - ON_NOTIFY(NM_DBLCLK, IDC_LIST1, OnDblclkSelect) + ON_NOTIFY(NM_DBLCLK, IDC_LIST1, &CDlgFactorisationList::OnDblclkSelect) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -125,8 +125,8 @@ void CDlgFactorisationList::Init_ListBox() UpdateData(FALSE); } -void CDlgFactorisationList::InsertFactDetail(CString &Num, CString &Factor1, - CString &Factor2, CString &Method , CString &Time, +void CDlgFactorisationList::InsertFactDetail(const CString &Num, const CString &Factor1, + const CString &Factor2, const CString &Method , const CString &Time, int PrimeMask, int BitlengthF1, int BitlengthF2) { struct DFItem *Last = new (struct DFItem); diff --git a/CrypTool/DlgFactorisationList.h b/CrypTool/DlgFactorisationList.h index c44b229c1..17489b39d 100644 --- a/CrypTool/DlgFactorisationList.h +++ b/CrypTool/DlgFactorisationList.h @@ -56,8 +56,8 @@ class CDlgFactorisationList : public CDialog char outfile[CRYPTOOL_PATH_LENGTH]; bool b_SaveFactorList; void ClearFactDetail(); - void InsertFactDetail( CString & Num, CString &Factor1, - CString &Factor2, CString &Method, CString &Time, int PrimeMask, + void InsertFactDetail( const CString & Num, const CString &Factor1, + const CString &Factor2, const CString &Method, const CString &Time, int PrimeMask, int BitlengthF1, int BitlengthF2); void Init_ListBox(); CDlgFactorisationList(CWnd* pParent = NULL); // Standardkonstruktor diff --git a/CrypTool/DlgFileProperties.cpp b/CrypTool/DlgFileProperties.cpp index 64b37d8bc..d074da7ea 100644 --- a/CrypTool/DlgFileProperties.cpp +++ b/CrypTool/DlgFileProperties.cpp @@ -26,7 +26,7 @@ #include "DlgFileProperties.h" #include "DlgShowKey.h" #include "CrypToolTools.h" -#include "keyHillBase.h" +#include "KeyHillBase.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -70,7 +70,7 @@ void CDlgFileProperties::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgFileProperties, CDialog) //{{AFX_MSG_MAP(CDlgFileProperties) - ON_BN_CLICKED(IDC_BUTTON1, OnShowKey) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgFileProperties::OnShowKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgFindAndReplace.cpp b/CrypTool/DlgFindAndReplace.cpp index 2f8835b4e..f668f4e80 100644 --- a/CrypTool/DlgFindAndReplace.cpp +++ b/CrypTool/DlgFindAndReplace.cpp @@ -27,7 +27,7 @@ #include "ScintillaDoc.h" #include "ScintillaView.h" #include "HexEditCtrlView.h" -#include ".\dlgfindandreplace.h" +#include "DlgFindAndReplace.h" // this function returns true if the input string (which is the output string also) // could be converted from hex to ascii; in case the hex string contains a zero byte (00), @@ -117,11 +117,11 @@ void CDlgFindAndReplace::DoDataExchange(CDataExchange* pDX) } BEGIN_MESSAGE_MAP(CDlgFindAndReplace, CDialog) - ON_BN_CLICKED(IDC_BUTTON_FIND, OnBnClickedButtonFind) - ON_BN_CLICKED(IDC_BUTTON_REPLACE, OnBnClickedButtonReplace) - ON_BN_CLICKED(IDC_BUTTON_REPLACE_ALL, OnBnClickedButtonReplaceAll) - ON_BN_CLICKED(IDC_RADIO_TEXT_MODE, OnBnClickedRadioTextMode) - ON_BN_CLICKED(IDC_RADIO_HEX_MODE, OnBnClickedRadioHexMode) + ON_BN_CLICKED(IDC_BUTTON_FIND, &CDlgFindAndReplace::OnBnClickedButtonFind) + ON_BN_CLICKED(IDC_BUTTON_REPLACE, &CDlgFindAndReplace::OnBnClickedButtonReplace) + ON_BN_CLICKED(IDC_BUTTON_REPLACE_ALL, &CDlgFindAndReplace::OnBnClickedButtonReplaceAll) + ON_BN_CLICKED(IDC_RADIO_TEXT_MODE, &CDlgFindAndReplace::OnBnClickedRadioTextMode) + ON_BN_CLICKED(IDC_RADIO_HEX_MODE, &CDlgFindAndReplace::OnBnClickedRadioHexMode) END_MESSAGE_MAP() // CDlgFindAndReplace message handlers diff --git a/CrypTool/DlgFindText.cpp b/CrypTool/DlgFindText.cpp index d14d1e2fc..7d71d8584 100644 --- a/CrypTool/DlgFindText.cpp +++ b/CrypTool/DlgFindText.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "DlgFindText.h" #ifdef _DEBUG diff --git a/CrypTool/DlgFormatTextDocument.cpp b/CrypTool/DlgFormatTextDocument.cpp index 87b416665..4e4ae699b 100644 --- a/CrypTool/DlgFormatTextDocument.cpp +++ b/CrypTool/DlgFormatTextDocument.cpp @@ -24,7 +24,7 @@ #include #include -#include ".\dlgformattextdocument.h" +#include "DlgFormatTextDocument.h" IMPLEMENT_DYNAMIC(CDlgFormatTextDocument, CDialog) CDlgFormatTextDocument::CDlgFormatTextDocument(CWnd* pParent /*=NULL*/) @@ -118,11 +118,11 @@ CString CDlgFormatTextDocument::format(CString fileName) } BEGIN_MESSAGE_MAP(CDlgFormatTextDocument, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDC_CHECK_REMOVE_NON_ALPHABET_CHARACTERS, OnBnClickedCheckRemoveNonAlphabetCharacters) - ON_BN_CLICKED(IDC_CHECK_CONVERT_TO_UPPERCASE, OnBnClickedCheckConvertToUppercase) - ON_BN_CLICKED(IDC_CHECK_CONVERT_TO_LOWERCASE, OnBnClickedCheckConvertToLowercase) - ON_BN_CLICKED(IDC_CHECK_DIVIDE_IN_BLOCKS, OnBnClickedCheckDivideInBlocks) + ON_BN_CLICKED(IDOK, &CDlgFormatTextDocument::OnBnClickedOk) + ON_BN_CLICKED(IDC_CHECK_REMOVE_NON_ALPHABET_CHARACTERS, &CDlgFormatTextDocument::OnBnClickedCheckRemoveNonAlphabetCharacters) + ON_BN_CLICKED(IDC_CHECK_CONVERT_TO_UPPERCASE, &CDlgFormatTextDocument::OnBnClickedCheckConvertToUppercase) + ON_BN_CLICKED(IDC_CHECK_CONVERT_TO_LOWERCASE, &CDlgFormatTextDocument::OnBnClickedCheckConvertToLowercase) + ON_BN_CLICKED(IDC_CHECK_DIVIDE_IN_BLOCKS, &CDlgFormatTextDocument::OnBnClickedCheckDivideInBlocks) ON_BN_CLICKED(ID_TEXTOPTIONS, &CDlgFormatTextDocument::OnBnClickedTextoptions) END_MESSAGE_MAP() diff --git a/CrypTool/DlgHMAC.cpp b/CrypTool/DlgHMAC.cpp index 33399ad40..b6fd0fbd7 100644 --- a/CrypTool/DlgHMAC.cpp +++ b/CrypTool/DlgHMAC.cpp @@ -78,10 +78,10 @@ void CDlgHMAC::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgHMAC, CDialog) //{{AFX_MSG_MAP(CDlgHMAC) - ON_EN_CHANGE(IDC_SHOW_TEXT, OnEditText) - ON_EN_CHANGE(IDC_EDIT_KEY, OnEditKey) - ON_EN_CHANGE(IDC_EDIT_ORIGINAL_MESSAGE, OnEditOriginalMessage) - ON_EN_CHANGE(IDC_EDIT_KEY2, OnEditSecondKey) + ON_EN_CHANGE(IDC_SHOW_TEXT, &CDlgHMAC::OnEditText) + ON_EN_CHANGE(IDC_EDIT_KEY, &CDlgHMAC::OnEditKey) + ON_EN_CHANGE(IDC_EDIT_ORIGINAL_MESSAGE, &CDlgHMAC::OnEditOriginalMessage) + ON_EN_CHANGE(IDC_EDIT_KEY2, &CDlgHMAC::OnEditSecondKey) //}}AFX_MSG_MAP ON_CBN_SELENDOK(IDC_COMBO_SELECT_HASH_FUNCTION, &CDlgHMAC::OnCbnSelendokComboSelectHashFunction) ON_CBN_SELENDOK(IDC_COMBO_SELECT_HMAC_ALGORITHM, &CDlgHMAC::OnCbnSelendokComboSelectHmacAlgorithm) diff --git a/CrypTool/DlgHashDemo.cpp b/CrypTool/DlgHashDemo.cpp index 590eb72df..92a3680b4 100644 --- a/CrypTool/DlgHashDemo.cpp +++ b/CrypTool/DlgHashDemo.cpp @@ -74,11 +74,11 @@ void CDlgHashDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgHashDemo, CDialog) //{{AFX_MSG_MAP(CDlgHashDemo) - ON_BN_CLICKED(IDC_RADIO_BIN, OnRadioBin) - ON_BN_CLICKED(IDC_RADIO_DEC, OnRadioDec) - ON_BN_CLICKED(IDC_RADIO_HEX, OnRadioHex) - ON_EN_CHANGE(IDC_EDIT_TEXT, OnChangeEditText) - ON_CBN_SELENDOK(IDC_COMBO_SELECT_HASH_FUNCTION, OnSelendokComboSelectHashFunction) + ON_BN_CLICKED(IDC_RADIO_BIN, &CDlgHashDemo::OnRadioBin) + ON_BN_CLICKED(IDC_RADIO_DEC, &CDlgHashDemo::OnRadioDec) + ON_BN_CLICKED(IDC_RADIO_HEX, &CDlgHashDemo::OnRadioHex) + ON_EN_CHANGE(IDC_EDIT_TEXT, &CDlgHashDemo::OnChangeEditText) + ON_CBN_SELENDOK(IDC_COMBO_SELECT_HASH_FUNCTION, &CDlgHashDemo::OnSelendokComboSelectHashFunction) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -290,7 +290,7 @@ void CDlgHashDemo::SetHashDiff(OctetString &hash1, OctetString &hash2) } -static DWORD CALLBACK EditStreamCallBack(DWORD dwCookie, LPBYTE pbBuff, LONG cb, +static DWORD CALLBACK EditStreamCallBack(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) { CString *pstr = (CString *)dwCookie; @@ -393,7 +393,7 @@ void CDlgHashDemo::SetRed() b += "\n\\par "; CString ratio; CString percentage = createStringNumberWithDigitGrouping((100.0*one)/(one+zero)); - ratio.Format(IDS_HASH_DEMO_PERCENT, percentage, one, (one+zero)); + ratio.Format(IDS_HASH_DEMO_PERCENT, (LPCTSTR)percentage, one, (one+zero)); b += ratio; CString sequence; @@ -409,7 +409,7 @@ void CDlgHashDemo::SetRed() // The rtfString contains the word Bold in bold font. CString rtfString = rtfPrefix + b + rtfPostfix; - EDITSTREAM es = {(DWORD)&rtfString, 0, EditStreamCallBack}; + EDITSTREAM es = {(DWORD_PTR)&rtfString, 0, EditStreamCallBack}; // richEd is the rich edit control m_ctrlHashDiff.StreamIn(SF_RTF | SFF_SELECTION, es); diff --git a/CrypTool/DlgHillAnalysis.cpp b/CrypTool/DlgHillAnalysis.cpp index 25003b4f7..15bb95f58 100644 --- a/CrypTool/DlgHillAnalysis.cpp +++ b/CrypTool/DlgHillAnalysis.cpp @@ -79,8 +79,8 @@ void CDlgHillAnaylsis::DoDataExchange(CDataExchange* pDX) } BEGIN_MESSAGE_MAP(CDlgHillAnaylsis, CDialog) - ON_CBN_SELCHANGE(IDC_DIM_VON, OnSelchangeDimVon) - ON_CBN_SELCHANGE(IDC_DIM_BIS, OnSelchangeDimBis) + ON_CBN_SELCHANGE(IDC_DIM_VON, &CDlgHillAnaylsis::OnSelchangeDimVon) + ON_CBN_SELCHANGE(IDC_DIM_BIS, &CDlgHillAnaylsis::OnSelchangeDimBis) ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CDlgHillAnaylsis::OnTcnSelchangeTab1) ON_BN_CLICKED(IDOK, &CDlgHillAnaylsis::OnBnClickedSearchKey) ON_BN_CLICKED(IDCANCEL, &CDlgHillAnaylsis::OnBnClickedCancel) diff --git a/CrypTool/DlgHillOptions.cpp b/CrypTool/DlgHillOptions.cpp index 351653d6f..7aacfbc54 100644 --- a/CrypTool/DlgHillOptions.cpp +++ b/CrypTool/DlgHillOptions.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgHillOptions.h" -#include ".\dlghilloptions.h" +#include "DlgHillOptions.h" #include "CrypToolTools.h" // DlgHillOptions dialog @@ -35,10 +35,10 @@ void DlgHillOptions::DoDataExchange(CDataExchange* pDX) } BEGIN_MESSAGE_MAP(DlgHillOptions, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDC_RADIO1, OnBnClickedRadio1) - ON_BN_CLICKED(IDC_RADIO2, OnBnClickedRadio2) - ON_EN_CHANGE (IDC_EDIT2, OnEnChangeEdit2) + ON_BN_CLICKED(IDOK, &DlgHillOptions::OnBnClickedOk) + ON_BN_CLICKED(IDC_RADIO1, &DlgHillOptions::OnBnClickedRadio1) + ON_BN_CLICKED(IDC_RADIO2, &DlgHillOptions::OnBnClickedRadio2) + ON_EN_CHANGE (IDC_EDIT2, &DlgHillOptions::OnEnChangeEdit2) ON_BN_CLICKED(IDC_RADIO3, &DlgHillOptions::OnBnClickedOffset0) ON_BN_CLICKED(IDC_RADIO4, &DlgHillOptions::OnBnClickedOffset1) END_MESSAGE_MAP() @@ -89,8 +89,8 @@ void DlgHillOptions::writeRegistry() { if ( CT_OPEN_REGISTRY_SETTINGS( KEY_WRITE, IDS_REGISTRY_SETTINGS, "Hill" ) == ERROR_SUCCESS ) { - CT_WRITE_REGISTRY(unsigned long(m_offset), "OrdChrOffset"); - CT_WRITE_REGISTRY(unsigned long(useFirstCharFromAlph), "PaddingDefaultChr"); + CT_WRITE_REGISTRY((unsigned long)(m_offset), "OrdChrOffset"); + CT_WRITE_REGISTRY((unsigned long)(useFirstCharFromAlph), "PaddingDefaultChr"); CT_WRITE_REGISTRY(m_ownCharForPadding,"PaddingOwnChr"); CT_CLOSE_REGISTRY(); } diff --git a/CrypTool/DlgHomophonicSubstitution.cpp b/CrypTool/DlgHomophonicSubstitution.cpp index d282653b7..e302b0e2f 100644 --- a/CrypTool/DlgHomophonicSubstitution.cpp +++ b/CrypTool/DlgHomophonicSubstitution.cpp @@ -79,16 +79,16 @@ void CDlgHomophonicSubstitution::DoDataExchange(CDataExchange *pDX) { } BEGIN_MESSAGE_MAP(CDlgHomophonicSubstitution, CDialog) - ON_BN_CLICKED(IDC_BUTTON_UPDATE_COUNT_HOMOPHONES, clickedButtonUpdateCountHomophones) - ON_BN_CLICKED(IDC_BUTTON_COPY_KEY_TO_KEYSTORE, clickedButtonCopyKeyToKeystore) - ON_BN_CLICKED(IDC_BUTTON_COPY_KEY_TO_CLIPBOARD, clickedButtonCopyKeyToClipboard) - ON_BN_CLICKED(IDC_BUTTON_PASTE_KEY_FROM_KEYSTORE, clickedButtonPasteKeyFromKeystore) - ON_BN_CLICKED(IDC_BUTTON_PASTE_KEY_FROM_CLIPBOARD, clickedButtonPasteKeyFromClipboard) - ON_NOTIFY(NM_DBLCLK, IDC_LIST_HOMOPHONES_KEY_TABLE, doubleClickedListHomophonesKeyTable) - ON_BN_CLICKED(IDC_BUTTON_ENCRYPT, clickedButtonEncrypt) - ON_BN_CLICKED(IDC_BUTTON_DECRYPT, clickedButtonDecrypt) - ON_BN_CLICKED(IDC_BUTTON_GENERATE_KEY, clickedButtonGenerateKey) - ON_BN_CLICKED(IDC_BUTTON_CANCEL, clickedButtonCancel) + ON_BN_CLICKED(IDC_BUTTON_UPDATE_COUNT_HOMOPHONES, &CDlgHomophonicSubstitution::clickedButtonUpdateCountHomophones) + ON_BN_CLICKED(IDC_BUTTON_COPY_KEY_TO_KEYSTORE, &CDlgHomophonicSubstitution::clickedButtonCopyKeyToKeystore) + ON_BN_CLICKED(IDC_BUTTON_COPY_KEY_TO_CLIPBOARD, &CDlgHomophonicSubstitution::clickedButtonCopyKeyToClipboard) + ON_BN_CLICKED(IDC_BUTTON_PASTE_KEY_FROM_KEYSTORE, &CDlgHomophonicSubstitution::clickedButtonPasteKeyFromKeystore) + ON_BN_CLICKED(IDC_BUTTON_PASTE_KEY_FROM_CLIPBOARD, &CDlgHomophonicSubstitution::clickedButtonPasteKeyFromClipboard) + ON_NOTIFY(NM_DBLCLK, IDC_LIST_HOMOPHONES_KEY_TABLE, &CDlgHomophonicSubstitution::doubleClickedListHomophonesKeyTable) + ON_BN_CLICKED(IDC_BUTTON_ENCRYPT, &CDlgHomophonicSubstitution::clickedButtonEncrypt) + ON_BN_CLICKED(IDC_BUTTON_DECRYPT, &CDlgHomophonicSubstitution::clickedButtonDecrypt) + ON_BN_CLICKED(IDC_BUTTON_GENERATE_KEY, &CDlgHomophonicSubstitution::clickedButtonGenerateKey) + ON_BN_CLICKED(IDC_BUTTON_CANCEL, &CDlgHomophonicSubstitution::clickedButtonCancel) END_MESSAGE_MAP() void CDlgHomophonicSubstitution::checkInputFile() { @@ -371,7 +371,7 @@ void CDlgHomophoneSubstitutionKeyEntryDetails::DoDataExchange(CDataExchange *pDX } BEGIN_MESSAGE_MAP(CDlgHomophoneSubstitutionKeyEntryDetails, CDialog) - ON_BN_CLICKED(IDC_BUTTON_CLOSE, clickedButtonClose) + ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CDlgHomophoneSubstitutionKeyEntryDetails::clickedButtonClose) END_MESSAGE_MAP() void CDlgHomophoneSubstitutionKeyEntryDetails::clickedButtonClose() { diff --git a/CrypTool/DlgHybridDecryptionDemo.cpp b/CrypTool/DlgHybridDecryptionDemo.cpp index 87ce99818..f8d9718dc 100644 --- a/CrypTool/DlgHybridDecryptionDemo.cpp +++ b/CrypTool/DlgHybridDecryptionDemo.cpp @@ -25,7 +25,7 @@ #include "CrypToolApp.h" #include #include "FileTools.h" -#include +#include #include "Cryptography.h" #include "CryptDoc.h" #include "AppDocument.h" @@ -89,8 +89,8 @@ void CDlgHybridDecryptionDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgHybridDecryptionDemo, CDialog) //{{AFX_MSG_MAP(CDlgHybridDecryptionDemo) - ON_BN_CLICKED(IDC_BUTTON_CONTINUE, OnButtonContinue) - ON_BN_CLICKED(IDC_SHOW_CERTIFICATE, OnButtonShowCertificate) + ON_BN_CLICKED(IDC_BUTTON_CONTINUE, &CDlgHybridDecryptionDemo::OnButtonContinue) + ON_BN_CLICKED(IDC_SHOW_CERTIFICATE, &CDlgHybridDecryptionDemo::OnButtonShowCertificate) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgHybridEncryptionDemo.cpp b/CrypTool/DlgHybridEncryptionDemo.cpp index 093d405ba..6f9ca770f 100644 --- a/CrypTool/DlgHybridEncryptionDemo.cpp +++ b/CrypTool/DlgHybridEncryptionDemo.cpp @@ -28,7 +28,7 @@ #include "DialogeMessage.h" #include #include "FileTools.h" -#include +#include #include "DlgRSAEncryption.h" #include "DlgKeyHexAnalysis.h" #include "Cryptography.h" @@ -132,17 +132,17 @@ void CDlgHybridEncryptionDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgHybridEncryptionDemo, CDialog) //{{AFX_MSG_MAP(CDlgHybridEncryptionDemo) - ON_BN_CLICKED(IDC_BUTTON1_TXT_EINFUEGEN, OnButtonGetDocument) - ON_BN_CLICKED(IDC_BUTTON_ENC_KEY_ASYM, OnButtonEncKeyAsym) - ON_BN_CLICKED(IDC_BUTTON_ENC_TXT_SYM, OnButtonEncDocumentSym) - ON_BN_CLICKED(IDC_BUTTON_GEN_SYM_KEY, OnButtonGenSymKey) - ON_BN_CLICKED(IDC_BUTTON_GET_ASYM_KEY, OnButtonGetAsymKey) - ON_BN_CLICKED(IDC_BUTTON_SHOW_SYM_KEY, OnButtonShowSymKey) - ON_BN_CLICKED(IDC_BUTTON_SHOW_ASYM_KEY, OnButtonShowAsymKey) - ON_BN_CLICKED(IDC_BUTTON_SHOWTXT, OnButtonShowDocument) - ON_BN_CLICKED(IDC_BUTTON2, OnButtonShowEncDocument) - ON_BN_CLICKED(IDC_BUTTON3, OnButtonShowEncSymKey) - ON_BN_CLICKED(IDC_BUTTON_DATENAUSGABE, OnButtonDatenausgabe) + ON_BN_CLICKED(IDC_BUTTON1_TXT_EINFUEGEN, &CDlgHybridEncryptionDemo::OnButtonGetDocument) + ON_BN_CLICKED(IDC_BUTTON_ENC_KEY_ASYM, &CDlgHybridEncryptionDemo::OnButtonEncKeyAsym) + ON_BN_CLICKED(IDC_BUTTON_ENC_TXT_SYM, &CDlgHybridEncryptionDemo::OnButtonEncDocumentSym) + ON_BN_CLICKED(IDC_BUTTON_GEN_SYM_KEY, &CDlgHybridEncryptionDemo::OnButtonGenSymKey) + ON_BN_CLICKED(IDC_BUTTON_GET_ASYM_KEY, &CDlgHybridEncryptionDemo::OnButtonGetAsymKey) + ON_BN_CLICKED(IDC_BUTTON_SHOW_SYM_KEY, &CDlgHybridEncryptionDemo::OnButtonShowSymKey) + ON_BN_CLICKED(IDC_BUTTON_SHOW_ASYM_KEY, &CDlgHybridEncryptionDemo::OnButtonShowAsymKey) + ON_BN_CLICKED(IDC_BUTTON_SHOWTXT, &CDlgHybridEncryptionDemo::OnButtonShowDocument) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgHybridEncryptionDemo::OnButtonShowEncDocument) + ON_BN_CLICKED(IDC_BUTTON3, &CDlgHybridEncryptionDemo::OnButtonShowEncSymKey) + ON_BN_CLICKED(IDC_BUTTON_DATENAUSGABE, &CDlgHybridEncryptionDemo::OnButtonDatenausgabe) ON_WM_SETCURSOR() ON_WM_PAINT() //}}AFX_MSG_MAP @@ -370,7 +370,7 @@ void CDlgHybridEncryptionDemo::OnButtonEncDocumentSym() LoadString(AfxGetInstanceHandle(),IDS_SCA_KEYWORDPROBLEM,pc_str,STR_LAENGE_STRING_TABLE); char temp[STR_LAENGE_STRING_TABLE+1]; memset(temp, 0, STR_LAENGE_STRING_TABLE+1); - sprintf(temp, pc_str, keyword); + sprintf(temp, pc_str, (LPCTSTR)keyword); if(AfxMessageBox(temp, MB_YESNO) == IDYES) { diff --git a/CrypTool/DlgICGRandomParamater.cpp b/CrypTool/DlgICGRandomParamater.cpp index 5bba6d81c..3e601b5fb 100644 --- a/CrypTool/DlgICGRandomParamater.cpp +++ b/CrypTool/DlgICGRandomParamater.cpp @@ -70,11 +70,11 @@ void CDlgICGRandomParamater::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgICGRandomParamater, CDialog) //{{AFX_MSG_MAP(CDlgICGRandomParamater) - ON_BN_CLICKED(IDC_STATIC_GPA, OnStaticGp_a) - ON_BN_CLICKED(IDC_PRIMBUTTON, OnPrimbutton) - ON_BN_CLICKED(IDC_STATIC_GPC, OnStaticGpc) - ON_BN_CLICKED(IDC_STATIC_GPP, OnStaticGpp) - ON_BN_CLICKED(IDC_STATIC_GPL, OnStaticGpl) + ON_BN_CLICKED(IDC_STATIC_GPA, &CDlgICGRandomParamater::OnStaticGp_a) + ON_BN_CLICKED(IDC_PRIMBUTTON, &CDlgICGRandomParamater::OnPrimbutton) + ON_BN_CLICKED(IDC_STATIC_GPC, &CDlgICGRandomParamater::OnStaticGpc) + ON_BN_CLICKED(IDC_STATIC_GPP, &CDlgICGRandomParamater::OnStaticGpp) + ON_BN_CLICKED(IDC_STATIC_GPL, &CDlgICGRandomParamater::OnStaticGpl) ON_WM_KEYDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -167,7 +167,8 @@ void CDlgICGRandomParamater::OnOK() if ( Modul_N_IsOK && Multiplikator_a_IsOK && Inkrement_b_IsOK) { GeneratePrimes P; - P.SetP(Get_N()); + CString strN = Get_N(); + P.SetP(strN); BOOL test=FALSE; test = P.MillerRabinTest(100); test = P.SolvayStrassenTest(100); diff --git a/CrypTool/DlgKey.cpp b/CrypTool/DlgKey.cpp index 16a14167f..937b70317 100644 --- a/CrypTool/DlgKey.cpp +++ b/CrypTool/DlgKey.cpp @@ -87,11 +87,11 @@ void CDlgKey::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKey, CDialog) //{{AFX_MSG_MAP(CDlgKey) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1) - ON_BN_CLICKED(IDC_BUTTON1, OnDecrypt) - ON_BN_CLICKED(IDOK, OnEncrypt) - ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, OnTextOptions) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteKey) + ON_EN_UPDATE(IDC_EDIT1, &CDlgKey::OnUpdateEdit1) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKey::OnDecrypt) + ON_BN_CLICKED(IDOK, &CDlgKey::OnEncrypt) + ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, &CDlgKey::OnTextOptions) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKey::OnPasteKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyAsym.cpp b/CrypTool/DlgKeyAsym.cpp index 1a2969ea3..058ab53ac 100644 --- a/CrypTool/DlgKeyAsym.cpp +++ b/CrypTool/DlgKeyAsym.cpp @@ -97,18 +97,18 @@ void CDlgKeyAsym::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyAsym, CDialog) //{{AFX_MSG_MAP(CDlgKeyAsym) - ON_BN_CLICKED(IDC_BUTTON1, OnShowPubParamButton) - ON_BN_CLICKED(IDC_BUTTON2, OnShowAllParamButton) - ON_BN_CLICKED(IDC_BUTTON3, OnDeleteEntryButton) - ON_NOTIFY(NM_CLICK, IDC_LIST3, OnClickList3) - ON_BN_CLICKED(IDC_BUTTON4, OnButtonShowCert) - ON_BN_CLICKED(IDC_BUTTON5, OnButtonExportCert) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST3, OnColumnclickList3) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST3, OnItemclickList3) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST3, OnKeydownList3) - ON_BN_CLICKED(IDC_CHECK1, OnCheckRsaKey) - ON_BN_CLICKED(IDC_CHECK2, OnCheckDsaKey) - ON_BN_CLICKED(IDC_CHECK3, OnCheckEcKey) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyAsym::OnShowPubParamButton) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyAsym::OnShowAllParamButton) + ON_BN_CLICKED(IDC_BUTTON3, &CDlgKeyAsym::OnDeleteEntryButton) + ON_NOTIFY(NM_CLICK, IDC_LIST3, &CDlgKeyAsym::OnClickList3) + ON_BN_CLICKED(IDC_BUTTON4, &CDlgKeyAsym::OnButtonShowCert) + ON_BN_CLICKED(IDC_BUTTON5, &CDlgKeyAsym::OnButtonExportCert) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST3, &CDlgKeyAsym::OnColumnclickList3) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST3, &CDlgKeyAsym::OnItemclickList3) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST3, &CDlgKeyAsym::OnKeydownList3) + ON_BN_CLICKED(IDC_CHECK1, &CDlgKeyAsym::OnCheckRsaKey) + ON_BN_CLICKED(IDC_CHECK2, &CDlgKeyAsym::OnCheckDsaKey) + ON_BN_CLICKED(IDC_CHECK3, &CDlgKeyAsym::OnCheckEcKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyAsymGeneration.cpp b/CrypTool/DlgKeyAsymGeneration.cpp index f96a341a0..c11f5cd5d 100644 --- a/CrypTool/DlgKeyAsymGeneration.cpp +++ b/CrypTool/DlgKeyAsymGeneration.cpp @@ -146,16 +146,16 @@ void CDlgKeyAsymGeneration::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyAsymGeneration, CDialog) //{{AFX_MSG_MAP(CDlgKeyAsymGeneration) - ON_CBN_SELCHANGE(IDC_COMBO3, OnSelchangeEcCombo) - ON_BN_CLICKED(IDC_RADIO1, OnRSARadio) - ON_BN_CLICKED(IDC_RADIO2, OnDSARadio) - ON_BN_CLICKED(IDC_RADIO3, OnECRadio) - ON_BN_CLICKED(IDC_RADIO5, OnDecimalRadio) - ON_BN_CLICKED(IDC_RADIO4, OnOctalRadio) - ON_BN_CLICKED(IDC_RADIO6, OnHexRadio) - ON_BN_CLICKED(IDC_BUTTON_P12IMPORT, OnButtonP12import) - ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList) - ON_EN_KILLFOCUS(IDC_EDIT_LV, OnKillfocusEditLv) + ON_CBN_SELCHANGE(IDC_COMBO3, &CDlgKeyAsymGeneration::OnSelchangeEcCombo) + ON_BN_CLICKED(IDC_RADIO1, &CDlgKeyAsymGeneration::OnRSARadio) + ON_BN_CLICKED(IDC_RADIO2, &CDlgKeyAsymGeneration::OnDSARadio) + ON_BN_CLICKED(IDC_RADIO3, &CDlgKeyAsymGeneration::OnECRadio) + ON_BN_CLICKED(IDC_RADIO5, &CDlgKeyAsymGeneration::OnDecimalRadio) + ON_BN_CLICKED(IDC_RADIO4, &CDlgKeyAsymGeneration::OnOctalRadio) + ON_BN_CLICKED(IDC_RADIO6, &CDlgKeyAsymGeneration::OnHexRadio) + ON_BN_CLICKED(IDC_BUTTON_P12IMPORT, &CDlgKeyAsymGeneration::OnButtonP12import) + ON_NOTIFY(NM_CLICK, IDC_LIST1, &CDlgKeyAsymGeneration::OnClickList) + ON_EN_KILLFOCUS(IDC_EDIT_LV, &CDlgKeyAsymGeneration::OnKillfocusEditLv) //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyAsymGeneration::OnBnClickedButton1) END_MESSAGE_MAP() @@ -440,7 +440,7 @@ void CDlgKeyAsymGeneration::UpdateEcListBox(EcDomParam_ac_ptr curveParameter, Ec { UpdateData(TRUE); LoadString(AfxGetInstanceHandle(),IDS_STRING_EC_DOMAIN_PARAMETER,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_ec_dom_par_description = (CString) pc_str1; UpdateData(FALSE); @@ -1074,7 +1074,7 @@ void CDlgKeyAsymGeneration::CreateAsymKeys() // user-information: key pair succesfully created. LoadString(AfxGetInstanceHandle(),IDS_STRING_ASYMKEY_MSG_STORE_KEYPAIR,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, UserKeyId); + sprintf(pc_str1, pc_str, (LPCTSTR)UserKeyId); LoadString(AfxGetInstanceHandle(),IDS_STRING_MSG_KEY_GENERATION_TIME,pc_str,STR_LAENGE_STRING_TABLE); char temp[256]; char strDuration[20]; diff --git a/CrypTool/DlgKeyFromPassword.cpp b/CrypTool/DlgKeyFromPassword.cpp index d180d8949..af0a1cccc 100644 --- a/CrypTool/DlgKeyFromPassword.cpp +++ b/CrypTool/DlgKeyFromPassword.cpp @@ -79,13 +79,13 @@ void CDlgKeyFromPassword::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyFromPassword, CDialog) //{{AFX_MSG_MAP(CDlgKeyFromPassword) - ON_BN_CLICKED(IDC_BUTTON_Generieren, OnBUTTONGenerieren) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1) - ON_EN_UPDATE(IDC_EDIT2, OnUpdateEdit2) - ON_BN_CLICKED(IDC_BUTTON_CANCEL, OnBUTTONcancel) - ON_BN_CLICKED(IDC_BUTTON_Uebernehmen, OnBUTTONUebernehmen) - ON_EN_UPDATE(IDC_EDIT4, OnUpdateEdit4) - ON_EN_UPDATE(IDC_EDIT5, OnUpdateEdit5) + ON_BN_CLICKED(IDC_BUTTON_Generieren, &CDlgKeyFromPassword::OnBUTTONGenerieren) + ON_EN_UPDATE(IDC_EDIT1, &CDlgKeyFromPassword::OnUpdateEdit1) + ON_EN_UPDATE(IDC_EDIT2, &CDlgKeyFromPassword::OnUpdateEdit2) + ON_BN_CLICKED(IDC_BUTTON_CANCEL, &CDlgKeyFromPassword::OnBUTTONcancel) + ON_BN_CLICKED(IDC_BUTTON_Uebernehmen, &CDlgKeyFromPassword::OnBUTTONUebernehmen) + ON_EN_UPDATE(IDC_EDIT4, &CDlgKeyFromPassword::OnUpdateEdit4) + ON_EN_UPDATE(IDC_EDIT5, &CDlgKeyFromPassword::OnUpdateEdit5) //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_RADIO1, &CDlgKeyFromPassword::OnBnClickedRadio1) ON_BN_CLICKED(IDC_RADIO2, &CDlgKeyFromPassword::OnBnClickedRadio2) diff --git a/CrypTool/DlgKeyHex.cpp b/CrypTool/DlgKeyHex.cpp index 07d7d0fa5..07add1242 100644 --- a/CrypTool/DlgKeyHex.cpp +++ b/CrypTool/DlgKeyHex.cpp @@ -112,10 +112,10 @@ void CDlgKeyHex::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyHex, CDialog) //{{AFX_MSG_MAP(CDlgKeyHex) - ON_BN_CLICKED(IDC_BUTTON1, OnDecrypt) - ON_BN_CLICKED(IDOK, OnEncrypt) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateKey) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteHexKey) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyHex::OnDecrypt) + ON_BN_CLICKED(IDOK, &CDlgKeyHex::OnEncrypt) + ON_EN_UPDATE(IDC_EDIT1, &CDlgKeyHex::OnUpdateKey) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyHex::OnPasteHexKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyHexFixedLen.cpp b/CrypTool/DlgKeyHexFixedLen.cpp index 6a8953d47..47a732deb 100644 --- a/CrypTool/DlgKeyHexFixedLen.cpp +++ b/CrypTool/DlgKeyHexFixedLen.cpp @@ -60,10 +60,10 @@ void CDlgKeyHexFixedLen::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyHexFixedLen, CDialog) //{{AFX_MSG_MAP(CDlgKeyHexFixedLen) - ON_CBN_SELCHANGE(IDC_KEY_LEN, OnChangeKeyLen) - ON_BN_CLICKED(IDC_ENCRYPT, OnEncrypt) - ON_BN_CLICKED(IDC_DECRYPT, OnDecrypt) - ON_BN_CLICKED(IDC_PASTE_KEY, OnPasteKey) + ON_CBN_SELCHANGE(IDC_KEY_LEN, &CDlgKeyHexFixedLen::OnChangeKeyLen) + ON_BN_CLICKED(IDC_ENCRYPT, &CDlgKeyHexFixedLen::OnEncrypt) + ON_BN_CLICKED(IDC_DECRYPT, &CDlgKeyHexFixedLen::OnDecrypt) + ON_BN_CLICKED(IDC_PASTE_KEY, &CDlgKeyHexFixedLen::OnPasteKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyHill10x10.cpp b/CrypTool/DlgKeyHill10x10.cpp index 89205c1d8..dd57d85b5 100644 --- a/CrypTool/DlgKeyHill10x10.cpp +++ b/CrypTool/DlgKeyHill10x10.cpp @@ -31,7 +31,7 @@ #include "HillEncryption.h" #include "ChrTools.h" #include "KeyRepository.h" -#include ".\dlgkeyhill10x10.h" +#include "DlgKeyHill10x10.h" #include "DlgHillOptions.h" #include "CrypToolTools.h" #include "assert.h" @@ -280,335 +280,335 @@ void CDlgKeyHill10x10::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyHill10x10, CDialog) //{{AFX_MSG_MAP(CDlgKeyHill10x10) - ON_EN_UPDATE(IDC_EDIT11, OnUpdateMat11) - ON_EN_UPDATE(IDC_EDIT12, OnUpdateMat12) - ON_EN_UPDATE(IDC_EDIT13, OnUpdateMat13) - ON_EN_UPDATE(IDC_EDIT14, OnUpdateMat14) - ON_EN_UPDATE(IDC_EDIT15, OnUpdateMat15) - ON_EN_UPDATE(IDC_EDIT16, OnUpdateMat16) - ON_EN_UPDATE(IDC_EDIT17, OnUpdateMat17) - ON_EN_UPDATE(IDC_EDIT18, OnUpdateMat18) - ON_EN_UPDATE(IDC_EDIT19, OnUpdateMat19) - ON_EN_UPDATE(IDC_EDIT110, OnUpdateMat110) - ON_EN_UPDATE(IDC_EDIT21, OnUpdateMat21) - ON_EN_UPDATE(IDC_EDIT22, OnUpdateMat22) - ON_EN_UPDATE(IDC_EDIT23, OnUpdateMat23) - ON_EN_UPDATE(IDC_EDIT24, OnUpdateMat24) - ON_EN_UPDATE(IDC_EDIT25, OnUpdateMat25) - ON_EN_UPDATE(IDC_EDIT26, OnUpdateMat26) - ON_EN_UPDATE(IDC_EDIT27, OnUpdateMat27) - ON_EN_UPDATE(IDC_EDIT28, OnUpdateMat28) - ON_EN_UPDATE(IDC_EDIT29, OnUpdateMat29) - ON_EN_UPDATE(IDC_EDIT210, OnUpdateMat210) - ON_EN_UPDATE(IDC_EDIT31, OnUpdateMat31) - ON_EN_UPDATE(IDC_EDIT32, OnUpdateMat32) - ON_EN_UPDATE(IDC_EDIT33, OnUpdateMat33) - ON_EN_UPDATE(IDC_EDIT34, OnUpdateMat34) - ON_EN_UPDATE(IDC_EDIT35, OnUpdateMat35) - ON_EN_UPDATE(IDC_EDIT36, OnUpdateMat36) - ON_EN_UPDATE(IDC_EDIT37, OnUpdateMat37) - ON_EN_UPDATE(IDC_EDIT38, OnUpdateMat38) - ON_EN_UPDATE(IDC_EDIT39, OnUpdateMat39) - ON_EN_UPDATE(IDC_EDIT310, OnUpdateMat310) - ON_EN_UPDATE(IDC_EDIT41, OnUpdateMat41) - ON_EN_UPDATE(IDC_EDIT42, OnUpdateMat42) - ON_EN_UPDATE(IDC_EDIT43, OnUpdateMat43) - ON_EN_UPDATE(IDC_EDIT44, OnUpdateMat44) - ON_EN_UPDATE(IDC_EDIT45, OnUpdateMat45) - ON_EN_UPDATE(IDC_EDIT46, OnUpdateMat46) - ON_EN_UPDATE(IDC_EDIT47, OnUpdateMat47) - ON_EN_UPDATE(IDC_EDIT48, OnUpdateMat48) - ON_EN_UPDATE(IDC_EDIT49, OnUpdateMat49) - ON_EN_UPDATE(IDC_EDIT410, OnUpdateMat410) - ON_EN_UPDATE(IDC_EDIT51, OnUpdateMat51) - ON_EN_UPDATE(IDC_EDIT52, OnUpdateMat52) - ON_EN_UPDATE(IDC_EDIT53, OnUpdateMat53) - ON_EN_UPDATE(IDC_EDIT54, OnUpdateMat54) - ON_EN_UPDATE(IDC_EDIT55, OnUpdateMat55) - ON_EN_UPDATE(IDC_EDIT56, OnUpdateMat56) - ON_EN_UPDATE(IDC_EDIT57, OnUpdateMat57) - ON_EN_UPDATE(IDC_EDIT58, OnUpdateMat58) - ON_EN_UPDATE(IDC_EDIT59, OnUpdateMat59) - ON_EN_UPDATE(IDC_EDIT510, OnUpdateMat510) - ON_EN_UPDATE(IDC_EDIT61, OnUpdateMat61) - ON_EN_UPDATE(IDC_EDIT62, OnUpdateMat62) - ON_EN_UPDATE(IDC_EDIT63, OnUpdateMat63) - ON_EN_UPDATE(IDC_EDIT64, OnUpdateMat64) - ON_EN_UPDATE(IDC_EDIT65, OnUpdateMat65) - ON_EN_UPDATE(IDC_EDIT66, OnUpdateMat66) - ON_EN_UPDATE(IDC_EDIT67, OnUpdateMat67) - ON_EN_UPDATE(IDC_EDIT68, OnUpdateMat68) - ON_EN_UPDATE(IDC_EDIT69, OnUpdateMat69) - ON_EN_UPDATE(IDC_EDIT610, OnUpdateMat610) - ON_EN_UPDATE(IDC_EDIT71, OnUpdateMat71) - ON_EN_UPDATE(IDC_EDIT72, OnUpdateMat72) - ON_EN_UPDATE(IDC_EDIT73, OnUpdateMat73) - ON_EN_UPDATE(IDC_EDIT74, OnUpdateMat74) - ON_EN_UPDATE(IDC_EDIT75, OnUpdateMat75) - ON_EN_UPDATE(IDC_EDIT76, OnUpdateMat76) - ON_EN_UPDATE(IDC_EDIT77, OnUpdateMat77) - ON_EN_UPDATE(IDC_EDIT78, OnUpdateMat78) - ON_EN_UPDATE(IDC_EDIT79, OnUpdateMat79) - ON_EN_UPDATE(IDC_EDIT710, OnUpdateMat710) - ON_EN_UPDATE(IDC_EDIT81, OnUpdateMat81) - ON_EN_UPDATE(IDC_EDIT82, OnUpdateMat82) - ON_EN_UPDATE(IDC_EDIT83, OnUpdateMat83) - ON_EN_UPDATE(IDC_EDIT84, OnUpdateMat84) - ON_EN_UPDATE(IDC_EDIT85, OnUpdateMat85) - ON_EN_UPDATE(IDC_EDIT86, OnUpdateMat86) - ON_EN_UPDATE(IDC_EDIT87, OnUpdateMat87) - ON_EN_UPDATE(IDC_EDIT88, OnUpdateMat88) - ON_EN_UPDATE(IDC_EDIT89, OnUpdateMat89) - ON_EN_UPDATE(IDC_EDIT810, OnUpdateMat810) - ON_EN_UPDATE(IDC_EDIT91, OnUpdateMat91) - ON_EN_UPDATE(IDC_EDIT92, OnUpdateMat92) - ON_EN_UPDATE(IDC_EDIT93, OnUpdateMat93) - ON_EN_UPDATE(IDC_EDIT94, OnUpdateMat94) - ON_EN_UPDATE(IDC_EDIT95, OnUpdateMat95) - ON_EN_UPDATE(IDC_EDIT96, OnUpdateMat96) - ON_EN_UPDATE(IDC_EDIT97, OnUpdateMat97) - ON_EN_UPDATE(IDC_EDIT98, OnUpdateMat98) - ON_EN_UPDATE(IDC_EDIT99, OnUpdateMat99) - ON_EN_UPDATE(IDC_EDIT910, OnUpdateMat910) - ON_EN_UPDATE(IDC_EDIT101, OnUpdateMat101) - ON_EN_UPDATE(IDC_EDIT102, OnUpdateMat102) - ON_EN_UPDATE(IDC_EDIT103, OnUpdateMat103) - ON_EN_UPDATE(IDC_EDIT104, OnUpdateMat104) - ON_EN_UPDATE(IDC_EDIT105, OnUpdateMat105) - ON_EN_UPDATE(IDC_EDIT106, OnUpdateMat106) - ON_EN_UPDATE(IDC_EDIT107, OnUpdateMat107) - ON_EN_UPDATE(IDC_EDIT108, OnUpdateMat108) - ON_EN_UPDATE(IDC_EDIT109, OnUpdateMat109) - ON_EN_UPDATE(IDC_EDIT1010, OnUpdateMat1010) + ON_EN_UPDATE(IDC_EDIT11, &CDlgKeyHill10x10::OnUpdateMat11) + ON_EN_UPDATE(IDC_EDIT12, &CDlgKeyHill10x10::OnUpdateMat12) + ON_EN_UPDATE(IDC_EDIT13, &CDlgKeyHill10x10::OnUpdateMat13) + ON_EN_UPDATE(IDC_EDIT14, &CDlgKeyHill10x10::OnUpdateMat14) + ON_EN_UPDATE(IDC_EDIT15, &CDlgKeyHill10x10::OnUpdateMat15) + ON_EN_UPDATE(IDC_EDIT16, &CDlgKeyHill10x10::OnUpdateMat16) + ON_EN_UPDATE(IDC_EDIT17, &CDlgKeyHill10x10::OnUpdateMat17) + ON_EN_UPDATE(IDC_EDIT18, &CDlgKeyHill10x10::OnUpdateMat18) + ON_EN_UPDATE(IDC_EDIT19, &CDlgKeyHill10x10::OnUpdateMat19) + ON_EN_UPDATE(IDC_EDIT110, &CDlgKeyHill10x10::OnUpdateMat110) + ON_EN_UPDATE(IDC_EDIT21, &CDlgKeyHill10x10::OnUpdateMat21) + ON_EN_UPDATE(IDC_EDIT22, &CDlgKeyHill10x10::OnUpdateMat22) + ON_EN_UPDATE(IDC_EDIT23, &CDlgKeyHill10x10::OnUpdateMat23) + ON_EN_UPDATE(IDC_EDIT24, &CDlgKeyHill10x10::OnUpdateMat24) + ON_EN_UPDATE(IDC_EDIT25, &CDlgKeyHill10x10::OnUpdateMat25) + ON_EN_UPDATE(IDC_EDIT26, &CDlgKeyHill10x10::OnUpdateMat26) + ON_EN_UPDATE(IDC_EDIT27, &CDlgKeyHill10x10::OnUpdateMat27) + ON_EN_UPDATE(IDC_EDIT28, &CDlgKeyHill10x10::OnUpdateMat28) + ON_EN_UPDATE(IDC_EDIT29, &CDlgKeyHill10x10::OnUpdateMat29) + ON_EN_UPDATE(IDC_EDIT210, &CDlgKeyHill10x10::OnUpdateMat210) + ON_EN_UPDATE(IDC_EDIT31, &CDlgKeyHill10x10::OnUpdateMat31) + ON_EN_UPDATE(IDC_EDIT32, &CDlgKeyHill10x10::OnUpdateMat32) + ON_EN_UPDATE(IDC_EDIT33, &CDlgKeyHill10x10::OnUpdateMat33) + ON_EN_UPDATE(IDC_EDIT34, &CDlgKeyHill10x10::OnUpdateMat34) + ON_EN_UPDATE(IDC_EDIT35, &CDlgKeyHill10x10::OnUpdateMat35) + ON_EN_UPDATE(IDC_EDIT36, &CDlgKeyHill10x10::OnUpdateMat36) + ON_EN_UPDATE(IDC_EDIT37, &CDlgKeyHill10x10::OnUpdateMat37) + ON_EN_UPDATE(IDC_EDIT38, &CDlgKeyHill10x10::OnUpdateMat38) + ON_EN_UPDATE(IDC_EDIT39, &CDlgKeyHill10x10::OnUpdateMat39) + ON_EN_UPDATE(IDC_EDIT310, &CDlgKeyHill10x10::OnUpdateMat310) + ON_EN_UPDATE(IDC_EDIT41, &CDlgKeyHill10x10::OnUpdateMat41) + ON_EN_UPDATE(IDC_EDIT42, &CDlgKeyHill10x10::OnUpdateMat42) + ON_EN_UPDATE(IDC_EDIT43, &CDlgKeyHill10x10::OnUpdateMat43) + ON_EN_UPDATE(IDC_EDIT44, &CDlgKeyHill10x10::OnUpdateMat44) + ON_EN_UPDATE(IDC_EDIT45, &CDlgKeyHill10x10::OnUpdateMat45) + ON_EN_UPDATE(IDC_EDIT46, &CDlgKeyHill10x10::OnUpdateMat46) + ON_EN_UPDATE(IDC_EDIT47, &CDlgKeyHill10x10::OnUpdateMat47) + ON_EN_UPDATE(IDC_EDIT48, &CDlgKeyHill10x10::OnUpdateMat48) + ON_EN_UPDATE(IDC_EDIT49, &CDlgKeyHill10x10::OnUpdateMat49) + ON_EN_UPDATE(IDC_EDIT410, &CDlgKeyHill10x10::OnUpdateMat410) + ON_EN_UPDATE(IDC_EDIT51, &CDlgKeyHill10x10::OnUpdateMat51) + ON_EN_UPDATE(IDC_EDIT52, &CDlgKeyHill10x10::OnUpdateMat52) + ON_EN_UPDATE(IDC_EDIT53, &CDlgKeyHill10x10::OnUpdateMat53) + ON_EN_UPDATE(IDC_EDIT54, &CDlgKeyHill10x10::OnUpdateMat54) + ON_EN_UPDATE(IDC_EDIT55, &CDlgKeyHill10x10::OnUpdateMat55) + ON_EN_UPDATE(IDC_EDIT56, &CDlgKeyHill10x10::OnUpdateMat56) + ON_EN_UPDATE(IDC_EDIT57, &CDlgKeyHill10x10::OnUpdateMat57) + ON_EN_UPDATE(IDC_EDIT58, &CDlgKeyHill10x10::OnUpdateMat58) + ON_EN_UPDATE(IDC_EDIT59, &CDlgKeyHill10x10::OnUpdateMat59) + ON_EN_UPDATE(IDC_EDIT510, &CDlgKeyHill10x10::OnUpdateMat510) + ON_EN_UPDATE(IDC_EDIT61, &CDlgKeyHill10x10::OnUpdateMat61) + ON_EN_UPDATE(IDC_EDIT62, &CDlgKeyHill10x10::OnUpdateMat62) + ON_EN_UPDATE(IDC_EDIT63, &CDlgKeyHill10x10::OnUpdateMat63) + ON_EN_UPDATE(IDC_EDIT64, &CDlgKeyHill10x10::OnUpdateMat64) + ON_EN_UPDATE(IDC_EDIT65, &CDlgKeyHill10x10::OnUpdateMat65) + ON_EN_UPDATE(IDC_EDIT66, &CDlgKeyHill10x10::OnUpdateMat66) + ON_EN_UPDATE(IDC_EDIT67, &CDlgKeyHill10x10::OnUpdateMat67) + ON_EN_UPDATE(IDC_EDIT68, &CDlgKeyHill10x10::OnUpdateMat68) + ON_EN_UPDATE(IDC_EDIT69, &CDlgKeyHill10x10::OnUpdateMat69) + ON_EN_UPDATE(IDC_EDIT610, &CDlgKeyHill10x10::OnUpdateMat610) + ON_EN_UPDATE(IDC_EDIT71, &CDlgKeyHill10x10::OnUpdateMat71) + ON_EN_UPDATE(IDC_EDIT72, &CDlgKeyHill10x10::OnUpdateMat72) + ON_EN_UPDATE(IDC_EDIT73, &CDlgKeyHill10x10::OnUpdateMat73) + ON_EN_UPDATE(IDC_EDIT74, &CDlgKeyHill10x10::OnUpdateMat74) + ON_EN_UPDATE(IDC_EDIT75, &CDlgKeyHill10x10::OnUpdateMat75) + ON_EN_UPDATE(IDC_EDIT76, &CDlgKeyHill10x10::OnUpdateMat76) + ON_EN_UPDATE(IDC_EDIT77, &CDlgKeyHill10x10::OnUpdateMat77) + ON_EN_UPDATE(IDC_EDIT78, &CDlgKeyHill10x10::OnUpdateMat78) + ON_EN_UPDATE(IDC_EDIT79, &CDlgKeyHill10x10::OnUpdateMat79) + ON_EN_UPDATE(IDC_EDIT710, &CDlgKeyHill10x10::OnUpdateMat710) + ON_EN_UPDATE(IDC_EDIT81, &CDlgKeyHill10x10::OnUpdateMat81) + ON_EN_UPDATE(IDC_EDIT82, &CDlgKeyHill10x10::OnUpdateMat82) + ON_EN_UPDATE(IDC_EDIT83, &CDlgKeyHill10x10::OnUpdateMat83) + ON_EN_UPDATE(IDC_EDIT84, &CDlgKeyHill10x10::OnUpdateMat84) + ON_EN_UPDATE(IDC_EDIT85, &CDlgKeyHill10x10::OnUpdateMat85) + ON_EN_UPDATE(IDC_EDIT86, &CDlgKeyHill10x10::OnUpdateMat86) + ON_EN_UPDATE(IDC_EDIT87, &CDlgKeyHill10x10::OnUpdateMat87) + ON_EN_UPDATE(IDC_EDIT88, &CDlgKeyHill10x10::OnUpdateMat88) + ON_EN_UPDATE(IDC_EDIT89, &CDlgKeyHill10x10::OnUpdateMat89) + ON_EN_UPDATE(IDC_EDIT810, &CDlgKeyHill10x10::OnUpdateMat810) + ON_EN_UPDATE(IDC_EDIT91, &CDlgKeyHill10x10::OnUpdateMat91) + ON_EN_UPDATE(IDC_EDIT92, &CDlgKeyHill10x10::OnUpdateMat92) + ON_EN_UPDATE(IDC_EDIT93, &CDlgKeyHill10x10::OnUpdateMat93) + ON_EN_UPDATE(IDC_EDIT94, &CDlgKeyHill10x10::OnUpdateMat94) + ON_EN_UPDATE(IDC_EDIT95, &CDlgKeyHill10x10::OnUpdateMat95) + ON_EN_UPDATE(IDC_EDIT96, &CDlgKeyHill10x10::OnUpdateMat96) + ON_EN_UPDATE(IDC_EDIT97, &CDlgKeyHill10x10::OnUpdateMat97) + ON_EN_UPDATE(IDC_EDIT98, &CDlgKeyHill10x10::OnUpdateMat98) + ON_EN_UPDATE(IDC_EDIT99, &CDlgKeyHill10x10::OnUpdateMat99) + ON_EN_UPDATE(IDC_EDIT910, &CDlgKeyHill10x10::OnUpdateMat910) + ON_EN_UPDATE(IDC_EDIT101, &CDlgKeyHill10x10::OnUpdateMat101) + ON_EN_UPDATE(IDC_EDIT102, &CDlgKeyHill10x10::OnUpdateMat102) + ON_EN_UPDATE(IDC_EDIT103, &CDlgKeyHill10x10::OnUpdateMat103) + ON_EN_UPDATE(IDC_EDIT104, &CDlgKeyHill10x10::OnUpdateMat104) + ON_EN_UPDATE(IDC_EDIT105, &CDlgKeyHill10x10::OnUpdateMat105) + ON_EN_UPDATE(IDC_EDIT106, &CDlgKeyHill10x10::OnUpdateMat106) + ON_EN_UPDATE(IDC_EDIT107, &CDlgKeyHill10x10::OnUpdateMat107) + ON_EN_UPDATE(IDC_EDIT108, &CDlgKeyHill10x10::OnUpdateMat108) + ON_EN_UPDATE(IDC_EDIT109, &CDlgKeyHill10x10::OnUpdateMat109) + ON_EN_UPDATE(IDC_EDIT1010, &CDlgKeyHill10x10::OnUpdateMat1010) - ON_EN_UPDATE(IDC_EDIT40, OnUpdateMat40) - ON_EN_UPDATE(IDC_EDIT50, OnUpdateMat50) - ON_EN_UPDATE(IDC_EDIT20, OnUpdateMat20) - ON_EN_UPDATE(IDC_EDIT90, OnUpdateMat90) - ON_EN_UPDATE(IDC_EDIT100, OnUpdateMat100) - ON_EN_UPDATE(IDC_EDIT117, OnUpdateMat117) - ON_EN_UPDATE(IDC_EDIT118, OnUpdateMat118) - ON_EN_UPDATE(IDC_EDIT119, OnUpdateMat119) - ON_EN_UPDATE(IDC_EDIT60, OnUpdateMat60) - ON_EN_UPDATE(IDC_EDIT125, OnUpdateMat125) - ON_EN_UPDATE(IDC_EDIT127, OnUpdateMat127) - ON_EN_UPDATE(IDC_EDIT134, OnUpdateMat134) - ON_EN_UPDATE(IDC_EDIT135, OnUpdateMat135) - ON_EN_UPDATE(IDC_EDIT136, OnUpdateMat136) - ON_EN_UPDATE(IDC_EDIT70, OnUpdateMat70) - ON_EN_UPDATE(IDC_EDIT137, OnUpdateMat137) - ON_EN_UPDATE(IDC_EDIT138, OnUpdateMat138) - ON_EN_UPDATE(IDC_EDIT139, OnUpdateMat139) - ON_EN_UPDATE(IDC_EDIT80, OnUpdateMat80) - ON_EN_UPDATE(IDC_EDIT211, OnUpdateMat211) - ON_EN_UPDATE(IDC_EDIT140, OnUpdateMat140) - ON_EN_UPDATE(IDC_EDIT141, OnUpdateMat141) - ON_EN_UPDATE(IDC_EDIT142, OnUpdateMat142) - ON_EN_UPDATE(IDC_EDIT143, OnUpdateMat143) - ON_EN_UPDATE(IDC_EDIT144, OnUpdateMat144) - ON_EN_UPDATE(IDC_EDIT145, OnUpdateMat145) - ON_EN_UPDATE(IDC_EDIT146, OnUpdateMat146) - ON_EN_UPDATE(IDC_EDIT147, OnUpdateMat147) - ON_EN_UPDATE(IDC_EDIT148, OnUpdateMat148) - ON_EN_UPDATE(IDC_EDIT311, OnUpdateMat311) - ON_EN_UPDATE(IDC_EDIT149, OnUpdateMat149) - ON_EN_UPDATE(IDC_EDIT150, OnUpdateMat150) - ON_EN_UPDATE(IDC_EDIT151, OnUpdateMat151) - ON_EN_UPDATE(IDC_EDIT152, OnUpdateMat152) - ON_EN_UPDATE(IDC_EDIT153, OnUpdateMat153) - ON_EN_UPDATE(IDC_EDIT154, OnUpdateMat154) - ON_EN_UPDATE(IDC_EDIT155, OnUpdateMat155) - ON_EN_UPDATE(IDC_EDIT156, OnUpdateMat156) - ON_EN_UPDATE(IDC_EDIT157, OnUpdateMat157) - ON_EN_UPDATE(IDC_EDIT411, OnUpdateMat411) - ON_EN_UPDATE(IDC_EDIT158, OnUpdateMat158) - ON_EN_UPDATE(IDC_EDIT159, OnUpdateMat159) - ON_EN_UPDATE(IDC_EDIT113, OnUpdateMat113) - ON_EN_UPDATE(IDC_EDIT160, OnUpdateMat160) - ON_EN_UPDATE(IDC_EDIT161, OnUpdateMat161) - ON_EN_UPDATE(IDC_EDIT162, OnUpdateMat162) - ON_EN_UPDATE(IDC_EDIT163, OnUpdateMat163) - ON_EN_UPDATE(IDC_EDIT164, OnUpdateMat164) - ON_EN_UPDATE(IDC_EDIT165, OnUpdateMat165) - ON_EN_UPDATE(IDC_EDIT511, OnUpdateMat511) - ON_EN_UPDATE(IDC_EDIT166, OnUpdateMat166) - ON_EN_UPDATE(IDC_EDIT167, OnUpdateMat167) - ON_EN_UPDATE(IDC_EDIT168, OnUpdateMat168) - ON_EN_UPDATE(IDC_EDIT169, OnUpdateMat169) - ON_EN_UPDATE(IDC_EDIT170, OnUpdateMat170) - ON_EN_UPDATE(IDC_EDIT171, OnUpdateMat171) - ON_EN_UPDATE(IDC_EDIT172, OnUpdateMat172) - ON_EN_UPDATE(IDC_EDIT173, OnUpdateMat173) - ON_EN_UPDATE(IDC_EDIT174, OnUpdateMat174) - ON_EN_UPDATE(IDC_EDIT611, OnUpdateMat611) - ON_EN_UPDATE(IDC_EDIT175, OnUpdateMat175) - ON_EN_UPDATE(IDC_EDIT176, OnUpdateMat176) - ON_EN_UPDATE(IDC_EDIT177, OnUpdateMat177) - ON_EN_UPDATE(IDC_EDIT178, OnUpdateMat178) - ON_EN_UPDATE(IDC_EDIT179, OnUpdateMat179) - ON_EN_UPDATE(IDC_EDIT180, OnUpdateMat180) - ON_EN_UPDATE(IDC_EDIT181, OnUpdateMat181) - ON_EN_UPDATE(IDC_EDIT182, OnUpdateMat182) - ON_EN_UPDATE(IDC_EDIT183, OnUpdateMat183) - ON_EN_UPDATE(IDC_EDIT711, OnUpdateMat711) - ON_EN_UPDATE(IDC_EDIT184, OnUpdateMat184) - ON_EN_UPDATE(IDC_EDIT185, OnUpdateMat185) - ON_EN_UPDATE(IDC_EDIT186, OnUpdateMat186) - ON_EN_UPDATE(IDC_EDIT187, OnUpdateMat187) - ON_EN_UPDATE(IDC_EDIT188, OnUpdateMat188) - ON_EN_UPDATE(IDC_EDIT189, OnUpdateMat189) - ON_EN_UPDATE(IDC_EDIT190, OnUpdateMat190) - ON_EN_UPDATE(IDC_EDIT191, OnUpdateMat191) - ON_EN_UPDATE(IDC_EDIT192, OnUpdateMat192) - ON_EN_UPDATE(IDC_EDIT811, OnUpdateMat811) - ON_EN_UPDATE(IDC_EDIT193, OnUpdateMat193) - ON_EN_UPDATE(IDC_EDIT194, OnUpdateMat194) - ON_EN_UPDATE(IDC_EDIT195, OnUpdateMat195) - ON_EN_UPDATE(IDC_EDIT196, OnUpdateMat196) - ON_EN_UPDATE(IDC_EDIT197, OnUpdateMat197) - ON_EN_UPDATE(IDC_EDIT198, OnUpdateMat198) - ON_EN_UPDATE(IDC_EDIT199, OnUpdateMat199) - ON_EN_UPDATE(IDC_EDIT200, OnUpdateMat200) - ON_EN_UPDATE(IDC_EDIT201, OnUpdateMat201) - ON_EN_UPDATE(IDC_EDIT911, OnUpdateMat911) - ON_EN_UPDATE(IDC_EDIT202, OnUpdateMat202) - ON_EN_UPDATE(IDC_EDIT203, OnUpdateMat203) - ON_EN_UPDATE(IDC_EDIT204, OnUpdateMat204) - ON_EN_UPDATE(IDC_EDIT205, OnUpdateMat205) - ON_EN_UPDATE(IDC_EDIT206, OnUpdateMat206) - ON_EN_UPDATE(IDC_EDIT207, OnUpdateMat207) - ON_EN_UPDATE(IDC_EDIT208, OnUpdateMat208) - ON_EN_UPDATE(IDC_EDIT209, OnUpdateMat209) - ON_EN_UPDATE(IDC_EDIT212, OnUpdateMat212) - ON_EN_UPDATE(IDC_EDIT1011, OnUpdateMat1011) + ON_EN_UPDATE(IDC_EDIT40, &CDlgKeyHill10x10::OnUpdateMat40) + ON_EN_UPDATE(IDC_EDIT50, &CDlgKeyHill10x10::OnUpdateMat50) + ON_EN_UPDATE(IDC_EDIT20, &CDlgKeyHill10x10::OnUpdateMat20) + ON_EN_UPDATE(IDC_EDIT90, &CDlgKeyHill10x10::OnUpdateMat90) + ON_EN_UPDATE(IDC_EDIT100, &CDlgKeyHill10x10::OnUpdateMat100) + ON_EN_UPDATE(IDC_EDIT117, &CDlgKeyHill10x10::OnUpdateMat117) + ON_EN_UPDATE(IDC_EDIT118, &CDlgKeyHill10x10::OnUpdateMat118) + ON_EN_UPDATE(IDC_EDIT119, &CDlgKeyHill10x10::OnUpdateMat119) + ON_EN_UPDATE(IDC_EDIT60, &CDlgKeyHill10x10::OnUpdateMat60) + ON_EN_UPDATE(IDC_EDIT125, &CDlgKeyHill10x10::OnUpdateMat125) + ON_EN_UPDATE(IDC_EDIT127, &CDlgKeyHill10x10::OnUpdateMat127) + ON_EN_UPDATE(IDC_EDIT134, &CDlgKeyHill10x10::OnUpdateMat134) + ON_EN_UPDATE(IDC_EDIT135, &CDlgKeyHill10x10::OnUpdateMat135) + ON_EN_UPDATE(IDC_EDIT136, &CDlgKeyHill10x10::OnUpdateMat136) + ON_EN_UPDATE(IDC_EDIT70, &CDlgKeyHill10x10::OnUpdateMat70) + ON_EN_UPDATE(IDC_EDIT137, &CDlgKeyHill10x10::OnUpdateMat137) + ON_EN_UPDATE(IDC_EDIT138, &CDlgKeyHill10x10::OnUpdateMat138) + ON_EN_UPDATE(IDC_EDIT139, &CDlgKeyHill10x10::OnUpdateMat139) + ON_EN_UPDATE(IDC_EDIT80, &CDlgKeyHill10x10::OnUpdateMat80) + ON_EN_UPDATE(IDC_EDIT211, &CDlgKeyHill10x10::OnUpdateMat211) + ON_EN_UPDATE(IDC_EDIT140, &CDlgKeyHill10x10::OnUpdateMat140) + ON_EN_UPDATE(IDC_EDIT141, &CDlgKeyHill10x10::OnUpdateMat141) + ON_EN_UPDATE(IDC_EDIT142, &CDlgKeyHill10x10::OnUpdateMat142) + ON_EN_UPDATE(IDC_EDIT143, &CDlgKeyHill10x10::OnUpdateMat143) + ON_EN_UPDATE(IDC_EDIT144, &CDlgKeyHill10x10::OnUpdateMat144) + ON_EN_UPDATE(IDC_EDIT145, &CDlgKeyHill10x10::OnUpdateMat145) + ON_EN_UPDATE(IDC_EDIT146, &CDlgKeyHill10x10::OnUpdateMat146) + ON_EN_UPDATE(IDC_EDIT147, &CDlgKeyHill10x10::OnUpdateMat147) + ON_EN_UPDATE(IDC_EDIT148, &CDlgKeyHill10x10::OnUpdateMat148) + ON_EN_UPDATE(IDC_EDIT311, &CDlgKeyHill10x10::OnUpdateMat311) + ON_EN_UPDATE(IDC_EDIT149, &CDlgKeyHill10x10::OnUpdateMat149) + ON_EN_UPDATE(IDC_EDIT150, &CDlgKeyHill10x10::OnUpdateMat150) + ON_EN_UPDATE(IDC_EDIT151, &CDlgKeyHill10x10::OnUpdateMat151) + ON_EN_UPDATE(IDC_EDIT152, &CDlgKeyHill10x10::OnUpdateMat152) + ON_EN_UPDATE(IDC_EDIT153, &CDlgKeyHill10x10::OnUpdateMat153) + ON_EN_UPDATE(IDC_EDIT154, &CDlgKeyHill10x10::OnUpdateMat154) + ON_EN_UPDATE(IDC_EDIT155, &CDlgKeyHill10x10::OnUpdateMat155) + ON_EN_UPDATE(IDC_EDIT156, &CDlgKeyHill10x10::OnUpdateMat156) + ON_EN_UPDATE(IDC_EDIT157, &CDlgKeyHill10x10::OnUpdateMat157) + ON_EN_UPDATE(IDC_EDIT411, &CDlgKeyHill10x10::OnUpdateMat411) + ON_EN_UPDATE(IDC_EDIT158, &CDlgKeyHill10x10::OnUpdateMat158) + ON_EN_UPDATE(IDC_EDIT159, &CDlgKeyHill10x10::OnUpdateMat159) + ON_EN_UPDATE(IDC_EDIT113, &CDlgKeyHill10x10::OnUpdateMat113) + ON_EN_UPDATE(IDC_EDIT160, &CDlgKeyHill10x10::OnUpdateMat160) + ON_EN_UPDATE(IDC_EDIT161, &CDlgKeyHill10x10::OnUpdateMat161) + ON_EN_UPDATE(IDC_EDIT162, &CDlgKeyHill10x10::OnUpdateMat162) + ON_EN_UPDATE(IDC_EDIT163, &CDlgKeyHill10x10::OnUpdateMat163) + ON_EN_UPDATE(IDC_EDIT164, &CDlgKeyHill10x10::OnUpdateMat164) + ON_EN_UPDATE(IDC_EDIT165, &CDlgKeyHill10x10::OnUpdateMat165) + ON_EN_UPDATE(IDC_EDIT511, &CDlgKeyHill10x10::OnUpdateMat511) + ON_EN_UPDATE(IDC_EDIT166, &CDlgKeyHill10x10::OnUpdateMat166) + ON_EN_UPDATE(IDC_EDIT167, &CDlgKeyHill10x10::OnUpdateMat167) + ON_EN_UPDATE(IDC_EDIT168, &CDlgKeyHill10x10::OnUpdateMat168) + ON_EN_UPDATE(IDC_EDIT169, &CDlgKeyHill10x10::OnUpdateMat169) + ON_EN_UPDATE(IDC_EDIT170, &CDlgKeyHill10x10::OnUpdateMat170) + ON_EN_UPDATE(IDC_EDIT171, &CDlgKeyHill10x10::OnUpdateMat171) + ON_EN_UPDATE(IDC_EDIT172, &CDlgKeyHill10x10::OnUpdateMat172) + ON_EN_UPDATE(IDC_EDIT173, &CDlgKeyHill10x10::OnUpdateMat173) + ON_EN_UPDATE(IDC_EDIT174, &CDlgKeyHill10x10::OnUpdateMat174) + ON_EN_UPDATE(IDC_EDIT611, &CDlgKeyHill10x10::OnUpdateMat611) + ON_EN_UPDATE(IDC_EDIT175, &CDlgKeyHill10x10::OnUpdateMat175) + ON_EN_UPDATE(IDC_EDIT176, &CDlgKeyHill10x10::OnUpdateMat176) + ON_EN_UPDATE(IDC_EDIT177, &CDlgKeyHill10x10::OnUpdateMat177) + ON_EN_UPDATE(IDC_EDIT178, &CDlgKeyHill10x10::OnUpdateMat178) + ON_EN_UPDATE(IDC_EDIT179, &CDlgKeyHill10x10::OnUpdateMat179) + ON_EN_UPDATE(IDC_EDIT180, &CDlgKeyHill10x10::OnUpdateMat180) + ON_EN_UPDATE(IDC_EDIT181, &CDlgKeyHill10x10::OnUpdateMat181) + ON_EN_UPDATE(IDC_EDIT182, &CDlgKeyHill10x10::OnUpdateMat182) + ON_EN_UPDATE(IDC_EDIT183, &CDlgKeyHill10x10::OnUpdateMat183) + ON_EN_UPDATE(IDC_EDIT711, &CDlgKeyHill10x10::OnUpdateMat711) + ON_EN_UPDATE(IDC_EDIT184, &CDlgKeyHill10x10::OnUpdateMat184) + ON_EN_UPDATE(IDC_EDIT185, &CDlgKeyHill10x10::OnUpdateMat185) + ON_EN_UPDATE(IDC_EDIT186, &CDlgKeyHill10x10::OnUpdateMat186) + ON_EN_UPDATE(IDC_EDIT187, &CDlgKeyHill10x10::OnUpdateMat187) + ON_EN_UPDATE(IDC_EDIT188, &CDlgKeyHill10x10::OnUpdateMat188) + ON_EN_UPDATE(IDC_EDIT189, &CDlgKeyHill10x10::OnUpdateMat189) + ON_EN_UPDATE(IDC_EDIT190, &CDlgKeyHill10x10::OnUpdateMat190) + ON_EN_UPDATE(IDC_EDIT191, &CDlgKeyHill10x10::OnUpdateMat191) + ON_EN_UPDATE(IDC_EDIT192, &CDlgKeyHill10x10::OnUpdateMat192) + ON_EN_UPDATE(IDC_EDIT811, &CDlgKeyHill10x10::OnUpdateMat811) + ON_EN_UPDATE(IDC_EDIT193, &CDlgKeyHill10x10::OnUpdateMat193) + ON_EN_UPDATE(IDC_EDIT194, &CDlgKeyHill10x10::OnUpdateMat194) + ON_EN_UPDATE(IDC_EDIT195, &CDlgKeyHill10x10::OnUpdateMat195) + ON_EN_UPDATE(IDC_EDIT196, &CDlgKeyHill10x10::OnUpdateMat196) + ON_EN_UPDATE(IDC_EDIT197, &CDlgKeyHill10x10::OnUpdateMat197) + ON_EN_UPDATE(IDC_EDIT198, &CDlgKeyHill10x10::OnUpdateMat198) + ON_EN_UPDATE(IDC_EDIT199, &CDlgKeyHill10x10::OnUpdateMat199) + ON_EN_UPDATE(IDC_EDIT200, &CDlgKeyHill10x10::OnUpdateMat200) + ON_EN_UPDATE(IDC_EDIT201, &CDlgKeyHill10x10::OnUpdateMat201) + ON_EN_UPDATE(IDC_EDIT911, &CDlgKeyHill10x10::OnUpdateMat911) + ON_EN_UPDATE(IDC_EDIT202, &CDlgKeyHill10x10::OnUpdateMat202) + ON_EN_UPDATE(IDC_EDIT203, &CDlgKeyHill10x10::OnUpdateMat203) + ON_EN_UPDATE(IDC_EDIT204, &CDlgKeyHill10x10::OnUpdateMat204) + ON_EN_UPDATE(IDC_EDIT205, &CDlgKeyHill10x10::OnUpdateMat205) + ON_EN_UPDATE(IDC_EDIT206, &CDlgKeyHill10x10::OnUpdateMat206) + ON_EN_UPDATE(IDC_EDIT207, &CDlgKeyHill10x10::OnUpdateMat207) + ON_EN_UPDATE(IDC_EDIT208, &CDlgKeyHill10x10::OnUpdateMat208) + ON_EN_UPDATE(IDC_EDIT209, &CDlgKeyHill10x10::OnUpdateMat209) + ON_EN_UPDATE(IDC_EDIT212, &CDlgKeyHill10x10::OnUpdateMat212) + ON_EN_UPDATE(IDC_EDIT1011, &CDlgKeyHill10x10::OnUpdateMat1011) - ON_EN_KILLFOCUS(IDC_EDIT40, OnExitMat40) - ON_EN_KILLFOCUS(IDC_EDIT50, OnExitMat50) - ON_EN_KILLFOCUS(IDC_EDIT20, OnExitMat20) - ON_EN_KILLFOCUS(IDC_EDIT90, OnExitMat90) - ON_EN_KILLFOCUS(IDC_EDIT100, OnExitMat100) - ON_EN_KILLFOCUS(IDC_EDIT117, OnExitMat117) - ON_EN_KILLFOCUS(IDC_EDIT118, OnExitMat118) - ON_EN_KILLFOCUS(IDC_EDIT119, OnExitMat119) - ON_EN_KILLFOCUS(IDC_EDIT60, OnExitMat60) - ON_EN_KILLFOCUS(IDC_EDIT125, OnExitMat125) - ON_EN_KILLFOCUS(IDC_EDIT127, OnExitMat127) - ON_EN_KILLFOCUS(IDC_EDIT134, OnExitMat134) - ON_EN_KILLFOCUS(IDC_EDIT135, OnExitMat135) - ON_EN_KILLFOCUS(IDC_EDIT136, OnExitMat136) - ON_EN_KILLFOCUS(IDC_EDIT70, OnExitMat70) - ON_EN_KILLFOCUS(IDC_EDIT137, OnExitMat137) - ON_EN_KILLFOCUS(IDC_EDIT138, OnExitMat138) - ON_EN_KILLFOCUS(IDC_EDIT139, OnExitMat139) - ON_EN_KILLFOCUS(IDC_EDIT80, OnExitMat80) - ON_EN_KILLFOCUS(IDC_EDIT211, OnExitMat211) - ON_EN_KILLFOCUS(IDC_EDIT140, OnExitMat140) - ON_EN_KILLFOCUS(IDC_EDIT141, OnExitMat141) - ON_EN_KILLFOCUS(IDC_EDIT142, OnExitMat142) - ON_EN_KILLFOCUS(IDC_EDIT143, OnExitMat143) - ON_EN_KILLFOCUS(IDC_EDIT144, OnExitMat144) - ON_EN_KILLFOCUS(IDC_EDIT145, OnExitMat145) - ON_EN_KILLFOCUS(IDC_EDIT146, OnExitMat146) - ON_EN_KILLFOCUS(IDC_EDIT147, OnExitMat147) - ON_EN_KILLFOCUS(IDC_EDIT148, OnExitMat148) - ON_EN_KILLFOCUS(IDC_EDIT311, OnExitMat311) - ON_EN_KILLFOCUS(IDC_EDIT149, OnExitMat149) - ON_EN_KILLFOCUS(IDC_EDIT150, OnExitMat150) - ON_EN_KILLFOCUS(IDC_EDIT151, OnExitMat151) - ON_EN_KILLFOCUS(IDC_EDIT152, OnExitMat152) - ON_EN_KILLFOCUS(IDC_EDIT153, OnExitMat153) - ON_EN_KILLFOCUS(IDC_EDIT154, OnExitMat154) - ON_EN_KILLFOCUS(IDC_EDIT155, OnExitMat155) - ON_EN_KILLFOCUS(IDC_EDIT156, OnExitMat156) - ON_EN_KILLFOCUS(IDC_EDIT157, OnExitMat157) - ON_EN_KILLFOCUS(IDC_EDIT411, OnExitMat411) - ON_EN_KILLFOCUS(IDC_EDIT158, OnExitMat158) - ON_EN_KILLFOCUS(IDC_EDIT159, OnExitMat159) - ON_EN_KILLFOCUS(IDC_EDIT113, OnExitMat113) - ON_EN_KILLFOCUS(IDC_EDIT160, OnExitMat160) - ON_EN_KILLFOCUS(IDC_EDIT161, OnExitMat161) - ON_EN_KILLFOCUS(IDC_EDIT162, OnExitMat162) - ON_EN_KILLFOCUS(IDC_EDIT163, OnExitMat163) - ON_EN_KILLFOCUS(IDC_EDIT164, OnExitMat164) - ON_EN_KILLFOCUS(IDC_EDIT165, OnExitMat165) - ON_EN_KILLFOCUS(IDC_EDIT511, OnExitMat511) - ON_EN_KILLFOCUS(IDC_EDIT166, OnExitMat166) - ON_EN_KILLFOCUS(IDC_EDIT167, OnExitMat167) - ON_EN_KILLFOCUS(IDC_EDIT168, OnExitMat168) - ON_EN_KILLFOCUS(IDC_EDIT169, OnExitMat169) - ON_EN_KILLFOCUS(IDC_EDIT170, OnExitMat170) - ON_EN_KILLFOCUS(IDC_EDIT171, OnExitMat171) - ON_EN_KILLFOCUS(IDC_EDIT172, OnExitMat172) - ON_EN_KILLFOCUS(IDC_EDIT173, OnExitMat173) - ON_EN_KILLFOCUS(IDC_EDIT174, OnExitMat174) - ON_EN_KILLFOCUS(IDC_EDIT611, OnExitMat611) - ON_EN_KILLFOCUS(IDC_EDIT175, OnExitMat175) - ON_EN_KILLFOCUS(IDC_EDIT176, OnExitMat176) - ON_EN_KILLFOCUS(IDC_EDIT177, OnExitMat177) - ON_EN_KILLFOCUS(IDC_EDIT178, OnExitMat178) - ON_EN_KILLFOCUS(IDC_EDIT179, OnExitMat179) - ON_EN_KILLFOCUS(IDC_EDIT180, OnExitMat180) - ON_EN_KILLFOCUS(IDC_EDIT181, OnExitMat181) - ON_EN_KILLFOCUS(IDC_EDIT182, OnExitMat182) - ON_EN_KILLFOCUS(IDC_EDIT183, OnExitMat183) - ON_EN_KILLFOCUS(IDC_EDIT711, OnExitMat711) - ON_EN_KILLFOCUS(IDC_EDIT184, OnExitMat184) - ON_EN_KILLFOCUS(IDC_EDIT185, OnExitMat185) - ON_EN_KILLFOCUS(IDC_EDIT186, OnExitMat186) - ON_EN_KILLFOCUS(IDC_EDIT187, OnExitMat187) - ON_EN_KILLFOCUS(IDC_EDIT188, OnExitMat188) - ON_EN_KILLFOCUS(IDC_EDIT189, OnExitMat189) - ON_EN_KILLFOCUS(IDC_EDIT190, OnExitMat190) - ON_EN_KILLFOCUS(IDC_EDIT191, OnExitMat191) - ON_EN_KILLFOCUS(IDC_EDIT192, OnExitMat192) - ON_EN_KILLFOCUS(IDC_EDIT811, OnExitMat811) - ON_EN_KILLFOCUS(IDC_EDIT193, OnExitMat193) - ON_EN_KILLFOCUS(IDC_EDIT194, OnExitMat194) - ON_EN_KILLFOCUS(IDC_EDIT195, OnExitMat195) - ON_EN_KILLFOCUS(IDC_EDIT196, OnExitMat196) - ON_EN_KILLFOCUS(IDC_EDIT197, OnExitMat197) - ON_EN_KILLFOCUS(IDC_EDIT198, OnExitMat198) - ON_EN_KILLFOCUS(IDC_EDIT199, OnExitMat199) - ON_EN_KILLFOCUS(IDC_EDIT200, OnExitMat200) - ON_EN_KILLFOCUS(IDC_EDIT201, OnExitMat201) - ON_EN_KILLFOCUS(IDC_EDIT911, OnExitMat911) - ON_EN_KILLFOCUS(IDC_EDIT202, OnExitMat202) - ON_EN_KILLFOCUS(IDC_EDIT203, OnExitMat203) - ON_EN_KILLFOCUS(IDC_EDIT204, OnExitMat204) - ON_EN_KILLFOCUS(IDC_EDIT205, OnExitMat205) - ON_EN_KILLFOCUS(IDC_EDIT206, OnExitMat206) - ON_EN_KILLFOCUS(IDC_EDIT207, OnExitMat207) - ON_EN_KILLFOCUS(IDC_EDIT208, OnExitMat208) - ON_EN_KILLFOCUS(IDC_EDIT209, OnExitMat209) - ON_EN_KILLFOCUS(IDC_EDIT212, OnExitMat212) - ON_EN_KILLFOCUS(IDC_EDIT1011, OnExitMat1011) + ON_EN_KILLFOCUS(IDC_EDIT40, &CDlgKeyHill10x10::OnExitMat40) + ON_EN_KILLFOCUS(IDC_EDIT50, &CDlgKeyHill10x10::OnExitMat50) + ON_EN_KILLFOCUS(IDC_EDIT20, &CDlgKeyHill10x10::OnExitMat20) + ON_EN_KILLFOCUS(IDC_EDIT90, &CDlgKeyHill10x10::OnExitMat90) + ON_EN_KILLFOCUS(IDC_EDIT100, &CDlgKeyHill10x10::OnExitMat100) + ON_EN_KILLFOCUS(IDC_EDIT117, &CDlgKeyHill10x10::OnExitMat117) + ON_EN_KILLFOCUS(IDC_EDIT118, &CDlgKeyHill10x10::OnExitMat118) + ON_EN_KILLFOCUS(IDC_EDIT119, &CDlgKeyHill10x10::OnExitMat119) + ON_EN_KILLFOCUS(IDC_EDIT60, &CDlgKeyHill10x10::OnExitMat60) + ON_EN_KILLFOCUS(IDC_EDIT125, &CDlgKeyHill10x10::OnExitMat125) + ON_EN_KILLFOCUS(IDC_EDIT127, &CDlgKeyHill10x10::OnExitMat127) + ON_EN_KILLFOCUS(IDC_EDIT134, &CDlgKeyHill10x10::OnExitMat134) + ON_EN_KILLFOCUS(IDC_EDIT135, &CDlgKeyHill10x10::OnExitMat135) + ON_EN_KILLFOCUS(IDC_EDIT136, &CDlgKeyHill10x10::OnExitMat136) + ON_EN_KILLFOCUS(IDC_EDIT70, &CDlgKeyHill10x10::OnExitMat70) + ON_EN_KILLFOCUS(IDC_EDIT137, &CDlgKeyHill10x10::OnExitMat137) + ON_EN_KILLFOCUS(IDC_EDIT138, &CDlgKeyHill10x10::OnExitMat138) + ON_EN_KILLFOCUS(IDC_EDIT139, &CDlgKeyHill10x10::OnExitMat139) + ON_EN_KILLFOCUS(IDC_EDIT80, &CDlgKeyHill10x10::OnExitMat80) + ON_EN_KILLFOCUS(IDC_EDIT211, &CDlgKeyHill10x10::OnExitMat211) + ON_EN_KILLFOCUS(IDC_EDIT140, &CDlgKeyHill10x10::OnExitMat140) + ON_EN_KILLFOCUS(IDC_EDIT141, &CDlgKeyHill10x10::OnExitMat141) + ON_EN_KILLFOCUS(IDC_EDIT142, &CDlgKeyHill10x10::OnExitMat142) + ON_EN_KILLFOCUS(IDC_EDIT143, &CDlgKeyHill10x10::OnExitMat143) + ON_EN_KILLFOCUS(IDC_EDIT144, &CDlgKeyHill10x10::OnExitMat144) + ON_EN_KILLFOCUS(IDC_EDIT145, &CDlgKeyHill10x10::OnExitMat145) + ON_EN_KILLFOCUS(IDC_EDIT146, &CDlgKeyHill10x10::OnExitMat146) + ON_EN_KILLFOCUS(IDC_EDIT147, &CDlgKeyHill10x10::OnExitMat147) + ON_EN_KILLFOCUS(IDC_EDIT148, &CDlgKeyHill10x10::OnExitMat148) + ON_EN_KILLFOCUS(IDC_EDIT311, &CDlgKeyHill10x10::OnExitMat311) + ON_EN_KILLFOCUS(IDC_EDIT149, &CDlgKeyHill10x10::OnExitMat149) + ON_EN_KILLFOCUS(IDC_EDIT150, &CDlgKeyHill10x10::OnExitMat150) + ON_EN_KILLFOCUS(IDC_EDIT151, &CDlgKeyHill10x10::OnExitMat151) + ON_EN_KILLFOCUS(IDC_EDIT152, &CDlgKeyHill10x10::OnExitMat152) + ON_EN_KILLFOCUS(IDC_EDIT153, &CDlgKeyHill10x10::OnExitMat153) + ON_EN_KILLFOCUS(IDC_EDIT154, &CDlgKeyHill10x10::OnExitMat154) + ON_EN_KILLFOCUS(IDC_EDIT155, &CDlgKeyHill10x10::OnExitMat155) + ON_EN_KILLFOCUS(IDC_EDIT156, &CDlgKeyHill10x10::OnExitMat156) + ON_EN_KILLFOCUS(IDC_EDIT157, &CDlgKeyHill10x10::OnExitMat157) + ON_EN_KILLFOCUS(IDC_EDIT411, &CDlgKeyHill10x10::OnExitMat411) + ON_EN_KILLFOCUS(IDC_EDIT158, &CDlgKeyHill10x10::OnExitMat158) + ON_EN_KILLFOCUS(IDC_EDIT159, &CDlgKeyHill10x10::OnExitMat159) + ON_EN_KILLFOCUS(IDC_EDIT113, &CDlgKeyHill10x10::OnExitMat113) + ON_EN_KILLFOCUS(IDC_EDIT160, &CDlgKeyHill10x10::OnExitMat160) + ON_EN_KILLFOCUS(IDC_EDIT161, &CDlgKeyHill10x10::OnExitMat161) + ON_EN_KILLFOCUS(IDC_EDIT162, &CDlgKeyHill10x10::OnExitMat162) + ON_EN_KILLFOCUS(IDC_EDIT163, &CDlgKeyHill10x10::OnExitMat163) + ON_EN_KILLFOCUS(IDC_EDIT164, &CDlgKeyHill10x10::OnExitMat164) + ON_EN_KILLFOCUS(IDC_EDIT165, &CDlgKeyHill10x10::OnExitMat165) + ON_EN_KILLFOCUS(IDC_EDIT511, &CDlgKeyHill10x10::OnExitMat511) + ON_EN_KILLFOCUS(IDC_EDIT166, &CDlgKeyHill10x10::OnExitMat166) + ON_EN_KILLFOCUS(IDC_EDIT167, &CDlgKeyHill10x10::OnExitMat167) + ON_EN_KILLFOCUS(IDC_EDIT168, &CDlgKeyHill10x10::OnExitMat168) + ON_EN_KILLFOCUS(IDC_EDIT169, &CDlgKeyHill10x10::OnExitMat169) + ON_EN_KILLFOCUS(IDC_EDIT170, &CDlgKeyHill10x10::OnExitMat170) + ON_EN_KILLFOCUS(IDC_EDIT171, &CDlgKeyHill10x10::OnExitMat171) + ON_EN_KILLFOCUS(IDC_EDIT172, &CDlgKeyHill10x10::OnExitMat172) + ON_EN_KILLFOCUS(IDC_EDIT173, &CDlgKeyHill10x10::OnExitMat173) + ON_EN_KILLFOCUS(IDC_EDIT174, &CDlgKeyHill10x10::OnExitMat174) + ON_EN_KILLFOCUS(IDC_EDIT611, &CDlgKeyHill10x10::OnExitMat611) + ON_EN_KILLFOCUS(IDC_EDIT175, &CDlgKeyHill10x10::OnExitMat175) + ON_EN_KILLFOCUS(IDC_EDIT176, &CDlgKeyHill10x10::OnExitMat176) + ON_EN_KILLFOCUS(IDC_EDIT177, &CDlgKeyHill10x10::OnExitMat177) + ON_EN_KILLFOCUS(IDC_EDIT178, &CDlgKeyHill10x10::OnExitMat178) + ON_EN_KILLFOCUS(IDC_EDIT179, &CDlgKeyHill10x10::OnExitMat179) + ON_EN_KILLFOCUS(IDC_EDIT180, &CDlgKeyHill10x10::OnExitMat180) + ON_EN_KILLFOCUS(IDC_EDIT181, &CDlgKeyHill10x10::OnExitMat181) + ON_EN_KILLFOCUS(IDC_EDIT182, &CDlgKeyHill10x10::OnExitMat182) + ON_EN_KILLFOCUS(IDC_EDIT183, &CDlgKeyHill10x10::OnExitMat183) + ON_EN_KILLFOCUS(IDC_EDIT711, &CDlgKeyHill10x10::OnExitMat711) + ON_EN_KILLFOCUS(IDC_EDIT184, &CDlgKeyHill10x10::OnExitMat184) + ON_EN_KILLFOCUS(IDC_EDIT185, &CDlgKeyHill10x10::OnExitMat185) + ON_EN_KILLFOCUS(IDC_EDIT186, &CDlgKeyHill10x10::OnExitMat186) + ON_EN_KILLFOCUS(IDC_EDIT187, &CDlgKeyHill10x10::OnExitMat187) + ON_EN_KILLFOCUS(IDC_EDIT188, &CDlgKeyHill10x10::OnExitMat188) + ON_EN_KILLFOCUS(IDC_EDIT189, &CDlgKeyHill10x10::OnExitMat189) + ON_EN_KILLFOCUS(IDC_EDIT190, &CDlgKeyHill10x10::OnExitMat190) + ON_EN_KILLFOCUS(IDC_EDIT191, &CDlgKeyHill10x10::OnExitMat191) + ON_EN_KILLFOCUS(IDC_EDIT192, &CDlgKeyHill10x10::OnExitMat192) + ON_EN_KILLFOCUS(IDC_EDIT811, &CDlgKeyHill10x10::OnExitMat811) + ON_EN_KILLFOCUS(IDC_EDIT193, &CDlgKeyHill10x10::OnExitMat193) + ON_EN_KILLFOCUS(IDC_EDIT194, &CDlgKeyHill10x10::OnExitMat194) + ON_EN_KILLFOCUS(IDC_EDIT195, &CDlgKeyHill10x10::OnExitMat195) + ON_EN_KILLFOCUS(IDC_EDIT196, &CDlgKeyHill10x10::OnExitMat196) + ON_EN_KILLFOCUS(IDC_EDIT197, &CDlgKeyHill10x10::OnExitMat197) + ON_EN_KILLFOCUS(IDC_EDIT198, &CDlgKeyHill10x10::OnExitMat198) + ON_EN_KILLFOCUS(IDC_EDIT199, &CDlgKeyHill10x10::OnExitMat199) + ON_EN_KILLFOCUS(IDC_EDIT200, &CDlgKeyHill10x10::OnExitMat200) + ON_EN_KILLFOCUS(IDC_EDIT201, &CDlgKeyHill10x10::OnExitMat201) + ON_EN_KILLFOCUS(IDC_EDIT911, &CDlgKeyHill10x10::OnExitMat911) + ON_EN_KILLFOCUS(IDC_EDIT202, &CDlgKeyHill10x10::OnExitMat202) + ON_EN_KILLFOCUS(IDC_EDIT203, &CDlgKeyHill10x10::OnExitMat203) + ON_EN_KILLFOCUS(IDC_EDIT204, &CDlgKeyHill10x10::OnExitMat204) + ON_EN_KILLFOCUS(IDC_EDIT205, &CDlgKeyHill10x10::OnExitMat205) + ON_EN_KILLFOCUS(IDC_EDIT206, &CDlgKeyHill10x10::OnExitMat206) + ON_EN_KILLFOCUS(IDC_EDIT207, &CDlgKeyHill10x10::OnExitMat207) + ON_EN_KILLFOCUS(IDC_EDIT208, &CDlgKeyHill10x10::OnExitMat208) + ON_EN_KILLFOCUS(IDC_EDIT209, &CDlgKeyHill10x10::OnExitMat209) + ON_EN_KILLFOCUS(IDC_EDIT212, &CDlgKeyHill10x10::OnExitMat212) + ON_EN_KILLFOCUS(IDC_EDIT1011, &CDlgKeyHill10x10::OnExitMat1011) - ON_BN_CLICKED(IDC_RADIO1, OnDimension1) - ON_BN_CLICKED(IDC_RADIO2, OnDimension2) - ON_BN_CLICKED(IDC_RADIO3, OnDimension3) - ON_BN_CLICKED(IDC_RADIO4, OnDimension4) - ON_BN_CLICKED(IDC_RADIO5, OnDimension5) - ON_BN_CLICKED(IDC_RADIO6, OnDimension6) - ON_BN_CLICKED(IDC_RADIO7, OnDimension7) - ON_BN_CLICKED(IDC_RADIO8, OnDimension8) - ON_BN_CLICKED(IDC_RADIO9, OnDimension9) - ON_BN_CLICKED(IDC_RADIO10, OnDimension10) + ON_BN_CLICKED(IDC_RADIO1, &CDlgKeyHill10x10::OnDimension1) + ON_BN_CLICKED(IDC_RADIO2, &CDlgKeyHill10x10::OnDimension2) + ON_BN_CLICKED(IDC_RADIO3, &CDlgKeyHill10x10::OnDimension3) + ON_BN_CLICKED(IDC_RADIO4, &CDlgKeyHill10x10::OnDimension4) + ON_BN_CLICKED(IDC_RADIO5, &CDlgKeyHill10x10::OnDimension5) + ON_BN_CLICKED(IDC_RADIO6, &CDlgKeyHill10x10::OnDimension6) + ON_BN_CLICKED(IDC_RADIO7, &CDlgKeyHill10x10::OnDimension7) + ON_BN_CLICKED(IDC_RADIO8, &CDlgKeyHill10x10::OnDimension8) + ON_BN_CLICKED(IDC_RADIO9, &CDlgKeyHill10x10::OnDimension9) + ON_BN_CLICKED(IDC_RADIO10, &CDlgKeyHill10x10::OnDimension10) - ON_BN_CLICKED(IDC_RADIO21, OnEnableAlphCode) - ON_BN_CLICKED(IDC_RADIO22, OnDisableAlphCode) - ON_BN_CLICKED(IDC_RADIO23, OnRowVectorMatrix) - ON_BN_CLICKED(IDC_RADIO24, OnMatrixColumnVector) + ON_BN_CLICKED(IDC_RADIO21, &CDlgKeyHill10x10::OnEnableAlphCode) + ON_BN_CLICKED(IDC_RADIO22, &CDlgKeyHill10x10::OnDisableAlphCode) + ON_BN_CLICKED(IDC_RADIO23, &CDlgKeyHill10x10::OnRowVectorMatrix) + ON_BN_CLICKED(IDC_RADIO24, &CDlgKeyHill10x10::OnMatrixColumnVector) - ON_BN_CLICKED(IDC_BUTTON3, OnZufaelligerSchluessel) - ON_BN_CLICKED(IDC_BUTTON_RESETKEY, OnResetKey) - ON_BN_CLICKED(IDC_BUTTON4, OnKleinereSchluessel) - ON_BN_CLICKED(IDC_BUTTON5, OnDecrypt) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteKey) + ON_BN_CLICKED(IDC_BUTTON3, &CDlgKeyHill10x10::OnZufaelligerSchluessel) + ON_BN_CLICKED(IDC_BUTTON_RESETKEY, &CDlgKeyHill10x10::OnResetKey) + ON_BN_CLICKED(IDC_BUTTON4, &CDlgKeyHill10x10::OnKleinereSchluessel) + ON_BN_CLICKED(IDC_BUTTON5, &CDlgKeyHill10x10::OnDecrypt) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyHill10x10::OnPasteKey) - ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, OnTextOptions) + ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, &CDlgKeyHill10x10::OnTextOptions) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_BUTTON69, OnHillOptions) + ON_BN_CLICKED(IDC_BUTTON69, &CDlgKeyHill10x10::OnHillOptions) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// diff --git a/CrypTool/DlgKeyHill5x5.cpp b/CrypTool/DlgKeyHill5x5.cpp index 980809ea6..d9a0cb55d 100644 --- a/CrypTool/DlgKeyHill5x5.cpp +++ b/CrypTool/DlgKeyHill5x5.cpp @@ -123,103 +123,103 @@ BEGIN_MESSAGE_MAP(CDlgKeyHill5x5, CDialog) //{{AFX_MSG_MAP(CDlgKeyHill5x5) // HillAlphMat - ON_EN_UPDATE(IDC_EDIT11, OnUpdateMat11) - ON_EN_UPDATE(IDC_EDIT12, OnUpdateMat12) - ON_EN_UPDATE(IDC_EDIT13, OnUpdateMat13) - ON_EN_UPDATE(IDC_EDIT14, OnUpdateMat14) - ON_EN_UPDATE(IDC_EDIT15, OnUpdateMat15) - ON_EN_UPDATE(IDC_EDIT21, OnUpdateMat21) - ON_EN_UPDATE(IDC_EDIT22, OnUpdateMat22) - ON_EN_UPDATE(IDC_EDIT23, OnUpdateMat23) - ON_EN_UPDATE(IDC_EDIT24, OnUpdateMat24) - ON_EN_UPDATE(IDC_EDIT25, OnUpdateMat25) - ON_EN_UPDATE(IDC_EDIT31, OnUpdateMat31) - ON_EN_UPDATE(IDC_EDIT32, OnUpdateMat32) - ON_EN_UPDATE(IDC_EDIT33, OnUpdateMat33) - ON_EN_UPDATE(IDC_EDIT34, OnUpdateMat34) - ON_EN_UPDATE(IDC_EDIT35, OnUpdateMat35) - ON_EN_UPDATE(IDC_EDIT41, OnUpdateMat41) - ON_EN_UPDATE(IDC_EDIT42, OnUpdateMat42) - ON_EN_UPDATE(IDC_EDIT43, OnUpdateMat43) - ON_EN_UPDATE(IDC_EDIT44, OnUpdateMat44) - ON_EN_UPDATE(IDC_EDIT45, OnUpdateMat45) - ON_EN_UPDATE(IDC_EDIT51, OnUpdateMat51) - ON_EN_UPDATE(IDC_EDIT52, OnUpdateMat52) - ON_EN_UPDATE(IDC_EDIT53, OnUpdateMat53) - ON_EN_UPDATE(IDC_EDIT54, OnUpdateMat54) - ON_EN_UPDATE(IDC_EDIT55, OnUpdateMat55) + ON_EN_UPDATE(IDC_EDIT11, &CDlgKeyHill5x5::OnUpdateMat11) + ON_EN_UPDATE(IDC_EDIT12, &CDlgKeyHill5x5::OnUpdateMat12) + ON_EN_UPDATE(IDC_EDIT13, &CDlgKeyHill5x5::OnUpdateMat13) + ON_EN_UPDATE(IDC_EDIT14, &CDlgKeyHill5x5::OnUpdateMat14) + ON_EN_UPDATE(IDC_EDIT15, &CDlgKeyHill5x5::OnUpdateMat15) + ON_EN_UPDATE(IDC_EDIT21, &CDlgKeyHill5x5::OnUpdateMat21) + ON_EN_UPDATE(IDC_EDIT22, &CDlgKeyHill5x5::OnUpdateMat22) + ON_EN_UPDATE(IDC_EDIT23, &CDlgKeyHill5x5::OnUpdateMat23) + ON_EN_UPDATE(IDC_EDIT24, &CDlgKeyHill5x5::OnUpdateMat24) + ON_EN_UPDATE(IDC_EDIT25, &CDlgKeyHill5x5::OnUpdateMat25) + ON_EN_UPDATE(IDC_EDIT31, &CDlgKeyHill5x5::OnUpdateMat31) + ON_EN_UPDATE(IDC_EDIT32, &CDlgKeyHill5x5::OnUpdateMat32) + ON_EN_UPDATE(IDC_EDIT33, &CDlgKeyHill5x5::OnUpdateMat33) + ON_EN_UPDATE(IDC_EDIT34, &CDlgKeyHill5x5::OnUpdateMat34) + ON_EN_UPDATE(IDC_EDIT35, &CDlgKeyHill5x5::OnUpdateMat35) + ON_EN_UPDATE(IDC_EDIT41, &CDlgKeyHill5x5::OnUpdateMat41) + ON_EN_UPDATE(IDC_EDIT42, &CDlgKeyHill5x5::OnUpdateMat42) + ON_EN_UPDATE(IDC_EDIT43, &CDlgKeyHill5x5::OnUpdateMat43) + ON_EN_UPDATE(IDC_EDIT44, &CDlgKeyHill5x5::OnUpdateMat44) + ON_EN_UPDATE(IDC_EDIT45, &CDlgKeyHill5x5::OnUpdateMat45) + ON_EN_UPDATE(IDC_EDIT51, &CDlgKeyHill5x5::OnUpdateMat51) + ON_EN_UPDATE(IDC_EDIT52, &CDlgKeyHill5x5::OnUpdateMat52) + ON_EN_UPDATE(IDC_EDIT53, &CDlgKeyHill5x5::OnUpdateMat53) + ON_EN_UPDATE(IDC_EDIT54, &CDlgKeyHill5x5::OnUpdateMat54) + ON_EN_UPDATE(IDC_EDIT55, &CDlgKeyHill5x5::OnUpdateMat55) // HillNumMat - ON_EN_UPDATE(IDC_EDIT36, OnUpdateMat36) - ON_EN_UPDATE(IDC_EDIT37, OnUpdateMat37) - ON_EN_UPDATE(IDC_EDIT38, OnUpdateMat38) - ON_EN_UPDATE(IDC_EDIT40, OnUpdateMat40) - ON_EN_UPDATE(IDC_EDIT46, OnUpdateMat46) - ON_EN_UPDATE(IDC_EDIT47, OnUpdateMat47) - ON_EN_UPDATE(IDC_EDIT48, OnUpdateMat48) - ON_EN_UPDATE(IDC_EDIT49, OnUpdateMat49) - ON_EN_UPDATE(IDC_EDIT50, OnUpdateMat50) - ON_EN_UPDATE(IDC_EDIT111, OnUpdateMat111) - ON_EN_UPDATE(IDC_EDIT57, OnUpdateMat57) - ON_EN_UPDATE(IDC_EDIT58, OnUpdateMat58) - ON_EN_UPDATE(IDC_EDIT59, OnUpdateMat59) - ON_EN_UPDATE(IDC_EDIT56, OnUpdateMat56) - ON_EN_UPDATE(IDC_EDIT115, OnUpdateMat115) - ON_EN_UPDATE(IDC_EDIT60, OnUpdateMat60) - ON_EN_UPDATE(IDC_EDIT61, OnUpdateMat61) - ON_EN_UPDATE(IDC_EDIT62, OnUpdateMat62) - ON_EN_UPDATE(IDC_EDIT116, OnUpdateMat116) - ON_EN_UPDATE(IDC_EDIT117, OnUpdateMat117) - ON_EN_UPDATE(IDC_EDIT63, OnUpdateMat63) - ON_EN_UPDATE(IDC_EDIT64, OnUpdateMat64) - ON_EN_UPDATE(IDC_EDIT69, OnUpdateMat69) - ON_EN_UPDATE(IDC_EDIT65, OnUpdateMat65) - ON_EN_UPDATE(IDC_EDIT66, OnUpdateMat66) + ON_EN_UPDATE(IDC_EDIT36, &CDlgKeyHill5x5::OnUpdateMat36) + ON_EN_UPDATE(IDC_EDIT37, &CDlgKeyHill5x5::OnUpdateMat37) + ON_EN_UPDATE(IDC_EDIT38, &CDlgKeyHill5x5::OnUpdateMat38) + ON_EN_UPDATE(IDC_EDIT40, &CDlgKeyHill5x5::OnUpdateMat40) + ON_EN_UPDATE(IDC_EDIT46, &CDlgKeyHill5x5::OnUpdateMat46) + ON_EN_UPDATE(IDC_EDIT47, &CDlgKeyHill5x5::OnUpdateMat47) + ON_EN_UPDATE(IDC_EDIT48, &CDlgKeyHill5x5::OnUpdateMat48) + ON_EN_UPDATE(IDC_EDIT49, &CDlgKeyHill5x5::OnUpdateMat49) + ON_EN_UPDATE(IDC_EDIT50, &CDlgKeyHill5x5::OnUpdateMat50) + ON_EN_UPDATE(IDC_EDIT111, &CDlgKeyHill5x5::OnUpdateMat111) + ON_EN_UPDATE(IDC_EDIT57, &CDlgKeyHill5x5::OnUpdateMat57) + ON_EN_UPDATE(IDC_EDIT58, &CDlgKeyHill5x5::OnUpdateMat58) + ON_EN_UPDATE(IDC_EDIT59, &CDlgKeyHill5x5::OnUpdateMat59) + ON_EN_UPDATE(IDC_EDIT56, &CDlgKeyHill5x5::OnUpdateMat56) + ON_EN_UPDATE(IDC_EDIT115, &CDlgKeyHill5x5::OnUpdateMat115) + ON_EN_UPDATE(IDC_EDIT60, &CDlgKeyHill5x5::OnUpdateMat60) + ON_EN_UPDATE(IDC_EDIT61, &CDlgKeyHill5x5::OnUpdateMat61) + ON_EN_UPDATE(IDC_EDIT62, &CDlgKeyHill5x5::OnUpdateMat62) + ON_EN_UPDATE(IDC_EDIT116, &CDlgKeyHill5x5::OnUpdateMat116) + ON_EN_UPDATE(IDC_EDIT117, &CDlgKeyHill5x5::OnUpdateMat117) + ON_EN_UPDATE(IDC_EDIT63, &CDlgKeyHill5x5::OnUpdateMat63) + ON_EN_UPDATE(IDC_EDIT64, &CDlgKeyHill5x5::OnUpdateMat64) + ON_EN_UPDATE(IDC_EDIT69, &CDlgKeyHill5x5::OnUpdateMat69) + ON_EN_UPDATE(IDC_EDIT65, &CDlgKeyHill5x5::OnUpdateMat65) + ON_EN_UPDATE(IDC_EDIT66, &CDlgKeyHill5x5::OnUpdateMat66) - ON_EN_KILLFOCUS(IDC_EDIT36, OnExitMat36) - ON_EN_KILLFOCUS(IDC_EDIT37, OnExitMat37) - ON_EN_KILLFOCUS(IDC_EDIT38, OnExitMat38) - ON_EN_KILLFOCUS(IDC_EDIT40, OnExitMat40) - ON_EN_KILLFOCUS(IDC_EDIT46, OnExitMat46) - ON_EN_KILLFOCUS(IDC_EDIT47, OnExitMat47) - ON_EN_KILLFOCUS(IDC_EDIT48, OnExitMat48) - ON_EN_KILLFOCUS(IDC_EDIT49, OnExitMat49) - ON_EN_KILLFOCUS(IDC_EDIT50, OnExitMat50) - ON_EN_KILLFOCUS(IDC_EDIT111, OnExitMat111) - ON_EN_KILLFOCUS(IDC_EDIT57, OnExitMat57) - ON_EN_KILLFOCUS(IDC_EDIT58, OnExitMat58) - ON_EN_KILLFOCUS(IDC_EDIT59, OnExitMat59) - ON_EN_KILLFOCUS(IDC_EDIT56, OnExitMat56) - ON_EN_KILLFOCUS(IDC_EDIT115, OnExitMat115) - ON_EN_KILLFOCUS(IDC_EDIT60, OnExitMat60) - ON_EN_KILLFOCUS(IDC_EDIT61, OnExitMat61) - ON_EN_KILLFOCUS(IDC_EDIT62, OnExitMat62) - ON_EN_KILLFOCUS(IDC_EDIT116, OnExitMat116) - ON_EN_KILLFOCUS(IDC_EDIT117, OnExitMat117) - ON_EN_KILLFOCUS(IDC_EDIT63, OnExitMat63) - ON_EN_KILLFOCUS(IDC_EDIT64, OnExitMat64) - ON_EN_KILLFOCUS(IDC_EDIT69, OnExitMat69) - ON_EN_KILLFOCUS(IDC_EDIT65, OnExitMat65) - ON_EN_KILLFOCUS(IDC_EDIT66, OnExitMat66) + ON_EN_KILLFOCUS(IDC_EDIT36, &CDlgKeyHill5x5::OnExitMat36) + ON_EN_KILLFOCUS(IDC_EDIT37, &CDlgKeyHill5x5::OnExitMat37) + ON_EN_KILLFOCUS(IDC_EDIT38, &CDlgKeyHill5x5::OnExitMat38) + ON_EN_KILLFOCUS(IDC_EDIT40, &CDlgKeyHill5x5::OnExitMat40) + ON_EN_KILLFOCUS(IDC_EDIT46, &CDlgKeyHill5x5::OnExitMat46) + ON_EN_KILLFOCUS(IDC_EDIT47, &CDlgKeyHill5x5::OnExitMat47) + ON_EN_KILLFOCUS(IDC_EDIT48, &CDlgKeyHill5x5::OnExitMat48) + ON_EN_KILLFOCUS(IDC_EDIT49, &CDlgKeyHill5x5::OnExitMat49) + ON_EN_KILLFOCUS(IDC_EDIT50, &CDlgKeyHill5x5::OnExitMat50) + ON_EN_KILLFOCUS(IDC_EDIT111, &CDlgKeyHill5x5::OnExitMat111) + ON_EN_KILLFOCUS(IDC_EDIT57, &CDlgKeyHill5x5::OnExitMat57) + ON_EN_KILLFOCUS(IDC_EDIT58, &CDlgKeyHill5x5::OnExitMat58) + ON_EN_KILLFOCUS(IDC_EDIT59, &CDlgKeyHill5x5::OnExitMat59) + ON_EN_KILLFOCUS(IDC_EDIT56, &CDlgKeyHill5x5::OnExitMat56) + ON_EN_KILLFOCUS(IDC_EDIT115, &CDlgKeyHill5x5::OnExitMat115) + ON_EN_KILLFOCUS(IDC_EDIT60, &CDlgKeyHill5x5::OnExitMat60) + ON_EN_KILLFOCUS(IDC_EDIT61, &CDlgKeyHill5x5::OnExitMat61) + ON_EN_KILLFOCUS(IDC_EDIT62, &CDlgKeyHill5x5::OnExitMat62) + ON_EN_KILLFOCUS(IDC_EDIT116, &CDlgKeyHill5x5::OnExitMat116) + ON_EN_KILLFOCUS(IDC_EDIT117, &CDlgKeyHill5x5::OnExitMat117) + ON_EN_KILLFOCUS(IDC_EDIT63, &CDlgKeyHill5x5::OnExitMat63) + ON_EN_KILLFOCUS(IDC_EDIT64, &CDlgKeyHill5x5::OnExitMat64) + ON_EN_KILLFOCUS(IDC_EDIT69, &CDlgKeyHill5x5::OnExitMat69) + ON_EN_KILLFOCUS(IDC_EDIT65, &CDlgKeyHill5x5::OnExitMat65) + ON_EN_KILLFOCUS(IDC_EDIT66, &CDlgKeyHill5x5::OnExitMat66) // Select Matrix Dimension - ON_BN_CLICKED(IDC_RADIO1, OnDimension1) - ON_BN_CLICKED(IDC_RADIO2, OnDimension2) - ON_BN_CLICKED(IDC_RADIO3, OnDimension3) - ON_BN_CLICKED(IDC_RADIO4, OnDimension4) - ON_BN_CLICKED(IDC_RADIO5, OnDimension5) - - ON_BN_CLICKED(IDC_RADIO6, OnEnableAlphCode) - ON_BN_CLICKED(IDC_RADIO7, OnDisableAlphCode) - ON_BN_CLICKED(IDC_RADIO8, OnRowVectorMatrix) - ON_BN_CLICKED(IDC_RADIO9, OnMatrixColumnVector) - - ON_BN_CLICKED(IDC_BUTTON3, OnZufaelligerSchluessel) - ON_BN_CLICKED(IDC_BUTTON_RESETKEY, OnResetKey) - ON_BN_CLICKED(IDC_BUTTON4, OnGroessereSchluessel) - ON_BN_CLICKED(IDC_BUTTON5, OnDecrypt) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteKey) - ON_BN_CLICKED(IDC_BUTTON1, OnHillOptions) - ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, OnTextOptions) + ON_BN_CLICKED(IDC_RADIO1, &CDlgKeyHill5x5::OnDimension1) + ON_BN_CLICKED(IDC_RADIO2, &CDlgKeyHill5x5::OnDimension2) + ON_BN_CLICKED(IDC_RADIO3, &CDlgKeyHill5x5::OnDimension3) + ON_BN_CLICKED(IDC_RADIO4, &CDlgKeyHill5x5::OnDimension4) + ON_BN_CLICKED(IDC_RADIO5, &CDlgKeyHill5x5::OnDimension5) + + ON_BN_CLICKED(IDC_RADIO6, &CDlgKeyHill5x5::OnEnableAlphCode) + ON_BN_CLICKED(IDC_RADIO7, &CDlgKeyHill5x5::OnDisableAlphCode) + ON_BN_CLICKED(IDC_RADIO8, &CDlgKeyHill5x5::OnRowVectorMatrix) + ON_BN_CLICKED(IDC_RADIO9, &CDlgKeyHill5x5::OnMatrixColumnVector) + + ON_BN_CLICKED(IDC_BUTTON3, &CDlgKeyHill5x5::OnZufaelligerSchluessel) + ON_BN_CLICKED(IDC_BUTTON_RESETKEY, &CDlgKeyHill5x5::OnResetKey) + ON_BN_CLICKED(IDC_BUTTON4, &CDlgKeyHill5x5::OnGroessereSchluessel) + ON_BN_CLICKED(IDC_BUTTON5, &CDlgKeyHill5x5::OnDecrypt) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyHill5x5::OnPasteKey) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyHill5x5::OnHillOptions) + ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, &CDlgKeyHill5x5::OnTextOptions) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyHomophone.cpp b/CrypTool/DlgKeyHomophone.cpp index 55196eb83..dcfa8667c 100644 --- a/CrypTool/DlgKeyHomophone.cpp +++ b/CrypTool/DlgKeyHomophone.cpp @@ -28,7 +28,7 @@ #include "assert.h" #include "DialogeMessage.h" #include "KeyRepository.h" -#include ".\dlgkeyhomophone.h" +#include "DlgKeyHomophone.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -84,20 +84,20 @@ void CDlgKeyHomophone::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyHomophone, CDialog) //{{AFX_MSG_MAP(CDlgKeyHomophone) - ON_BN_CLICKED(IDC_ERZEUGEN, OnErzeugen) - ON_BN_CLICKED(IDC_BUTTON2, OnLoadKey) - ON_BN_CLICKED(IDC_BUTTON1, OnDecrypt) - ON_BN_CLICKED(IDOK, OnEncrypt) - ON_BN_CLICKED(IDC_RADIO4, OnHex) - ON_BN_CLICKED(IDC_RADIO5, OnDecimal) - ON_BN_CLICKED(IDC_BUTTON3, OnActualizeNoOfHomophones) - ON_NOTIFY(NM_CLICK, IDC_LIST1, OnSelectList) - ON_NOTIFY(NM_DBLCLK, IDC_LIST1, OnDblclkSelect) - ON_NOTIFY(NM_RETURN, IDC_LIST1, OnReturnSelect) - ON_BN_CLICKED(IDC_CHECK1, OnSelectEncryptFormatCharacters) + ON_BN_CLICKED(IDC_ERZEUGEN, &CDlgKeyHomophone::OnErzeugen) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyHomophone::OnLoadKey) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyHomophone::OnDecrypt) + ON_BN_CLICKED(IDOK, &CDlgKeyHomophone::OnEncrypt) + ON_BN_CLICKED(IDC_RADIO4, &CDlgKeyHomophone::OnHex) + ON_BN_CLICKED(IDC_RADIO5, &CDlgKeyHomophone::OnDecimal) + ON_BN_CLICKED(IDC_BUTTON3, &CDlgKeyHomophone::OnActualizeNoOfHomophones) + ON_NOTIFY(NM_CLICK, IDC_LIST1, &CDlgKeyHomophone::OnSelectList) + ON_NOTIFY(NM_DBLCLK, IDC_LIST1, &CDlgKeyHomophone::OnDblclkSelect) + ON_NOTIFY(NM_RETURN, IDC_LIST1, &CDlgKeyHomophone::OnReturnSelect) + ON_BN_CLICKED(IDC_CHECK1, &CDlgKeyHomophone::OnSelectEncryptFormatCharacters) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_RADIO_TEXT_INPUT, OnBnClickedRadioTextInput) - ON_BN_CLICKED(IDC_RADIO_BINARY_INPUT, OnBnClickedRadioBinaryInput) + ON_BN_CLICKED(IDC_RADIO_TEXT_INPUT, &CDlgKeyHomophone::OnBnClickedRadioTextInput) + ON_BN_CLICKED(IDC_RADIO_BINARY_INPUT, &CDlgKeyHomophone::OnBnClickedRadioBinaryInput) ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, &CDlgKeyHomophone::OnBnClickedButtonTextoptions) END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyPermutation.cpp b/CrypTool/DlgKeyPermutation.cpp index 10062f887..ff7c5b8e7 100644 --- a/CrypTool/DlgKeyPermutation.cpp +++ b/CrypTool/DlgKeyPermutation.cpp @@ -29,7 +29,7 @@ #include "KeyRepository.h" #include "DialogeMessage.h" -#include ".\dlgkeypermutation.h" +#include "DlgKeyPermutation.h" #include "CrypToolTools.h" #include "ChrTools.h" @@ -90,14 +90,14 @@ void CDlgKeyPermutation::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyPermutation, CDialog) //{{AFX_MSG_MAP(CDlgKeyPermutation) - ON_BN_CLICKED(IDC_BUTTON1, OnDecrypt) - ON_BN_CLICKED(IDOK, OnEncrypt) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteKey) - ON_BN_CLICKED(IDC_BUTTON_TxtOpt, OnTextOptions) - ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit1) - ON_EN_CHANGE(IDC_EDIT2, OnChangeEdit2) - ON_BN_CLICKED(IDC_RADIO9, OnRadioButtonBinaryData) - ON_BN_CLICKED(IDC_RADIO14, OnRadioButtonText) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyPermutation::OnDecrypt) + ON_BN_CLICKED(IDOK, &CDlgKeyPermutation::OnEncrypt) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyPermutation::OnPasteKey) + ON_BN_CLICKED(IDC_BUTTON_TxtOpt, &CDlgKeyPermutation::OnTextOptions) + ON_EN_CHANGE(IDC_EDIT1, &CDlgKeyPermutation::OnChangeEdit1) + ON_EN_CHANGE(IDC_EDIT2, &CDlgKeyPermutation::OnChangeEdit2) + ON_BN_CLICKED(IDC_RADIO9, &CDlgKeyPermutation::OnRadioButtonBinaryData) + ON_BN_CLICKED(IDC_RADIO14, &CDlgKeyPermutation::OnRadioButtonText) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -490,16 +490,18 @@ void CDlgKeyPermutation::OnPasteKey() if( k < 0 ) { int t = readKeyParam( buffer ); - if ( t > 0 ) m_Perm1 = makeASCII(buffer.Left(t)); + CString part = buffer.Left(t); + if ( t > 0 ) m_Perm1 = makeASCII(part); else m_Perm1 = makeASCII(buffer); m_Perm2.Empty(); } else { - m_Perm1 = makeASCII(buffer.Left(k)); + CString part1 = buffer.Left(k); + m_Perm1 = makeASCII(part1); int t = readKeyParam( buffer ); - if ( t > 0 ) m_Perm2 = makeASCII(buffer.Mid(k+1,(t-k)-1)); - else m_Perm2 = makeASCII(buffer.Right(buffer.GetLength()-k-1)); + CString part2 = ( t > 0 ) ? buffer.Mid(k+1,(t-k)-1) : buffer.Right(buffer.GetLength()-k-1); + m_Perm2 = makeASCII(part2); } UpdateData(FALSE); OnChangeEdit1(); diff --git a/CrypTool/DlgKeyPermutationInfo.cpp b/CrypTool/DlgKeyPermutationInfo.cpp index 9a3621a96..effcf624b 100644 --- a/CrypTool/DlgKeyPermutationInfo.cpp +++ b/CrypTool/DlgKeyPermutationInfo.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgKeyPermutationInfo.h" -#include ".\dlgkeypermutationinfo.h" +#include "DlgKeyPermutationInfo.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -64,7 +64,7 @@ void CDlgKeyPermutationInfo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyPermutationInfo, CDialog) //{{AFX_MSG_MAP(CDlgKeyPermutationInfo) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDBACK, OnBnClickedBack) + ON_BN_CLICKED(IDBACK, &CDlgKeyPermutationInfo::OnBnClickedBack) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// diff --git a/CrypTool/DlgKeyPlayfair.cpp b/CrypTool/DlgKeyPlayfair.cpp index 609cc774c..3582f4cba 100644 --- a/CrypTool/DlgKeyPlayfair.cpp +++ b/CrypTool/DlgKeyPlayfair.cpp @@ -138,19 +138,19 @@ void CDlgKeyPlayfair::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyPlayfair, CDialog) //{{AFX_MSG_MAP(CDlgKeyPlayfair) - ON_EN_UPDATE(IDC_KEYENTER, OnUpdateEdit1) - ON_BN_CLICKED(IDC_RADIO3, OnSechs) - ON_BN_CLICKED(IDC_RADIO4, OnSechs) - ON_BN_CLICKED(IDC_BUTTON1, OnDecrypt) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteKey) - ON_BN_CLICKED(IDOK, OnEncrypt) - ON_BN_CLICKED(IDC_CHECK1, OnCheck) - ON_BN_CLICKED(IDC_PREFORM, OnCheck) - ON_BN_CLICKED(IDC_CHECK_SEPARATE_LETTERS, OnCheck) - ON_EN_CHANGE(IDC_EDIT_SEPARATOR1, OnChangeSeparator) - ON_EN_CHANGE(IDC_EDIT_SEPARATOR2, OnChangeSeparator) - ON_BN_CLICKED(IDC_CHECK_SEPARATE_LETTERS_ONLY_IN_PAIRS, OnCheck) - ON_BN_CLICKED(IDC_CHECK_IGNORE_DOUBLE_CHARACTERS_IN_KEY, OnCheck) + ON_EN_UPDATE(IDC_KEYENTER, &CDlgKeyPlayfair::OnUpdateEdit1) + ON_BN_CLICKED(IDC_RADIO3, &CDlgKeyPlayfair::OnSechs) + ON_BN_CLICKED(IDC_RADIO4, &CDlgKeyPlayfair::OnSechs) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeyPlayfair::OnDecrypt) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeyPlayfair::OnPasteKey) + ON_BN_CLICKED(IDOK, &CDlgKeyPlayfair::OnEncrypt) + ON_BN_CLICKED(IDC_CHECK1, &CDlgKeyPlayfair::OnCheck) + ON_BN_CLICKED(IDC_PREFORM, &CDlgKeyPlayfair::OnCheck) + ON_BN_CLICKED(IDC_CHECK_SEPARATE_LETTERS, &CDlgKeyPlayfair::OnCheck) + ON_EN_CHANGE(IDC_EDIT_SEPARATOR1, &CDlgKeyPlayfair::OnChangeSeparator) + ON_EN_CHANGE(IDC_EDIT_SEPARATOR2, &CDlgKeyPlayfair::OnChangeSeparator) + ON_BN_CLICKED(IDC_CHECK_SEPARATE_LETTERS_ONLY_IN_PAIRS, &CDlgKeyPlayfair::OnCheck) + ON_BN_CLICKED(IDC_CHECK_IGNORE_DOUBLE_CHARACTERS_IN_KEY, &CDlgKeyPlayfair::OnCheck) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyPlayfair.h b/CrypTool/DlgKeyPlayfair.h index 76087a394..416578ccc 100644 --- a/CrypTool/DlgKeyPlayfair.h +++ b/CrypTool/DlgKeyPlayfair.h @@ -29,7 +29,7 @@ // Copyright 1998-2001 Deutsche Bank AG, Frankfurt am Main ////////////////////////////////////////////////////////////////// -#include +#include "PlayfairAnalysis.h" #include "ToolTipButton.h" // Dlg_PlayfairKey.h : Header-Datei diff --git a/CrypTool/DlgKeySubstitution.cpp b/CrypTool/DlgKeySubstitution.cpp index 19a19cfc7..c0bfac5a8 100644 --- a/CrypTool/DlgKeySubstitution.cpp +++ b/CrypTool/DlgKeySubstitution.cpp @@ -65,10 +65,10 @@ void CDlgKeySubstitution::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeySubstitution, CDialog) //{{AFX_MSG_MAP(CDlgKeySubstitution) - ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit1) - ON_BN_CLICKED(IDC_BUTTON1, OnDecrypt) - ON_BN_CLICKED(IDOK, OnEncrypt) - ON_BN_CLICKED(IDC_BUTTON2, OnPasteKey) + ON_EN_CHANGE(IDC_EDIT1, &CDlgKeySubstitution::OnChangeEdit1) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgKeySubstitution::OnDecrypt) + ON_BN_CLICKED(IDOK, &CDlgKeySubstitution::OnEncrypt) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgKeySubstitution::OnPasteKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgKeyVigenere.cpp b/CrypTool/DlgKeyVigenere.cpp index f00bb8c71..ab771c572 100644 --- a/CrypTool/DlgKeyVigenere.cpp +++ b/CrypTool/DlgKeyVigenere.cpp @@ -58,7 +58,7 @@ void CDlgKeyVigenereAnalyisis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgKeyVigenereAnalyisis, CDialog) //{{AFX_MSG_MAP(CDlgKeyVigenereAnalyisis) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1) + ON_EN_UPDATE(IDC_EDIT1, &CDlgKeyVigenereAnalyisis::OnUpdateEdit1) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgLengthOfANumber.cpp b/CrypTool/DlgLengthOfANumber.cpp index 265077eac..b6122513b 100644 --- a/CrypTool/DlgLengthOfANumber.cpp +++ b/CrypTool/DlgLengthOfANumber.cpp @@ -71,11 +71,11 @@ BOOL CDlgLengthOfANumber::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgLengthOfANumber, CDialog) - ON_BN_CLICKED(IDC_RADIO_BINARY, updateNumberRepresentation) - ON_BN_CLICKED(IDC_RADIO_OCTAL, updateNumberRepresentation) - ON_BN_CLICKED(IDC_RADIO_DECIMAL, updateNumberRepresentation) - ON_BN_CLICKED(IDC_RADIO_HEXADECIMAL, updateNumberRepresentation) - ON_EN_CHANGE(IDC_EDIT_NUMBER, updateNumber) + ON_BN_CLICKED(IDC_RADIO_BINARY, &CDlgLengthOfANumber::updateNumberRepresentation) + ON_BN_CLICKED(IDC_RADIO_OCTAL, &CDlgLengthOfANumber::updateNumberRepresentation) + ON_BN_CLICKED(IDC_RADIO_DECIMAL, &CDlgLengthOfANumber::updateNumberRepresentation) + ON_BN_CLICKED(IDC_RADIO_HEXADECIMAL, &CDlgLengthOfANumber::updateNumberRepresentation) + ON_EN_CHANGE(IDC_EDIT_NUMBER, &CDlgLengthOfANumber::updateNumber) END_MESSAGE_MAP() void CDlgLengthOfANumber::updateNumberRepresentation() diff --git a/CrypTool/DlgMac.cpp b/CrypTool/DlgMac.cpp index 51c9d8f21..b2e002d04 100644 --- a/CrypTool/DlgMac.cpp +++ b/CrypTool/DlgMac.cpp @@ -24,7 +24,7 @@ #include "SecudeCryptography.h" #include "CrypToolTools.h" #include "FileTools.h" -#include ".\dlgmac.h" +#include "DlgMac.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -81,21 +81,21 @@ void CDlgMac::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgMac, CDialog) //{{AFX_MSG_MAP(CDlgMac) - ON_BN_CLICKED(IDC_RADIO11, OnBUTTONSecondKey) - ON_EN_CHANGE(IDC_SHOW_TEXT, OnEditText) - ON_EN_CHANGE(IDC_EDIT_KEY, OnEditKey) - ON_BN_CLICKED(IDC_RADIO7, OnBUTTONFront) - ON_BN_CLICKED(IDC_RADIO8, OnBUTTONBack) - ON_BN_CLICKED(IDC_RADIO9, OnBUTTONBoth) - ON_BN_CLICKED(IDC_RADIO10, OnBUTTONDouble) - ON_EN_CHANGE(IDC_EDIT_KEY2, OnEditSecondKey) - ON_BN_CLICKED(IDOK, OnOK) - ON_BN_CLICKED(IDC_RADIO1, OnBUTTONHashFunction) - ON_BN_CLICKED(IDC_RADIO2, OnBUTTONHashFunction) - ON_BN_CLICKED(IDC_RADIO3, OnBUTTONHashFunction) - ON_BN_CLICKED(IDC_RADIO4, OnBUTTONHashFunction) - ON_BN_CLICKED(IDC_RADIO5, OnBUTTONHashFunction) - ON_BN_CLICKED(IDC_RADIO6, OnBUTTONHashFunction) + ON_BN_CLICKED(IDC_RADIO11, &CDlgMac::OnBUTTONSecondKey) + ON_EN_CHANGE(IDC_SHOW_TEXT, &CDlgMac::OnEditText) + ON_EN_CHANGE(IDC_EDIT_KEY, &CDlgMac::OnEditKey) + ON_BN_CLICKED(IDC_RADIO7, &CDlgMac::OnBUTTONFront) + ON_BN_CLICKED(IDC_RADIO8, &CDlgMac::OnBUTTONBack) + ON_BN_CLICKED(IDC_RADIO9, &CDlgMac::OnBUTTONBoth) + ON_BN_CLICKED(IDC_RADIO10, &CDlgMac::OnBUTTONDouble) + ON_EN_CHANGE(IDC_EDIT_KEY2, &CDlgMac::OnEditSecondKey) + ON_BN_CLICKED(IDOK, &CDlgMac::OnOK) + ON_BN_CLICKED(IDC_RADIO1, &CDlgMac::OnBUTTONHashFunction) + ON_BN_CLICKED(IDC_RADIO2, &CDlgMac::OnBUTTONHashFunction) + ON_BN_CLICKED(IDC_RADIO3, &CDlgMac::OnBUTTONHashFunction) + ON_BN_CLICKED(IDC_RADIO4, &CDlgMac::OnBUTTONHashFunction) + ON_BN_CLICKED(IDC_RADIO5, &CDlgMac::OnBUTTONHashFunction) + ON_BN_CLICKED(IDC_RADIO6, &CDlgMac::OnBUTTONHashFunction) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgManualSubstAnalysis.cpp b/CrypTool/DlgManualSubstAnalysis.cpp index 5ac7e5f27..d2fcd7bef 100644 --- a/CrypTool/DlgManualSubstAnalysis.cpp +++ b/CrypTool/DlgManualSubstAnalysis.cpp @@ -159,37 +159,37 @@ void CDlgManualSubstAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgManualSubstAnalysis, CDialog) //{{AFX_MSG_MAP(CDlgManualSubstAnalysis) - ON_BN_CLICKED(IDC_BUTTON2, OnButton2) - ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit1) - ON_EN_CHANGE(IDC_EDIT2, OnChangeEdit2) - ON_EN_CHANGE(IDC_EDIT3, OnChangeEdit3) - ON_EN_CHANGE(IDC_EDIT4, OnChangeEdit4) - ON_EN_CHANGE(IDC_EDIT5, OnChangeEdit5) - ON_EN_CHANGE(IDC_EDIT6, OnChangeEdit6) - ON_EN_CHANGE(IDC_EDIT7, OnChangeEdit7) - ON_EN_CHANGE(IDC_EDIT8, OnChangeEdit8) - ON_EN_CHANGE(IDC_EDIT9, OnChangeEdit9) - ON_EN_CHANGE(IDC_EDIT10, OnChangeEdit10) - ON_EN_CHANGE(IDC_EDIT11, OnChangeEdit11) - ON_EN_CHANGE(IDC_EDIT12, OnChangeEdit12) - ON_EN_CHANGE(IDC_EDIT13, OnChangeEdit13) - ON_EN_CHANGE(IDC_EDIT14, OnChangeEdit14) - ON_EN_CHANGE(IDC_EDIT15, OnChangeEdit15) - ON_EN_CHANGE(IDC_EDIT16, OnChangeEdit16) - ON_EN_CHANGE(IDC_EDIT17, OnChangeEdit17) - ON_EN_CHANGE(IDC_EDIT18, OnChangeEdit18) - ON_EN_CHANGE(IDC_EDIT19, OnChangeEdit19) - ON_EN_CHANGE(IDC_EDIT20, OnChangeEdit20) - ON_EN_CHANGE(IDC_EDIT21, OnChangeEdit21) - ON_EN_CHANGE(IDC_EDIT22, OnChangeEdit22) - ON_EN_CHANGE(IDC_EDIT23, OnChangeEdit23) - ON_EN_CHANGE(IDC_EDIT24, OnChangeEdit24) - ON_EN_CHANGE(IDC_EDIT25, OnChangeEdit25) - ON_EN_CHANGE(IDC_EDIT26, OnChangeEdit26) - ON_EN_CHANGE(IDC_EDIT27, OnChangeEdit27) - ON_BN_CLICKED(IDC_UNDO_, OnUndo) - ON_BN_CLICKED(IDC_BUTTON1, OnCopyKey) - ON_BN_CLICKED(IDC_REDO_, OnRedo) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgManualSubstAnalysis::OnButton2) + ON_EN_CHANGE(IDC_EDIT1, &CDlgManualSubstAnalysis::OnChangeEdit1) + ON_EN_CHANGE(IDC_EDIT2, &CDlgManualSubstAnalysis::OnChangeEdit2) + ON_EN_CHANGE(IDC_EDIT3, &CDlgManualSubstAnalysis::OnChangeEdit3) + ON_EN_CHANGE(IDC_EDIT4, &CDlgManualSubstAnalysis::OnChangeEdit4) + ON_EN_CHANGE(IDC_EDIT5, &CDlgManualSubstAnalysis::OnChangeEdit5) + ON_EN_CHANGE(IDC_EDIT6, &CDlgManualSubstAnalysis::OnChangeEdit6) + ON_EN_CHANGE(IDC_EDIT7, &CDlgManualSubstAnalysis::OnChangeEdit7) + ON_EN_CHANGE(IDC_EDIT8, &CDlgManualSubstAnalysis::OnChangeEdit8) + ON_EN_CHANGE(IDC_EDIT9, &CDlgManualSubstAnalysis::OnChangeEdit9) + ON_EN_CHANGE(IDC_EDIT10, &CDlgManualSubstAnalysis::OnChangeEdit10) + ON_EN_CHANGE(IDC_EDIT11, &CDlgManualSubstAnalysis::OnChangeEdit11) + ON_EN_CHANGE(IDC_EDIT12, &CDlgManualSubstAnalysis::OnChangeEdit12) + ON_EN_CHANGE(IDC_EDIT13, &CDlgManualSubstAnalysis::OnChangeEdit13) + ON_EN_CHANGE(IDC_EDIT14, &CDlgManualSubstAnalysis::OnChangeEdit14) + ON_EN_CHANGE(IDC_EDIT15, &CDlgManualSubstAnalysis::OnChangeEdit15) + ON_EN_CHANGE(IDC_EDIT16, &CDlgManualSubstAnalysis::OnChangeEdit16) + ON_EN_CHANGE(IDC_EDIT17, &CDlgManualSubstAnalysis::OnChangeEdit17) + ON_EN_CHANGE(IDC_EDIT18, &CDlgManualSubstAnalysis::OnChangeEdit18) + ON_EN_CHANGE(IDC_EDIT19, &CDlgManualSubstAnalysis::OnChangeEdit19) + ON_EN_CHANGE(IDC_EDIT20, &CDlgManualSubstAnalysis::OnChangeEdit20) + ON_EN_CHANGE(IDC_EDIT21, &CDlgManualSubstAnalysis::OnChangeEdit21) + ON_EN_CHANGE(IDC_EDIT22, &CDlgManualSubstAnalysis::OnChangeEdit22) + ON_EN_CHANGE(IDC_EDIT23, &CDlgManualSubstAnalysis::OnChangeEdit23) + ON_EN_CHANGE(IDC_EDIT24, &CDlgManualSubstAnalysis::OnChangeEdit24) + ON_EN_CHANGE(IDC_EDIT25, &CDlgManualSubstAnalysis::OnChangeEdit25) + ON_EN_CHANGE(IDC_EDIT26, &CDlgManualSubstAnalysis::OnChangeEdit26) + ON_EN_CHANGE(IDC_EDIT27, &CDlgManualSubstAnalysis::OnChangeEdit27) + ON_BN_CLICKED(IDC_UNDO_, &CDlgManualSubstAnalysis::OnUndo) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgManualSubstAnalysis::OnCopyKey) + ON_BN_CLICKED(IDC_REDO_, &CDlgManualSubstAnalysis::OnRedo) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgMonSubst.cpp b/CrypTool/DlgMonSubst.cpp index c458f3e2c..fa037e06e 100644 --- a/CrypTool/DlgMonSubst.cpp +++ b/CrypTool/DlgMonSubst.cpp @@ -22,10 +22,10 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "DlgMonSubst.h" #include "KeyRepository.h" -#include ".\dlgmonsubst.h" +#include "DlgMonSubst.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -69,14 +69,14 @@ void CDlgMonSubst::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgMonSubst, CDialog) //{{AFX_MSG_MAP(CDlgMonSubst) - ON_EN_CHANGE(IDC_KEY, ComputeSubstKeyMapping) - ON_EN_CHANGE(IDC_KEY_OFFSET, OnChangedKeyOffset) - ON_BN_CLICKED(IDC_PASTE_KEY, OnPasteKey) - ON_BN_CLICKED(ID_ENCRYPT, OnEncrypt) - ON_BN_CLICKED(ID_DECRYPT, OnDecrypt) - ON_BN_CLICKED(IDC_RADIO1, OnBnClickedRadioSubstFillAscendingOrder) - ON_BN_CLICKED(IDC_RADIO2, OnBnClickedRadioSubstFillDescendingOrder) - ON_BN_CLICKED(IDC_RADIO3, OnBnClickedRadioAtbash) + ON_EN_CHANGE(IDC_KEY, &CDlgMonSubst::ComputeSubstKeyMapping) + ON_EN_CHANGE(IDC_KEY_OFFSET, &CDlgMonSubst::OnChangedKeyOffset) + ON_BN_CLICKED(IDC_PASTE_KEY, &CDlgMonSubst::OnPasteKey) + ON_BN_CLICKED(ID_ENCRYPT, &CDlgMonSubst::OnEncrypt) + ON_BN_CLICKED(ID_DECRYPT, &CDlgMonSubst::OnDecrypt) + ON_BN_CLICKED(IDC_RADIO1, &CDlgMonSubst::OnBnClickedRadioSubstFillAscendingOrder) + ON_BN_CLICKED(IDC_RADIO2, &CDlgMonSubst::OnBnClickedRadioSubstFillDescendingOrder) + ON_BN_CLICKED(IDC_RADIO3, &CDlgMonSubst::OnBnClickedRadioAtbash) //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, &CDlgMonSubst::OnBnClickedButtonTextoptions) END_MESSAGE_MAP() diff --git a/CrypTool/DlgNGramAnalysis.cpp b/CrypTool/DlgNGramAnalysis.cpp index 1d56f71b9..3aeac90a0 100644 --- a/CrypTool/DlgNGramAnalysis.cpp +++ b/CrypTool/DlgNGramAnalysis.cpp @@ -80,20 +80,20 @@ void CDlgNGramAnaylsis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgNGramAnaylsis, CDialog) //{{AFX_MSG_MAP(CDlgNGramAnaylsis) - ON_BN_CLICKED(IDC_RADIO1, OnEvalNGram) - ON_BN_CLICKED(IDC_RADIO2, OnEvalNGram) - ON_BN_CLICKED(IDC_RADIO3, OnEvalNGram) - ON_BN_CLICKED(IDC_RADIO4, OnEvalNGram) - ON_BN_CLICKED(IDC_BUTTON2, OnEvalNGram) - ON_BN_CLICKED(IDOK, OnSaveNGramList) - ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, OnTextOptions) + ON_BN_CLICKED(IDC_RADIO1, &CDlgNGramAnaylsis::OnEvalNGram) + ON_BN_CLICKED(IDC_RADIO2, &CDlgNGramAnaylsis::OnEvalNGram) + ON_BN_CLICKED(IDC_RADIO3, &CDlgNGramAnaylsis::OnEvalNGram) + ON_BN_CLICKED(IDC_RADIO4, &CDlgNGramAnaylsis::OnEvalNGram) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgNGramAnaylsis::OnEvalNGram) + ON_BN_CLICKED(IDOK, &CDlgNGramAnaylsis::OnSaveNGramList) + ON_BN_CLICKED(IDC_BUTTON_TEXTOPTIONS, &CDlgNGramAnaylsis::OnTextOptions) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // Behandlungsroutinen für Nachrichten CDlgNGramAnaylsis -int CDlgNGramAnaylsis::DoModal() +INT_PTR CDlgNGramAnaylsis::DoModal() { // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen @@ -563,7 +563,7 @@ CNGram::CNGram(const unsigned long fileSize, const unsigned short _N, const unsi AlphabetSize = alphabetSize; if ( N <= 2 ) { - unsigned long Sz = unsigned long(pow((long)AlphabetSize, (int)N)); + unsigned long Sz = (unsigned long)(pow((long)AlphabetSize, (int)N)); HashTableSize = min(Sz+Sz/8, Size+Size/8); } else diff --git a/CrypTool/DlgNGramAnalysis.h b/CrypTool/DlgNGramAnalysis.h index 5cb9babff..d0811e23b 100644 --- a/CrypTool/DlgNGramAnalysis.h +++ b/CrypTool/DlgNGramAnalysis.h @@ -79,7 +79,7 @@ class CDlgNGramAnaylsis : public CDialog // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CDlgNGramAnaylsis) public: - virtual int DoModal(); + virtual INT_PTR DoModal(); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL diff --git a/CrypTool/DlgOptionsAnalysis.cpp b/CrypTool/DlgOptionsAnalysis.cpp index 1f59fb2df..c378da8c6 100644 --- a/CrypTool/DlgOptionsAnalysis.cpp +++ b/CrypTool/DlgOptionsAnalysis.cpp @@ -93,10 +93,10 @@ void CDlgOptionsAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgOptionsAnalysis, CDialog) //{{AFX_MSG_MAP(CDlgOptionsAnalysis) - ON_BN_CLICKED(IDC_BUTTON_SEARCH_DICTIONARY_FILE, OnButtonSearchDictionaryFile) - ON_BN_CLICKED(IDC_BUTTON_SEARCH_DIGRAMS_FILE, OnButtonSearchDigramsFile) - ON_BN_CLICKED(IDC_BUTTON_SEARCH_TRIGRAMS_FILE, OnButtonSearchTrigramsFile) - ON_BN_CLICKED(IDC_BUTTON_RESTORE_STANDARD, OnBnClickedButtonRestoreStandard) + ON_BN_CLICKED(IDC_BUTTON_SEARCH_DICTIONARY_FILE, &CDlgOptionsAnalysis::OnButtonSearchDictionaryFile) + ON_BN_CLICKED(IDC_BUTTON_SEARCH_DIGRAMS_FILE, &CDlgOptionsAnalysis::OnButtonSearchDigramsFile) + ON_BN_CLICKED(IDC_BUTTON_SEARCH_TRIGRAMS_FILE, &CDlgOptionsAnalysis::OnButtonSearchTrigramsFile) + ON_BN_CLICKED(IDC_BUTTON_RESTORE_STANDARD, &CDlgOptionsAnalysis::OnBnClickedButtonRestoreStandard) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgOptionsAutoSubstitutionAnalysis.cpp b/CrypTool/DlgOptionsAutoSubstitutionAnalysis.cpp index 51a8cc261..6d8b19626 100644 --- a/CrypTool/DlgOptionsAutoSubstitutionAnalysis.cpp +++ b/CrypTool/DlgOptionsAutoSubstitutionAnalysis.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "DlgOptionsAutoSubstitutionAnalysis.h" #ifdef _DEBUG diff --git a/CrypTool/DlgOptionsRSADemo.cpp b/CrypTool/DlgOptionsRSADemo.cpp index 4159103e5..c5e6cae36 100644 --- a/CrypTool/DlgOptionsRSADemo.cpp +++ b/CrypTool/DlgOptionsRSADemo.cpp @@ -75,17 +75,17 @@ void CDlgOptionsRSADemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgOptionsRSADemo, CDialog) //{{AFX_MSG_MAP(CDlgOptionsRSADemo) - ON_BN_CLICKED(IDC_RADIO7, OnSelectRSA) - ON_BN_CLICKED(IDC_RADIO8, OnSelectDialougeOfSisters) - ON_EN_UPDATE(IDC_EDIT1, OnChangeAlphabet) - ON_BN_CLICKED(IDC_RADIO1, OnSelectASCII) - ON_BN_CLICKED(IDC_RADIO2, OnSelectAlphabet) - ON_BN_CLICKED(IDC_RADIO10, OnCodingNumberSystem) - ON_BN_CLICKED(IDC_RADIO9, OnCodingBAdic) - ON_BN_CLICKED(IDC_RADIO3, OnBase10) - ON_BN_CLICKED(IDC_RADIO4, OnBase2) - ON_BN_CLICKED(IDC_RADIO5, OnBase8) - ON_BN_CLICKED(IDC_RADIO6, OnBase16) + ON_BN_CLICKED(IDC_RADIO7, &CDlgOptionsRSADemo::OnSelectRSA) + ON_BN_CLICKED(IDC_RADIO8, &CDlgOptionsRSADemo::OnSelectDialougeOfSisters) + ON_EN_UPDATE(IDC_EDIT1, &CDlgOptionsRSADemo::OnChangeAlphabet) + ON_BN_CLICKED(IDC_RADIO1, &CDlgOptionsRSADemo::OnSelectASCII) + ON_BN_CLICKED(IDC_RADIO2, &CDlgOptionsRSADemo::OnSelectAlphabet) + ON_BN_CLICKED(IDC_RADIO10, &CDlgOptionsRSADemo::OnCodingNumberSystem) + ON_BN_CLICKED(IDC_RADIO9, &CDlgOptionsRSADemo::OnCodingBAdic) + ON_BN_CLICKED(IDC_RADIO3, &CDlgOptionsRSADemo::OnBase10) + ON_BN_CLICKED(IDC_RADIO4, &CDlgOptionsRSADemo::OnBase2) + ON_BN_CLICKED(IDC_RADIO5, &CDlgOptionsRSADemo::OnBase8) + ON_BN_CLICKED(IDC_RADIO6, &CDlgOptionsRSADemo::OnBase16) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgOptionsSignatureAttack.cpp b/CrypTool/DlgOptionsSignatureAttack.cpp index aa3c79e7f..c86a3ad96 100644 --- a/CrypTool/DlgOptionsSignatureAttack.cpp +++ b/CrypTool/DlgOptionsSignatureAttack.cpp @@ -72,18 +72,18 @@ void CDlgOptionsSignatureAttack::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgOptionsSignatureAttack, CDialog) //{{AFX_MSG_MAP(CDlgOptionsSignatureAttack) - ON_BN_CLICKED(IDC_RADIO1, OnMD2) - ON_BN_CLICKED(IDC_RADIO2, OnMD4) - ON_BN_CLICKED(IDC_RADIO3, OnMD5) - ON_BN_CLICKED(IDC_RADIO4, OnSHA) - ON_BN_CLICKED(IDC_RADIO5, OnSHA_1) - ON_BN_CLICKED(IDC_RADIO6, OnRIPEMD_160) - ON_BN_CLICKED(IDC_BUTTON1, OnResetToDefault) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1) - ON_BN_CLICKED(IDC_RADIO7, OnRadio7) - ON_BN_CLICKED(IDC_RADIO8, OnRadio8) - ON_BN_CLICKED(IDC_RADIO9, OnRadio9) - ON_BN_CLICKED(IDC_RADIO10, OnRadio10) + ON_BN_CLICKED(IDC_RADIO1, &CDlgOptionsSignatureAttack::OnMD2) + ON_BN_CLICKED(IDC_RADIO2, &CDlgOptionsSignatureAttack::OnMD4) + ON_BN_CLICKED(IDC_RADIO3, &CDlgOptionsSignatureAttack::OnMD5) + ON_BN_CLICKED(IDC_RADIO4, &CDlgOptionsSignatureAttack::OnSHA) + ON_BN_CLICKED(IDC_RADIO5, &CDlgOptionsSignatureAttack::OnSHA_1) + ON_BN_CLICKED(IDC_RADIO6, &CDlgOptionsSignatureAttack::OnRIPEMD_160) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgOptionsSignatureAttack::OnResetToDefault) + ON_EN_UPDATE(IDC_EDIT1, &CDlgOptionsSignatureAttack::OnUpdateEdit1) + ON_BN_CLICKED(IDC_RADIO7, &CDlgOptionsSignatureAttack::OnRadio7) + ON_BN_CLICKED(IDC_RADIO8, &CDlgOptionsSignatureAttack::OnRadio8) + ON_BN_CLICKED(IDC_RADIO9, &CDlgOptionsSignatureAttack::OnRadio9) + ON_BN_CLICKED(IDC_RADIO10, &CDlgOptionsSignatureAttack::OnRadio10) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgOptionsStartoptions.cpp b/CrypTool/DlgOptionsStartoptions.cpp index d20ff5584..6ee3ac23c 100644 --- a/CrypTool/DlgOptionsStartoptions.cpp +++ b/CrypTool/DlgOptionsStartoptions.cpp @@ -97,8 +97,8 @@ void CDlgOptionsStartoptions::OnOK() UpdateData(true); if ( CT_OPEN_REGISTRY_SETTINGS( KEY_WRITE, IDS_REGISTRY_SETTINGS_OPTIONS, "StartingOptions" ) == ERROR_SUCCESS ) { - CT_WRITE_REGISTRY(unsigned long(!m_how_to_start), "NoTipps"); - CT_WRITE_REGISTRY(unsigned long(m_sample_text_file), "SampleTextFile"); + CT_WRITE_REGISTRY((unsigned long)(!m_how_to_start), "NoTipps"); + CT_WRITE_REGISTRY((unsigned long)(m_sample_text_file), "SampleTextFile"); CT_CLOSE_REGISTRY(); } diff --git a/CrypTool/DlgOptionsSubstitutionAnalysis.cpp b/CrypTool/DlgOptionsSubstitutionAnalysis.cpp index 6e2218b5b..94cdeff1c 100644 --- a/CrypTool/DlgOptionsSubstitutionAnalysis.cpp +++ b/CrypTool/DlgOptionsSubstitutionAnalysis.cpp @@ -74,15 +74,15 @@ void CDlgOptionsSubstitutionAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgOptionsSubstitutionAnalysis, CDialog) - ON_BN_CLICKED(IDC_RADIO_ANALYSIS_AUTOMATIC, OnRadioAnalysisAutomatic) - ON_BN_CLICKED(IDC_RADIO_ANALYSIS_MANUAL, OnRadioAnalysisManual) - ON_BN_CLICKED(IDC_RADIO_ANALYSIS_AUTOMATIC_GERMAN, OnRadioAnalysisAutomaticGerman) - ON_BN_CLICKED(IDC_RADIO_ANALYSIS_AUTOMATIC_ENGLISH, OnRadioAnalysisAutomaticEnglish) - ON_BN_CLICKED(IDC_BUTTON_SELECT_WORDLIST_GERMAN, OnButtonSelectWordlistGerman) - ON_BN_CLICKED(IDC_BUTTON_SELECT_WORDLIST_ENGLISH, OnButtonSelectWordlistEnglish) - ON_BN_CLICKED(IDC_CHECK_ANALYSIS_AUTOMATIC_OPTION1, OnCheckAnalysisAutomaticOption1) - ON_BN_CLICKED(IDC_CHECK_ANALYSIS_AUTOMATIC_OPTION2, OnCheckAnalysisAutomaticOption2) - ON_BN_CLICKED(IDC_CHECK_ANALYSIS_MANUAL_OPTION1, OnCheckAnalysisManualOption1) + ON_BN_CLICKED(IDC_RADIO_ANALYSIS_AUTOMATIC, &CDlgOptionsSubstitutionAnalysis::OnRadioAnalysisAutomatic) + ON_BN_CLICKED(IDC_RADIO_ANALYSIS_MANUAL, &CDlgOptionsSubstitutionAnalysis::OnRadioAnalysisManual) + ON_BN_CLICKED(IDC_RADIO_ANALYSIS_AUTOMATIC_GERMAN, &CDlgOptionsSubstitutionAnalysis::OnRadioAnalysisAutomaticGerman) + ON_BN_CLICKED(IDC_RADIO_ANALYSIS_AUTOMATIC_ENGLISH, &CDlgOptionsSubstitutionAnalysis::OnRadioAnalysisAutomaticEnglish) + ON_BN_CLICKED(IDC_BUTTON_SELECT_WORDLIST_GERMAN, &CDlgOptionsSubstitutionAnalysis::OnButtonSelectWordlistGerman) + ON_BN_CLICKED(IDC_BUTTON_SELECT_WORDLIST_ENGLISH, &CDlgOptionsSubstitutionAnalysis::OnButtonSelectWordlistEnglish) + ON_BN_CLICKED(IDC_CHECK_ANALYSIS_AUTOMATIC_OPTION1, &CDlgOptionsSubstitutionAnalysis::OnCheckAnalysisAutomaticOption1) + ON_BN_CLICKED(IDC_CHECK_ANALYSIS_AUTOMATIC_OPTION2, &CDlgOptionsSubstitutionAnalysis::OnCheckAnalysisAutomaticOption2) + ON_BN_CLICKED(IDC_CHECK_ANALYSIS_MANUAL_OPTION1, &CDlgOptionsSubstitutionAnalysis::OnCheckAnalysisManualOption1) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -119,13 +119,13 @@ BOOL CDlgOptionsSubstitutionAnalysis::OnInitDialog() CFileStatus wordlistFileStatus; if(!CFile::GetStatus(m_editWordlistGerman, wordlistFileStatus)) { CString message; - message.Format(IDS_STRING_SUBSTITUTION_ANALYSIS_MISSING_WORDLIST_GERMAN, m_editWordlistGerman); + message.Format(IDS_STRING_SUBSTITUTION_ANALYSIS_MISSING_WORDLIST_GERMAN, (LPCTSTR)m_editWordlistGerman); AfxMessageBox(message, MB_ICONWARNING); } if(!CFile::GetStatus(m_editWordlistEnglish, wordlistFileStatus)) { CString message; - message.Format(IDS_STRING_SUBSTITUTION_ANALYSIS_MISSING_WORDLIST_ENGLISH, m_editWordlistEnglish); + message.Format(IDS_STRING_SUBSTITUTION_ANALYSIS_MISSING_WORDLIST_ENGLISH, (LPCTSTR)m_editWordlistEnglish); AfxMessageBox(message, MB_ICONWARNING); } diff --git a/CrypTool/DlgPINAccess.cpp b/CrypTool/DlgPINAccess.cpp index 8acdc383d..6c4646a70 100644 --- a/CrypTool/DlgPINAccess.cpp +++ b/CrypTool/DlgPINAccess.cpp @@ -72,7 +72,7 @@ END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // Behandlungsroutinen für Nachrichten CDlgPINAccess -int CDlgPINAccess::DoModal() +INT_PTR CDlgPINAccess::DoModal() { // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen @@ -103,7 +103,7 @@ BOOL CDlgPINAccess::OnInitDialog() m_ModusInfoBox = (CString) pc_str; LoadString(AfxGetInstanceHandle(),IDS_STRING_REQ_DEL_KEYDATA,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, UserKeyId); + sprintf(pc_str1, pc_str, (LPCTSTR)UserKeyId); m_InfoBox = (CString) pc_str1; } else @@ -114,7 +114,7 @@ BOOL CDlgPINAccess::OnInitDialog() m_ModusInfoBox = (CString) pc_str; LoadString(AfxGetInstanceHandle(),IDS_STRING_REQUEST_FOR_PIN,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, UserKeyId); + sprintf(pc_str1, pc_str, (LPCTSTR)UserKeyId); m_InfoBox = (CString) pc_str1; } diff --git a/CrypTool/DlgPINAccess.h b/CrypTool/DlgPINAccess.h index 26c70a789..63d867a47 100644 --- a/CrypTool/DlgPINAccess.h +++ b/CrypTool/DlgPINAccess.h @@ -50,7 +50,7 @@ class CDlgPINAccess : public CDialog // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CDlgPINAccess) public: - virtual int DoModal(); + virtual INT_PTR DoModal(); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL diff --git a/CrypTool/DlgPasswordEntropy.cpp b/CrypTool/DlgPasswordEntropy.cpp index 6168ddac4..48d3a9f18 100644 --- a/CrypTool/DlgPasswordEntropy.cpp +++ b/CrypTool/DlgPasswordEntropy.cpp @@ -79,15 +79,15 @@ BOOL CDlgPasswordEntropy::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgPasswordEntropy, CDialog) - ON_BN_CLICKED(ID_GENERATEPASSWORD, OnBnClickedGeneratepassword) - ON_EN_CHANGE(IDC_EDIT_PASSWORDBITLENGTH, EditPasswordBitLengthChanged) - ON_EN_CHANGE(IDC_EDIT_PASSWORDALPHABET, EditPasswordAlphabetChanged) - ON_BN_CLICKED(IDC_CHECK_USECRYPTOOLALPHABET, CheckBoxesAlphabetChanged) - ON_BN_CLICKED(IDC_CHECK_USENONCONFUSABLECHARACTERS_WRITTENTRANSMISSION, CheckBoxesAlphabetChanged) - ON_BN_CLICKED(IDC_CHECK_USENONCONFUSABLECHARACTERS_TELEPHONICTRANSMISSION, CheckBoxesAlphabetChanged) - ON_BN_CLICKED(IDC_CHECK_USEWLANALPHABET, CheckBoxesAlphabetChanged) - ON_BN_CLICKED(ID_TEXTOPTIONS, OnBnClickedTextoptions) - ON_BN_CLICKED(ID_MEASUREPASSWORDQUALITY, OnBnClickedMeasurepasswordquality) + ON_BN_CLICKED(ID_GENERATEPASSWORD, &CDlgPasswordEntropy::OnBnClickedGeneratepassword) + ON_EN_CHANGE(IDC_EDIT_PASSWORDBITLENGTH, &CDlgPasswordEntropy::EditPasswordBitLengthChanged) + ON_EN_CHANGE(IDC_EDIT_PASSWORDALPHABET, &CDlgPasswordEntropy::EditPasswordAlphabetChanged) + ON_BN_CLICKED(IDC_CHECK_USECRYPTOOLALPHABET, &CDlgPasswordEntropy::CheckBoxesAlphabetChanged) + ON_BN_CLICKED(IDC_CHECK_USENONCONFUSABLECHARACTERS_WRITTENTRANSMISSION, &CDlgPasswordEntropy::CheckBoxesAlphabetChanged) + ON_BN_CLICKED(IDC_CHECK_USENONCONFUSABLECHARACTERS_TELEPHONICTRANSMISSION, &CDlgPasswordEntropy::CheckBoxesAlphabetChanged) + ON_BN_CLICKED(IDC_CHECK_USEWLANALPHABET, &CDlgPasswordEntropy::CheckBoxesAlphabetChanged) + ON_BN_CLICKED(ID_TEXTOPTIONS, &CDlgPasswordEntropy::OnBnClickedTextoptions) + ON_BN_CLICKED(ID_MEASUREPASSWORDQUALITY, &CDlgPasswordEntropy::OnBnClickedMeasurepasswordquality) END_MESSAGE_MAP() diff --git a/CrypTool/DlgPasswordGuidelines.cpp b/CrypTool/DlgPasswordGuidelines.cpp index 28c7215ad..daa722014 100644 --- a/CrypTool/DlgPasswordGuidelines.cpp +++ b/CrypTool/DlgPasswordGuidelines.cpp @@ -24,7 +24,7 @@ #include "CrypToolApp.h" #include "DlgPasswordGuidelines.h" #include "CrypToolTools.h" -#include ".\dlgpasswordguidelines.h" +#include "DlgPasswordGuidelines.h" #include "DialogeMessage.h" CDlgPasswordGuidelines::CDlgPasswordGuidelines(CWnd* pParent /*=NULL*/) @@ -133,8 +133,8 @@ void CDlgPasswordGuidelines::OnBnClickedOk() } BEGIN_MESSAGE_MAP(CDlgPasswordGuidelines, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(ID_DEFAULT, OnBnClickedDefault) + ON_BN_CLICKED(IDOK, &CDlgPasswordGuidelines::OnBnClickedOk) + ON_BN_CLICKED(ID_DEFAULT, &CDlgPasswordGuidelines::OnBnClickedDefault) END_MESSAGE_MAP() void CDlgPasswordGuidelines::OnBnClickedDefault() diff --git a/CrypTool/DlgPasswordQualityMeter.cpp b/CrypTool/DlgPasswordQualityMeter.cpp index 87362ed89..37060d0e3 100644 --- a/CrypTool/DlgPasswordQualityMeter.cpp +++ b/CrypTool/DlgPasswordQualityMeter.cpp @@ -237,9 +237,9 @@ void CDlgPasswordQualityMeter::UpdateUserInterface() } BEGIN_MESSAGE_MAP(CDlgPasswordQualityMeter, CDialog) - ON_EN_CHANGE(IDC_EDIT_PASSWORD, EditPasswordChanged) - ON_BN_CLICKED(IDC_CHECK_SHOWPASSWORD, OnBnClickedCheckShowpassword) - ON_BN_CLICKED(ID_CONFIGURE_PASSWORD_GUIDELINES, OnBnClickedConfigurePasswordGuidelines) + ON_EN_CHANGE(IDC_EDIT_PASSWORD, &CDlgPasswordQualityMeter::EditPasswordChanged) + ON_BN_CLICKED(IDC_CHECK_SHOWPASSWORD, &CDlgPasswordQualityMeter::OnBnClickedCheckShowpassword) + ON_BN_CLICKED(ID_CONFIGURE_PASSWORD_GUIDELINES, &CDlgPasswordQualityMeter::OnBnClickedConfigurePasswordGuidelines) END_MESSAGE_MAP() diff --git a/CrypTool/DlgPeriodicityAnalysis.cpp b/CrypTool/DlgPeriodicityAnalysis.cpp index 321649c13..bdf14d107 100644 --- a/CrypTool/DlgPeriodicityAnalysis.cpp +++ b/CrypTool/DlgPeriodicityAnalysis.cpp @@ -67,7 +67,7 @@ void CDlgPeriodicityAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgPeriodicityAnalysis, CDialog) //{{AFX_MSG_MAP(CDlgPeriodicityAnalysis) - ON_BN_CLICKED(IDOK, OnSaveList) + ON_BN_CLICKED(IDOK, &CDlgPeriodicityAnalysis::OnSaveList) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgPermKey.cpp b/CrypTool/DlgPermKey.cpp index d19b1c64c..4fc59a8eb 100644 --- a/CrypTool/DlgPermKey.cpp +++ b/CrypTool/DlgPermKey.cpp @@ -92,7 +92,7 @@ void CDlgPermKey::OnBnClickedCopyKey() LoadString(AfxGetInstanceHandle(),IDS_CRYPT_PERMUTATION,pc_str,STR_LAENGE_STRING_TABLE); CString strKey; strKey.Format("%s %s%s%i,%i,%i,%i,%i,%i", - m_permKey1, PARAM_TOKEN, (m_dataType) ? TEXT_TOKEN : BINARY_TOKEN, inDir1, permDir1, outDir1, inDir2, permDir2, outDir2); + (LPCTSTR)m_permKey1, PARAM_TOKEN, (m_dataType) ? TEXT_TOKEN : BINARY_TOKEN, inDir1, permDir1, outDir1, inDir2, permDir2, outDir2); CopyKey ( pc_str, strKey ); // TODO: Add your control notification handler code here } diff --git a/CrypTool/DlgPlayfairAnalysis.cpp b/CrypTool/DlgPlayfairAnalysis.cpp index fac5691fe..6b75c2cba 100644 --- a/CrypTool/DlgPlayfairAnalysis.cpp +++ b/CrypTool/DlgPlayfairAnalysis.cpp @@ -217,15 +217,15 @@ void CDlgPlayfairAnalysis::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgPlayfairAnalysis, CDialog) //{{AFX_MSG_MAP(CDlgPlayfairAnalysis) - ON_BN_CLICKED(IDC_CHECK1, OnCheck) - ON_BN_CLICKED(IDC_RAD5, OnSechs) - ON_BN_CLICKED(IDC_RAD6, OnSechs) - ON_BN_CLICKED(IDC_BUTTON5, OnAnalyse) - ON_BN_CLICKED(IDC_BUTTON6, OnSynchronise) - ON_EN_UPDATE(IDC_MYTXT, OnManAnalyse) - ON_EN_UPDATE(IDC_PASSWORD, OnUpdate) + ON_BN_CLICKED(IDC_CHECK1, &CDlgPlayfairAnalysis::OnCheck) + ON_BN_CLICKED(IDC_RAD5, &CDlgPlayfairAnalysis::OnSechs) + ON_BN_CLICKED(IDC_RAD6, &CDlgPlayfairAnalysis::OnSechs) + ON_BN_CLICKED(IDC_BUTTON5, &CDlgPlayfairAnalysis::OnAnalyse) + ON_BN_CLICKED(IDC_BUTTON6, &CDlgPlayfairAnalysis::OnSynchronise) + ON_EN_UPDATE(IDC_MYTXT, &CDlgPlayfairAnalysis::OnManAnalyse) + ON_EN_UPDATE(IDC_PASSWORD, &CDlgPlayfairAnalysis::OnUpdate) ON_WM_HSCROLL() - ON_EN_CHANGE(IDC_MYTXT, OnChangeEditPlaintext) + ON_EN_CHANGE(IDC_MYTXT, &CDlgPlayfairAnalysis::OnChangeEditPlaintext) ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgPrimeTest.cpp b/CrypTool/DlgPrimeTest.cpp index 511eb5c0c..e8b420f91 100644 --- a/CrypTool/DlgPrimeTest.cpp +++ b/CrypTool/DlgPrimeTest.cpp @@ -25,7 +25,7 @@ #include "CrypToolApp.h" #include "DialogeMessage.h" #include "DlgPrimeTest.h" -#include ".\dlgprimetest.h" +#include "DlgPrimeTest.h" #include "DlgFactorisationDemo.h" #include "PrimeTest.h" @@ -128,15 +128,15 @@ void CDlgPrimeTest::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgPrimeTest, CDialog) - ON_BN_CLICKED(IDC_PRIMETEST_BUTTON_TEST, OnBnClickedPrimetestButtonTest) - ON_BN_CLICKED(IDC_PRIMETEST_BUTTON_CANCEL, OnBnClickedPrimetestButtonCancel) - ON_BN_CLICKED(IDC_PRIMETEST_BUTTON_LOADNUMBER, OnBnClickedPrimetestButtonLoadnumber) - ON_EN_CHANGE(IDC_PRIMETEST_EDIT_NUMBER, OnEnChangePrimetestEditNumber) - ON_BN_CLICKED(IDC_PRIMETEST_RADIO_FERMAT, OnBnClickedPrimetestRadio) - ON_BN_CLICKED(IDC_PRIMETEST_RADIO_SOLOVAY, OnBnClickedPrimetestRadio) - ON_BN_CLICKED(IDC_PRIMETEST_RADIO_MILLERRABIN, OnBnClickedPrimetestRadio) - ON_BN_CLICKED(IDC_PRIMETEST_RADIO_AKS, OnBnClickedPrimetestRadio) - ON_BN_CLICKED(IDC_BUTTON_JUMP_TO_FACTORIZATION, CDlgPrimeTest::OnBnClickedButtonJumpToFactorization) + ON_BN_CLICKED(IDC_PRIMETEST_BUTTON_TEST, &CDlgPrimeTest::OnBnClickedPrimetestButtonTest) + ON_BN_CLICKED(IDC_PRIMETEST_BUTTON_CANCEL, &CDlgPrimeTest::OnBnClickedPrimetestButtonCancel) + ON_BN_CLICKED(IDC_PRIMETEST_BUTTON_LOADNUMBER, &CDlgPrimeTest::OnBnClickedPrimetestButtonLoadnumber) + ON_EN_CHANGE(IDC_PRIMETEST_EDIT_NUMBER, &CDlgPrimeTest::OnEnChangePrimetestEditNumber) + ON_BN_CLICKED(IDC_PRIMETEST_RADIO_FERMAT, &CDlgPrimeTest::OnBnClickedPrimetestRadio) + ON_BN_CLICKED(IDC_PRIMETEST_RADIO_SOLOVAY, &CDlgPrimeTest::OnBnClickedPrimetestRadio) + ON_BN_CLICKED(IDC_PRIMETEST_RADIO_MILLERRABIN, &CDlgPrimeTest::OnBnClickedPrimetestRadio) + ON_BN_CLICKED(IDC_PRIMETEST_RADIO_AKS, &CDlgPrimeTest::OnBnClickedPrimetestRadio) + ON_BN_CLICKED(IDC_BUTTON_JUMP_TO_FACTORIZATION, &CDlgPrimeTest::OnBnClickedButtonJumpToFactorization) END_MESSAGE_MAP() diff --git a/CrypTool/DlgPrimesGeneratorDemo.cpp b/CrypTool/DlgPrimesGeneratorDemo.cpp index 735047995..a218c5e07 100644 --- a/CrypTool/DlgPrimesGeneratorDemo.cpp +++ b/CrypTool/DlgPrimesGeneratorDemo.cpp @@ -27,7 +27,7 @@ #include #include "DlgPrimesGeneratorDemo.h" -#include "Keyrepository.h" +#include "KeyRepository.h" #include "DialogeMessage.h" #include "FileTools.h" #include "CrypToolTools.h" @@ -126,17 +126,17 @@ void CDlgPrimesGeneratorDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgPrimesGeneratorDemo, CDialog) //{{AFX_MSG_MAP(CDlgPrimesGeneratorDemo) - ON_BN_CLICKED(IDC_RADIO4, OnRadio4) - ON_BN_CLICKED(IDC_RADIO5, OnRadio5) - ON_BN_CLICKED(IDC_RADIO6, OnRadio6) - ON_BN_CLICKED(IDC_RADIO7, OnRadio7) - ON_BN_CLICKED(IDC_BUTTON_GENERATE, OnButtonGenerate) - ON_BN_CLICKED(IDC_BUTTON_ACCEPT, OnButtonAccept) - ON_BN_CLICKED(IDC_ENDDIALOG, OnEndDialog) - ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit) - ON_EN_UPDATE(IDC_EDIT2, OnUpdateEdit) - ON_EN_UPDATE(IDC_EDIT3, OnUpdateEdit) - ON_EN_UPDATE(IDC_EDIT4, OnUpdateEdit) + ON_BN_CLICKED(IDC_RADIO4, &CDlgPrimesGeneratorDemo::OnRadio4) + ON_BN_CLICKED(IDC_RADIO5, &CDlgPrimesGeneratorDemo::OnRadio5) + ON_BN_CLICKED(IDC_RADIO6, &CDlgPrimesGeneratorDemo::OnRadio6) + ON_BN_CLICKED(IDC_RADIO7, &CDlgPrimesGeneratorDemo::OnRadio7) + ON_BN_CLICKED(IDC_BUTTON_GENERATE, &CDlgPrimesGeneratorDemo::OnButtonGenerate) + ON_BN_CLICKED(IDC_BUTTON_ACCEPT, &CDlgPrimesGeneratorDemo::OnButtonAccept) + ON_BN_CLICKED(IDC_ENDDIALOG, &CDlgPrimesGeneratorDemo::OnEndDialog) + ON_EN_UPDATE(IDC_EDIT1, &CDlgPrimesGeneratorDemo::OnUpdateEdit) + ON_EN_UPDATE(IDC_EDIT2, &CDlgPrimesGeneratorDemo::OnUpdateEdit) + ON_EN_UPDATE(IDC_EDIT3, &CDlgPrimesGeneratorDemo::OnUpdateEdit) + ON_EN_UPDATE(IDC_EDIT4, &CDlgPrimesGeneratorDemo::OnUpdateEdit) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -365,7 +365,7 @@ void CDlgPrimesGeneratorDemo::OnButtonGenerate() // display value range in progress dialog char temp[1024]; LoadString(AfxGetInstanceHandle(), IDS_STRING_MULTIPLE_PRIME_NUMBERS_GENERATION_TEXT, pc_str, STR_LAENGE_STRING_TABLE); - sprintf(temp, pc_str, m_edit1, m_edit2); + sprintf(temp, pc_str, (LPCTSTR)m_edit1, (LPCTSTR)m_edit2); theApp.fs.setFormat(temp); // start the prime number generation thread AfxBeginThread(singleThreadGenerateMultiplePrimeNumbers, PVOID(this)); @@ -408,7 +408,7 @@ void CDlgPrimesGeneratorDemo::OnButtonGenerate() // either way, reset the abortion flag (otherwise we'll get weird errors) generationMultiplePrimeNumbersAborted = false; // build the notification message - sprintf(temp, pc_str, m_edit1, m_edit2, mapGeneratedPrimeNumbers.size()); + sprintf(temp, pc_str, (LPCTSTR)m_edit1, (LPCTSTR)m_edit2, mapGeneratedPrimeNumbers.size()); message.Append(temp); MessageBox(message, "CrypTool", MB_ICONINFORMATION); // write the separator to the registry @@ -447,11 +447,11 @@ void CDlgPrimesGeneratorDemo::OnButtonGenerate() char temp[1024]; if(m_radio4 == 0) { LoadString(AfxGetInstanceHandle(), IDS_STRING_PRIME_NUMBERS_GENERATION_TEXT2, pc_str, STR_LAENGE_STRING_TABLE); - sprintf(temp, pc_str, m_edit1, m_edit2, m_edit3, m_edit4); + sprintf(temp, pc_str, (LPCTSTR)m_edit1, (LPCTSTR)m_edit2, (LPCTSTR)m_edit3, (LPCTSTR)m_edit4); } else { LoadString(AfxGetInstanceHandle(), IDS_STRING_PRIME_NUMBERS_GENERATION_TEXT1, pc_str, STR_LAENGE_STRING_TABLE); - sprintf(temp, pc_str, m_edit1, m_edit2); + sprintf(temp, pc_str, (LPCTSTR)m_edit1, (LPCTSTR)m_edit2); } theApp.fs.setFormat(temp); // start the prime number generation thread diff --git a/CrypTool/DlgProgressFactorisation.cpp b/CrypTool/DlgProgressFactorisation.cpp index b2d662b06..89f8ecf0b 100644 --- a/CrypTool/DlgProgressFactorisation.cpp +++ b/CrypTool/DlgProgressFactorisation.cpp @@ -90,11 +90,11 @@ void CDlgProgressFactorisation::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgProgressFactorisation, CDialog) //{{AFX_MSG_MAP(CDlgProgressFactorisation) ON_WM_TIMER() - ON_BN_CLICKED(IDCANCEL2, OnCancel2) - ON_BN_CLICKED(IDCANCEL3, OnCancel3) - ON_BN_CLICKED(IDCANCEL4, OnCancel4) - ON_BN_CLICKED(IDCANCEL5, OnCancel5) - ON_BN_CLICKED(IDCANCEL6, OnCancel6) + ON_BN_CLICKED(IDCANCEL2, &CDlgProgressFactorisation::OnCancel2) + ON_BN_CLICKED(IDCANCEL3, &CDlgProgressFactorisation::OnCancel3) + ON_BN_CLICKED(IDCANCEL4, &CDlgProgressFactorisation::OnCancel4) + ON_BN_CLICKED(IDCANCEL5, &CDlgProgressFactorisation::OnCancel5) + ON_BN_CLICKED(IDCANCEL6, &CDlgProgressFactorisation::OnCancel6) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgRSADecryption.cpp b/CrypTool/DlgRSADecryption.cpp index 3041ff21b..41f5366d3 100644 --- a/CrypTool/DlgRSADecryption.cpp +++ b/CrypTool/DlgRSADecryption.cpp @@ -81,10 +81,10 @@ void CDlgRSADecryption::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgRSADecryption, CDialog) //{{AFX_MSG_MAP(CDlgRSADecryption) - ON_NOTIFY(NM_CLICK, IDC_LIST_KEYS, OnClickListKeys) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST_KEYS, OnItemclickListKeys) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_KEYS, OnColumnclickListKeys) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_KEYS, OnKeydownListKeys) + ON_NOTIFY(NM_CLICK, IDC_LIST_KEYS, &CDlgRSADecryption::OnClickListKeys) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST_KEYS, &CDlgRSADecryption::OnItemclickListKeys) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_KEYS, &CDlgRSADecryption::OnColumnclickListKeys) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_KEYS, &CDlgRSADecryption::OnKeydownListKeys) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgRSADemo.cpp b/CrypTool/DlgRSADemo.cpp index 0b326f06c..10a15c27e 100644 --- a/CrypTool/DlgRSADemo.cpp +++ b/CrypTool/DlgRSADemo.cpp @@ -21,7 +21,7 @@ // RSA_mit_kleinenPZ.cpp: Implementierungsdatei // #include "stdafx.h" -#include "Afx.h" +#include "afx.h" #include "CrypToolApp.h" #include "DlgOptionsRSADemo.h" #include "DlgRSADemo.h" @@ -157,21 +157,21 @@ void CDlgRSADemo::DoDataExchange(CDataExchange* pDX) //****************************************************************************** BEGIN_MESSAGE_MAP(CDlgRSADemo, CDialog) //{{AFX_MSG_MAP(CDlgRSADemo) - ON_BN_CLICKED(IDC_BUTTON_PZ_GENERIEREN, OnButtonGeneratePrimes) - ON_BN_CLICKED(IDC_BUTTON2, OnButtonUpdateRSAParameter) - ON_BN_CLICKED(IDC_OPTIONEN, OnButtonOptions) - ON_BN_CLICKED(IDC_BUTTON_VERSCHLUESSELN, OnButtonEncrypt) - ON_BN_CLICKED(IDC_BUTTON_ENTSCHLUESSELN, OnButtonDecrypt) - ON_BN_CLICKED(IDC_ENDDIALOG, OnEndDialog) - ON_EN_UPDATE(IDC_EDIT1, OnUpdatePrimeP) - ON_EN_UPDATE(IDC_EDIT2, OnUpdatePrimeQ) - ON_EN_UPDATE(IDC_EDIT3, OnUpdateModulN) - ON_EN_UPDATE(IDC_EDIT5, OnUpdatePublicKeyE) - ON_EN_UPDATE(IDC_EDIT10, OnUpdateRSAInput) - ON_BN_CLICKED(IDC_RADIO1, OnRadioRSAText) - ON_BN_CLICKED(IDC_RADIO2, OnRadioRSANumbers) - ON_BN_CLICKED(IDC_RADIO3, OnRadioRSAComplete) - ON_BN_CLICKED(IDC_RADIO4, OnRadioRSAPublicKey) + ON_BN_CLICKED(IDC_BUTTON_PZ_GENERIEREN, &CDlgRSADemo::OnButtonGeneratePrimes) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgRSADemo::OnButtonUpdateRSAParameter) + ON_BN_CLICKED(IDC_OPTIONEN, &CDlgRSADemo::OnButtonOptions) + ON_BN_CLICKED(IDC_BUTTON_VERSCHLUESSELN, &CDlgRSADemo::OnButtonEncrypt) + ON_BN_CLICKED(IDC_BUTTON_ENTSCHLUESSELN, &CDlgRSADemo::OnButtonDecrypt) + ON_BN_CLICKED(IDC_ENDDIALOG, &CDlgRSADemo::OnEndDialog) + ON_EN_UPDATE(IDC_EDIT1, &CDlgRSADemo::OnUpdatePrimeP) + ON_EN_UPDATE(IDC_EDIT2, &CDlgRSADemo::OnUpdatePrimeQ) + ON_EN_UPDATE(IDC_EDIT3, &CDlgRSADemo::OnUpdateModulN) + ON_EN_UPDATE(IDC_EDIT5, &CDlgRSADemo::OnUpdatePublicKeyE) + ON_EN_UPDATE(IDC_EDIT10, &CDlgRSADemo::OnUpdateRSAInput) + ON_BN_CLICKED(IDC_RADIO1, &CDlgRSADemo::OnRadioRSAText) + ON_BN_CLICKED(IDC_RADIO2, &CDlgRSADemo::OnRadioRSANumbers) + ON_BN_CLICKED(IDC_RADIO3, &CDlgRSADemo::OnRadioRSAComplete) + ON_BN_CLICKED(IDC_RADIO4, &CDlgRSADemo::OnRadioRSAPublicKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -604,7 +604,7 @@ void CDlgRSADemo::InitPrivateRSAParameter() // an invalid parameter e, we present two options to the user: either going // with e=2^16+1 (the default) or computing e with regards to p and q CString message; - message.Format(IDS_STRING_RSATUT_WRONG_PUBLICKEY, m_edit_e, m_edit_phi_of_N); + message.Format(IDS_STRING_RSATUT_WRONG_PUBLICKEY, (LPCTSTR)m_edit_e, (LPCTSTR)m_edit_phi_of_N); if(AfxMessageBox(message, MB_ICONINFORMATION | MB_YESNO) == IDYES) { if(!calculateSmallestE(m_edit_e, m_edit_p, m_edit_q)) { CString message; @@ -1194,14 +1194,14 @@ void CDlgRSADemo::SetHeadLine(CString &mHeader, int IDS_STRING_ID, int base, int mHeader = line; } -void CDlgRSADemo::SetHeadLine(CString &mHeader, int IDS_STRING_ID, CString &Str, const char *str2) +void CDlgRSADemo::SetHeadLine(CString &mHeader, int IDS_STRING_ID, const CString &Str, const char *str2) { char line[IDS_STRINGLENGTH]; LoadString(AfxGetInstanceHandle(),IDS_STRING_ID,pc_str,STR_LAENGE_STRING_TABLE); if ( !str2 ) - sprintf( line, pc_str, Str ); + sprintf( line, pc_str, (LPCTSTR)Str ); else - sprintf( line, pc_str, Str, str2 ); + sprintf( line, pc_str, (LPCTSTR)Str, str2 ); mHeader = line; } @@ -2039,7 +2039,7 @@ CMyRSADemoEdit::~CMyRSADemoEdit() BEGIN_MESSAGE_MAP(CMyRSADemoEdit, CEdit) //{{AFX_MSG_MAP(CMyRSADemoEdit) ON_WM_CHAR() - ON_COMMAND(ID_EDIT_PASTE, OnMyPaste) + ON_COMMAND(ID_EDIT_PASTE, &CMyRSADemoEdit::OnMyPaste) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgRSADemo.h b/CrypTool/DlgRSADemo.h index 85147d62f..293e5cf78 100644 --- a/CrypTool/DlgRSADemo.h +++ b/CrypTool/DlgRSADemo.h @@ -233,7 +233,7 @@ class CDlgRSADemo : public CDialog void HeadingEncryption(BOOL decryptText); void RequestForInput( BOOL clearInput = FALSE ); void SetHeadLine( CString &mHeader, int IDS_STRING_ID, int base = 0, int BlockLength = 0 ); - void SetHeadLine( CString &mHeader, int IDS_STRING_ID, CString &Str, const char *str2 = 0); + void SetHeadLine( CString &mHeader, int IDS_STRING_ID, const CString &Str, const char *str2 = 0); int GetBase(); bool KeyStatusPublicKeyOnly() { return (s_publicKeyOnly == (m_RSAKeyStatus & s_publicKeyOnly) ); } diff --git a/CrypTool/DlgRSAEncryption.cpp b/CrypTool/DlgRSAEncryption.cpp index 800d1ee83..bed8cb8f6 100644 --- a/CrypTool/DlgRSAEncryption.cpp +++ b/CrypTool/DlgRSAEncryption.cpp @@ -82,10 +82,10 @@ void CDlgRSAEncryption::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgRSAEncryption, CDialog) //{{AFX_MSG_MAP(CDlgRSAEncryption) - ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList1) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnclickList1) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST1, OnItemclickList1) + ON_NOTIFY(NM_CLICK, IDC_LIST1, &CDlgRSAEncryption::OnClickList1) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, &CDlgRSAEncryption::OnColumnclickList1) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, &CDlgRSAEncryption::OnKeydownList1) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST1, &CDlgRSAEncryption::OnItemclickList1) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -115,7 +115,7 @@ BOOL CDlgRSAEncryption::OnInitDialog() m_listview.InsertColumn( 5, pc_str, LVCFMT_LEFT, colWidth-20 , 5); // Interne ID-Nr. CString tmpStr; - tmpStr.Format(IDS_TITLE_DLG_RSAENCRYPTION, oldTitle); + tmpStr.Format(IDS_TITLE_DLG_RSAENCRYPTION, (LPCTSTR)oldTitle); this->SetWindowText(tmpStr); diff --git a/CrypTool/DlgRandomGenerator.cpp b/CrypTool/DlgRandomGenerator.cpp index 73b3438e4..c50abbb1e 100644 --- a/CrypTool/DlgRandomGenerator.cpp +++ b/CrypTool/DlgRandomGenerator.cpp @@ -38,7 +38,7 @@ using namespace std; #include "DlgPrimesGeneratorDemo.h" #include "DlgShowProgress.h" #include "CrypToolTools.h" -#include ".\dlgrandomgenerator.h" +#include "DlgRandomGenerator.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -275,13 +275,13 @@ void CDlgRandomGenerator::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgRandomGenerator, CDialog) //{{AFX_MSG_MAP(CDlgRandomGenerator) - ON_BN_CLICKED(IDC_BUTTON1, OnSelGenParam) - ON_BN_CLICKED(IDOK, OnGenRandomData) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgRandomGenerator::OnSelGenParam) + ON_BN_CLICKED(IDOK, &CDlgRandomGenerator::OnGenRandomData) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_RADIO1, OnBnClickedRadio1) - ON_BN_CLICKED(IDC_RADIO2, OnBnClickedRadio2) - ON_BN_CLICKED(IDC_RADIO3, OnBnClickedRadio3) - ON_BN_CLICKED(IDC_RADIO4, OnBnClickedRadio4) + ON_BN_CLICKED(IDC_RADIO1, &CDlgRandomGenerator::OnBnClickedRadio1) + ON_BN_CLICKED(IDC_RADIO2, &CDlgRandomGenerator::OnBnClickedRadio2) + ON_BN_CLICKED(IDC_RADIO3, &CDlgRandomGenerator::OnBnClickedRadio3) + ON_BN_CLICKED(IDC_RADIO4, &CDlgRandomGenerator::OnBnClickedRadio4) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -300,21 +300,24 @@ void CDlgRandomGenerator::OnSelGenParam() case 1: { if (IDOK == m_pPara->DRPXN.DoModal() ) { - m_pPara->rnd_x2modN.setModul( m_pPara->DRPXN.GetModul() ); + CString strModul = m_pPara->DRPXN.GetModul(); + m_pPara->rnd_x2modN.setModul( strModul ); } } break; case 2: { if (IDOK == m_pPara->DRP_LCG.DoModal() ) { - m_pPara->DLCG.SetParameter(m_pPara->DRP_LCG.Get_a(), m_pPara->DRP_LCG.Get_b(), m_pPara->DRP_LCG.Get_N()); + CString strA = m_pPara->DRP_LCG.Get_a(), strB = m_pPara->DRP_LCG.Get_b(), strN = m_pPara->DRP_LCG.Get_N(); + m_pPara->DLCG.SetParameter(strA, strB, strN); } } break; case 3: { if (IDOK == m_pPara->DRP_ICG.DoModal() ) { - m_pPara->DICG.SetParameter(m_pPara->DRP_ICG.Get_a(), m_pPara->DRP_ICG.Get_b(), m_pPara->DRP_ICG.Get_N()); + CString strA = m_pPara->DRP_ICG.Get_a(), strB = m_pPara->DRP_ICG.Get_b(), strN = m_pPara->DRP_ICG.Get_N(); + m_pPara->DICG.SetParameter(strA, strB, strN); } break; diff --git a/CrypTool/DlgRot13Caesar.cpp b/CrypTool/DlgRot13Caesar.cpp index 5e3695446..84bf0b42d 100644 --- a/CrypTool/DlgRot13Caesar.cpp +++ b/CrypTool/DlgRot13Caesar.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "DlgRot13Caesar.h" #include "CrypToolTools.h" @@ -76,18 +76,18 @@ void CDlgRot13Caesar::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgRot13Caesar, CDialog) //{{AFX_MSG_MAP(CDlgRot13Caesar) - ON_BN_CLICKED(IDC_RADIO1, onUpdateGUI) - ON_BN_CLICKED(IDC_RADIO2, onUpdateGUI) - ON_BN_CLICKED(IDC_RADIO3, onUpdateGUI) - ON_BN_CLICKED(IDC_RADIO4, onUpdateGUI) - ON_BN_CLICKED(IDC_RADIO5, onUpdateGUI) - ON_BN_CLICKED(IDC_RADIO6, onUpdateGUI) - ON_EN_UPDATE(IDC_KEY, onUpdateGUI) - ON_EN_UPDATE(IDC_EDIT_ALPHCODE, onUpdateGUI) - ON_BN_CLICKED(IDC_PASTE_KEY, OnPasteKey) - ON_BN_CLICKED(ID_ENCRYPT, OnEncrypt) - ON_BN_CLICKED(ID_DECRYPT, OnDecrypt) - ON_BN_CLICKED(IDC_BUTTON_TxtOpt, onTextOptions) + ON_BN_CLICKED(IDC_RADIO1, &CDlgRot13Caesar::onUpdateGUI) + ON_BN_CLICKED(IDC_RADIO2, &CDlgRot13Caesar::onUpdateGUI) + ON_BN_CLICKED(IDC_RADIO3, &CDlgRot13Caesar::onUpdateGUI) + ON_BN_CLICKED(IDC_RADIO4, &CDlgRot13Caesar::onUpdateGUI) + ON_BN_CLICKED(IDC_RADIO5, &CDlgRot13Caesar::onUpdateGUI) + ON_BN_CLICKED(IDC_RADIO6, &CDlgRot13Caesar::onUpdateGUI) + ON_EN_UPDATE(IDC_KEY, &CDlgRot13Caesar::onUpdateGUI) + ON_EN_UPDATE(IDC_EDIT_ALPHCODE, &CDlgRot13Caesar::onUpdateGUI) + ON_BN_CLICKED(IDC_PASTE_KEY, &CDlgRot13Caesar::OnPasteKey) + ON_BN_CLICKED(ID_ENCRYPT, &CDlgRot13Caesar::OnEncrypt) + ON_BN_CLICKED(ID_DECRYPT, &CDlgRot13Caesar::OnDecrypt) + ON_BN_CLICKED(IDC_BUTTON_TxtOpt, &CDlgRot13Caesar::onTextOptions) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgSecretSharingIntro.cpp b/CrypTool/DlgSecretSharingIntro.cpp index 0a8af6698..433a61f2a 100644 --- a/CrypTool/DlgSecretSharingIntro.cpp +++ b/CrypTool/DlgSecretSharingIntro.cpp @@ -22,9 +22,9 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" +#include "DlgSecretSharingIntro.h" #include "DlgSecretSharingIntro.h" -#include ".\dlgsecretsharingintro.h" #include "CrypToolTools.h" @@ -54,7 +54,7 @@ void CDlgSecretSharingIntro::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSecretSharingIntro, CDialog) //{{AFX_MSG_MAP(CDlgSecretSharingIntro) - ON_BN_CLICKED(IDOK, OnOk) + ON_BN_CLICKED(IDOK, &CDlgSecretSharingIntro::OnOk) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -68,7 +68,7 @@ void CDlgSecretSharingIntro::OnOk() if ( CT_OPEN_REGISTRY_SETTINGS( KEY_WRITE, IDS_REGISTRY_SETTINGS, "SecretSharing" ) == ERROR_SUCCESS ) { - CT_WRITE_REGISTRY(unsigned long(!m_hide_intro), "ShowIntroShamir"); + CT_WRITE_REGISTRY((unsigned long)(!m_hide_intro), "ShowIntroShamir"); CT_CLOSE_REGISTRY(); } else diff --git a/CrypTool/DlgSecretSharingOptions.cpp b/CrypTool/DlgSecretSharingOptions.cpp index 6eea04da2..4db5d4210 100644 --- a/CrypTool/DlgSecretSharingOptions.cpp +++ b/CrypTool/DlgSecretSharingOptions.cpp @@ -52,7 +52,7 @@ void CDlgSecretSharingOptions::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSecretSharingOptions, CDialog) //{{AFX_MSG_MAP(CDlgSecretSharingOptions) - ON_BN_CLICKED(IDOK, OnButtonOk) + ON_BN_CLICKED(IDOK, &CDlgSecretSharingOptions::OnButtonOk) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgSecretSharingParameter.cpp b/CrypTool/DlgSecretSharingParameter.cpp index 978d8d877..cc5e4721d 100644 --- a/CrypTool/DlgSecretSharingParameter.cpp +++ b/CrypTool/DlgSecretSharingParameter.cpp @@ -25,7 +25,7 @@ #include "CrypToolApp.h" #include "DlgSecretSharingOptions.h" #include "DlgSecretSharingParameter.h" -#include ".\dlgsecretsharingparameter.h" +#include "DlgSecretSharingParameter.h" #include "CrypToolTools.h" // CDlgSecretSharingParameter-Dialogfeld @@ -66,10 +66,10 @@ void CDlgSecretSharingParameter::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSecretSharingParameter, CDialog) - ON_BN_CLICKED(IDB_GENERATENEW, OnButtonGenerateNew) - ON_EN_UPDATE(IDC_EDIT_MYPRIME, OnEnUpdateEditMyprime) - ON_BN_CLICKED(IDOK, OnButtonClickedOk) - ON_EN_UPDATE(IDC_EDIT_MYCOEFF, OnUpdateEditMycoeff) + ON_BN_CLICKED(IDB_GENERATENEW, &CDlgSecretSharingParameter::OnButtonGenerateNew) + ON_EN_UPDATE(IDC_EDIT_MYPRIME, &CDlgSecretSharingParameter::OnEnUpdateEditMyprime) + ON_BN_CLICKED(IDOK, &CDlgSecretSharingParameter::OnButtonClickedOk) + ON_EN_UPDATE(IDC_EDIT_MYCOEFF, &CDlgSecretSharingParameter::OnUpdateEditMycoeff) END_MESSAGE_MAP() BOOL CDlgSecretSharingParameter::OnInitDialog() diff --git a/CrypTool/DlgSecretSharingReveal.cpp b/CrypTool/DlgSecretSharingReveal.cpp index a94c9bd0c..3d7b520fc 100644 --- a/CrypTool/DlgSecretSharingReveal.cpp +++ b/CrypTool/DlgSecretSharingReveal.cpp @@ -66,7 +66,7 @@ void CDlgSecretSharingReveal::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSecretSharingReveal, CDialog) - ON_BN_CLICKED(IDC_BUTTON_LOG, OnShowLog) + ON_BN_CLICKED(IDC_BUTTON_LOG, &CDlgSecretSharingReveal::OnShowLog) END_MESSAGE_MAP() BOOL CDlgSecretSharingReveal::OnInitDialog() diff --git a/CrypTool/DlgSecretSharingSetup.cpp b/CrypTool/DlgSecretSharingSetup.cpp index a200a1819..c37ccbe2d 100644 --- a/CrypTool/DlgSecretSharingSetup.cpp +++ b/CrypTool/DlgSecretSharingSetup.cpp @@ -30,7 +30,7 @@ #include "DlgSecretSharingReveal.h" #include "DlgSecretSharingOptions.h" #include "SecretSharingLog.h" -#include ".\dlgsecretsharingsetup.h" +#include "DlgSecretSharingSetup.h" #include "CrypToolTools.h" #ifdef _DEBUG @@ -89,18 +89,18 @@ void CDlgSecretSharingSetup::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSecretSharingSetup, CDialog) //{{AFX_MSG_MAP(CDlgSecretSharingSetup) - ON_BN_CLICKED(IDC_BUTTON_GENERATE, OnButtonGenerate) - ON_BN_CLICKED(IDC_BUTTON_UPDATE, OnButtonUpdate) - ON_BN_CLICKED(IDOK, OnButtonOk) - ON_EN_UPDATE(IDC_EDIT_THRESHOLD, OnUpdateEditThreshold) - ON_EN_UPDATE(IDC_EDIT_SECRET, OnUpdateEditSecret) - ON_EN_UPDATE(IDC_EDIT_PARTICIPANTS, OnUpdateEditParticipants) - ON_BN_CLICKED(IDC_BUTTON_OPT, OnButtonOpt) - ON_BN_CLICKED(IDC_BUTTON_CHANGE, OnButtonChange) - ON_BN_CLICKED(IDC_CHECK_SHOWINTRO, OnButtonClickedCheckShowintro) - ON_BN_CLICKED(IDC_BUTTON_EXAMPLE, OnButtonExample) + ON_BN_CLICKED(IDC_BUTTON_GENERATE, &CDlgSecretSharingSetup::OnButtonGenerate) + ON_BN_CLICKED(IDC_BUTTON_UPDATE, &CDlgSecretSharingSetup::OnButtonUpdate) + ON_BN_CLICKED(IDOK, &CDlgSecretSharingSetup::OnButtonOk) + ON_EN_UPDATE(IDC_EDIT_THRESHOLD, &CDlgSecretSharingSetup::OnUpdateEditThreshold) + ON_EN_UPDATE(IDC_EDIT_SECRET, &CDlgSecretSharingSetup::OnUpdateEditSecret) + ON_EN_UPDATE(IDC_EDIT_PARTICIPANTS, &CDlgSecretSharingSetup::OnUpdateEditParticipants) + ON_BN_CLICKED(IDC_BUTTON_OPT, &CDlgSecretSharingSetup::OnButtonOpt) + ON_BN_CLICKED(IDC_BUTTON_CHANGE, &CDlgSecretSharingSetup::OnButtonChange) + ON_BN_CLICKED(IDC_CHECK_SHOWINTRO, &CDlgSecretSharingSetup::OnButtonClickedCheckShowintro) + ON_BN_CLICKED(IDC_BUTTON_EXAMPLE, &CDlgSecretSharingSetup::OnButtonExample) //}}AFX_MSG_MAP - ON_NOTIFY(NM_CLICK, IDC_LIST_SHARES, OnNMClickListShares) + ON_NOTIFY(NM_CLICK, IDC_LIST_SHARES, &CDlgSecretSharingSetup::OnNMClickListShares) END_MESSAGE_MAP() BOOL CDlgSecretSharingSetup::OnInitDialog() diff --git a/CrypTool/DlgSelectHashFunction.cpp b/CrypTool/DlgSelectHashFunction.cpp index 249dffa5a..1facca786 100644 --- a/CrypTool/DlgSelectHashFunction.cpp +++ b/CrypTool/DlgSelectHashFunction.cpp @@ -73,14 +73,14 @@ void CDlgSelectHashFunction::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSelectHashFunction, CDialog) //{{AFX_MSG_MAP(CDlgSelectHashFunction) - ON_BN_CLICKED(IDC_RADIO1, OnSelectedMD2) - ON_BN_CLICKED(IDC_RADIO2, OnSelectedMD4) - ON_BN_CLICKED(IDC_RADIO3, OnSelectedMD5) - ON_BN_CLICKED(IDC_RADIO4, OnSelectSHA) - ON_BN_CLICKED(IDC_RADIO5, OnSelectedSHA_1) - ON_BN_CLICKED(IDC_RADIO7, OnSelectedSHA_256) - ON_BN_CLICKED(IDC_RADIO8, OnSelectedSHA_512) - ON_BN_CLICKED(IDC_RADIO6, OnSelectedRIPEMD_160) + ON_BN_CLICKED(IDC_RADIO1, &CDlgSelectHashFunction::OnSelectedMD2) + ON_BN_CLICKED(IDC_RADIO2, &CDlgSelectHashFunction::OnSelectedMD4) + ON_BN_CLICKED(IDC_RADIO3, &CDlgSelectHashFunction::OnSelectedMD5) + ON_BN_CLICKED(IDC_RADIO4, &CDlgSelectHashFunction::OnSelectSHA) + ON_BN_CLICKED(IDC_RADIO5, &CDlgSelectHashFunction::OnSelectedSHA_1) + ON_BN_CLICKED(IDC_RADIO7, &CDlgSelectHashFunction::OnSelectedSHA_256) + ON_BN_CLICKED(IDC_RADIO8, &CDlgSelectHashFunction::OnSelectedSHA_512) + ON_BN_CLICKED(IDC_RADIO6, &CDlgSelectHashFunction::OnSelectedRIPEMD_160) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgShowHash.cpp b/CrypTool/DlgShowHash.cpp index d618e9ac4..5ac4ff699 100644 --- a/CrypTool/DlgShowHash.cpp +++ b/CrypTool/DlgShowHash.cpp @@ -56,7 +56,7 @@ void CDlgShowHash::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowHash, CDialog) //{{AFX_MSG_MAP(CDlgShowHash) - ON_BN_CLICKED(IDOK, OnShowHashInDesktop) + ON_BN_CLICKED(IDOK, &CDlgShowHash::OnShowHashInDesktop) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgShowKey.cpp b/CrypTool/DlgShowKey.cpp index 33b997ff6..4f183a26a 100644 --- a/CrypTool/DlgShowKey.cpp +++ b/CrypTool/DlgShowKey.cpp @@ -57,7 +57,7 @@ void CDlgShowKey::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowKey, CDialog) //{{AFX_MSG_MAP(CDlgShowKey) - ON_BN_CLICKED(IDC_BUTTON1, OnCopyKey) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgShowKey::OnCopyKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -112,7 +112,7 @@ BOOL CDlgShowKey::PreTranslateMessage(MSG *msg) { return CDialog::PreTranslateMessage(msg); } -int CDlgShowKey::DoModal() +INT_PTR CDlgShowKey::DoModal() { // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen return CDialog::DoModal(); diff --git a/CrypTool/DlgShowKey.h b/CrypTool/DlgShowKey.h index e425c8e45..f87d764fb 100644 --- a/CrypTool/DlgShowKey.h +++ b/CrypTool/DlgShowKey.h @@ -51,7 +51,7 @@ class CDlgShowKey : public CDialog // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CDlgShowKey) public: - virtual int DoModal(); + virtual INT_PTR DoModal(); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL diff --git a/CrypTool/DlgShowKeyHill10x10.cpp b/CrypTool/DlgShowKeyHill10x10.cpp index cda128885..b4b8e92fa 100644 --- a/CrypTool/DlgShowKeyHill10x10.cpp +++ b/CrypTool/DlgShowKeyHill10x10.cpp @@ -266,11 +266,11 @@ void CDlgShowKeyHill10x10::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowKeyHill10x10, CDialog) //{{AFX_MSG_MAP(CDlgShowKeyHill10x10) - ON_BN_CLICKED(IDC_RADIO1, OnKey) - ON_BN_CLICKED(IDC_RADIO2, OnInvKey) - ON_BN_CLICKED(IDC_RADIO27, OnOfs0) - ON_BN_CLICKED(IDC_RADIO28, OnOfs1) - ON_BN_CLICKED(IDC_BUTTON1, OnCopyKey) + ON_BN_CLICKED(IDC_RADIO1, &CDlgShowKeyHill10x10::OnKey) + ON_BN_CLICKED(IDC_RADIO2, &CDlgShowKeyHill10x10::OnInvKey) + ON_BN_CLICKED(IDC_RADIO27, &CDlgShowKeyHill10x10::OnOfs0) + ON_BN_CLICKED(IDC_RADIO28, &CDlgShowKeyHill10x10::OnOfs1) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgShowKeyHill10x10::OnCopyKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgShowKeyHill5x5.cpp b/CrypTool/DlgShowKeyHill5x5.cpp index 275d43bcd..c0f143919 100644 --- a/CrypTool/DlgShowKeyHill5x5.cpp +++ b/CrypTool/DlgShowKeyHill5x5.cpp @@ -117,11 +117,11 @@ void CDlgShowKeyHill5x5::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowKeyHill5x5, CDialog) //{{AFX_MSG_MAP(CDlgShowKeyHill5x5) - ON_BN_CLICKED(IDC_RADIO1, OnKey) - ON_BN_CLICKED(IDC_RADIO2, OnInvKey) - ON_BN_CLICKED(IDC_RADIO3, OnOfs0) - ON_BN_CLICKED(IDC_RADIO4, OnOfs1) - ON_BN_CLICKED(IDC_BUTTON1, OnCopyKey) + ON_BN_CLICKED(IDC_RADIO1, &CDlgShowKeyHill5x5::OnKey) + ON_BN_CLICKED(IDC_RADIO2, &CDlgShowKeyHill5x5::OnInvKey) + ON_BN_CLICKED(IDC_RADIO3, &CDlgShowKeyHill5x5::OnOfs0) + ON_BN_CLICKED(IDC_RADIO4, &CDlgShowKeyHill5x5::OnOfs1) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgShowKeyHill5x5::OnCopyKey) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgShowKeyParameter.cpp b/CrypTool/DlgShowKeyParameter.cpp index d14e6c318..27243961a 100644 --- a/CrypTool/DlgShowKeyParameter.cpp +++ b/CrypTool/DlgShowKeyParameter.cpp @@ -55,9 +55,9 @@ void CDlgShowKeyParameter::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowKeyParameter, CDialog) //{{AFX_MSG_MAP(CDlgShowKeyParameter) - ON_BN_CLICKED(IDC_RADIO1, OnUpdate) - ON_BN_CLICKED(IDC_RADIO2, OnUpdate) - ON_BN_CLICKED(IDC_RADIO3, OnUpdate) + ON_BN_CLICKED(IDC_RADIO1, &CDlgShowKeyParameter::OnUpdate) + ON_BN_CLICKED(IDC_RADIO2, &CDlgShowKeyParameter::OnUpdate) + ON_BN_CLICKED(IDC_RADIO3, &CDlgShowKeyParameter::OnUpdate) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgShowParameterKeyEC.cpp b/CrypTool/DlgShowParameterKeyEC.cpp index dbec16250..15d6aac87 100644 --- a/CrypTool/DlgShowParameterKeyEC.cpp +++ b/CrypTool/DlgShowParameterKeyEC.cpp @@ -79,10 +79,10 @@ void CDlgShowParameterKeyEC::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowParameterKeyEC, CDialog) //{{AFX_MSG_MAP(CDlgShowParameterKeyEC) - ON_BN_CLICKED(IDC_RADIO1, OnOctalRadio) - ON_BN_CLICKED(IDC_RADIO2, OnDecimalRadio) - ON_BN_CLICKED(IDC_RADIO3, OnHexRadio) - ON_BN_CLICKED(IDC_BUTTON1, OnNewKeyPair) + ON_BN_CLICKED(IDC_RADIO1, &CDlgShowParameterKeyEC::OnOctalRadio) + ON_BN_CLICKED(IDC_RADIO2, &CDlgShowParameterKeyEC::OnDecimalRadio) + ON_BN_CLICKED(IDC_RADIO3, &CDlgShowParameterKeyEC::OnHexRadio) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgShowParameterKeyEC::OnNewKeyPair) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -97,7 +97,7 @@ BOOL CDlgShowParameterKeyEC::OnInitDialog() // m_dom_param_listview aufbauen UpdateData(TRUE); LoadString(AfxGetInstanceHandle(),IDS_STRING_EC_DOMAIN_PARAMETER,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_ec_dom_par_editbox = (CString) pc_str1; UpdateData(FALSE); diff --git a/CrypTool/DlgShowPrivateKeyEC.cpp b/CrypTool/DlgShowPrivateKeyEC.cpp index 495d3a9f2..bcfd506cd 100644 --- a/CrypTool/DlgShowPrivateKeyEC.cpp +++ b/CrypTool/DlgShowPrivateKeyEC.cpp @@ -92,9 +92,9 @@ void CDlgShowPrivateKeyEC::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowPrivateKeyEC, CDialog) //{{AFX_MSG_MAP(CDlgShowPrivateKeyEC) - ON_BN_CLICKED(IDC_RADIO1, OnOctalRadio) - ON_BN_CLICKED(IDC_RADIO2, OnDecimalRadio) - ON_BN_CLICKED(IDC_RADIO3, OnHexRadio) + ON_BN_CLICKED(IDC_RADIO1, &CDlgShowPrivateKeyEC::OnOctalRadio) + ON_BN_CLICKED(IDC_RADIO2, &CDlgShowPrivateKeyEC::OnDecimalRadio) + ON_BN_CLICKED(IDC_RADIO3, &CDlgShowPrivateKeyEC::OnHexRadio) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -257,7 +257,7 @@ BOOL CDlgShowPrivateKeyEC::OnInitDialog() // m_dom_param_listview aufbauen UpdateData(TRUE); LoadString(AfxGetInstanceHandle(),IDS_STRING_EC_DOMAIN_PARAMETER,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_ec_dom_par_editbox = (CString) pc_str1; UpdateData(FALSE); LoadString(AfxGetInstanceHandle(),IDS_STRING_PARAMETER,pc_str,STR_LAENGE_STRING_TABLE); diff --git a/CrypTool/DlgShowProgress.cpp b/CrypTool/DlgShowProgress.cpp index 44940e3ad..ad0734150 100644 --- a/CrypTool/DlgShowProgress.cpp +++ b/CrypTool/DlgShowProgress.cpp @@ -218,13 +218,13 @@ CString CDlgShowProgress::duration(double progress) const d.Format("%02d h", s/3600); } else if (rest < 3600.0*24.0*365.0) { - d.Format("%.1f %s",rest/(3600.0*24.0),m_days); + d.Format("%.1f %s",rest/(3600.0*24.0),(LPCTSTR)m_days); // flomar, 05/04/2010 // we want language-dependent separators (i.e. "," in DE, "." in EN); therefore we replace // all periods (".", default!) with the appropriate separator (IDS_FLOAT_NUMBER_SEPARATOR) d.Replace('.', m_floatNumberSeparator[0]); } else { - d.Format("%.2g %s",rest/(3600.0*24.0*365.0),m_years); + d.Format("%.2g %s",rest/(3600.0*24.0*365.0),(LPCTSTR)m_years); // flomar, 05/04/2010 // we want language-dependent separators (i.e. "," in DE, "." in EN); therefore we replace // all periods (".", default!) with the appropriate separator (IDS_FLOAT_NUMBER_SEPARATOR) @@ -249,7 +249,7 @@ void CDlgShowProgress::OnTimer(UINT nIDEvent) CString text; double progress = m_model->getProgress(); int percent = (int)(100.0*progress+0.5); - text.Format(m_format,percent,duration(progress)); + text.Format(m_format,percent,(LPCTSTR)duration(progress)); m_text_ctl.SetWindowText(text); m_Progress.SetPos(percent); } else { diff --git a/CrypTool/DlgShowPublicKeyEC.cpp b/CrypTool/DlgShowPublicKeyEC.cpp index 101d725a3..888960ac4 100644 --- a/CrypTool/DlgShowPublicKeyEC.cpp +++ b/CrypTool/DlgShowPublicKeyEC.cpp @@ -91,9 +91,9 @@ void CDlgShowPublicKeyEC::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgShowPublicKeyEC, CDialog) //{{AFX_MSG_MAP(CDlgShowPublicKeyEC) - ON_BN_CLICKED(IDC_RADIO1, OnOctalRadio) - ON_BN_CLICKED(IDC_RADIO2, OnDecimalRadio) - ON_BN_CLICKED(IDC_RADIO3, OnHexRadio) + ON_BN_CLICKED(IDC_RADIO1, &CDlgShowPublicKeyEC::OnOctalRadio) + ON_BN_CLICKED(IDC_RADIO2, &CDlgShowPublicKeyEC::OnDecimalRadio) + ON_BN_CLICKED(IDC_RADIO3, &CDlgShowPublicKeyEC::OnHexRadio) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -251,7 +251,7 @@ BOOL CDlgShowPublicKeyEC::OnInitDialog() // m_dom_param_listview aufbauen UpdateData(TRUE); LoadString(AfxGetInstanceHandle(),IDS_STRING_EC_DOMAIN_PARAMETER,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_ec_dom_par_editbox = (CString) pc_str1; UpdateData(FALSE); LoadString(AfxGetInstanceHandle(),IDS_STRING_PARAMETER,pc_str,STR_LAENGE_STRING_TABLE); diff --git a/CrypTool/DlgShowPublicKeyEC.h b/CrypTool/DlgShowPublicKeyEC.h index 33ad72f94..4caac5c88 100644 --- a/CrypTool/DlgShowPublicKeyEC.h +++ b/CrypTool/DlgShowPublicKeyEC.h @@ -81,7 +81,7 @@ class CDlgShowPublicKeyEC : public CDialog virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL - void CDlgShowPublicKeyEC::UpdateEcListBox(); + void UpdateEcListBox(); // Implementierung protected: diff --git a/CrypTool/DlgSideChannelAttackVisualizationHE.cpp b/CrypTool/DlgSideChannelAttackVisualizationHE.cpp index 74e82947e..6436df5f8 100644 --- a/CrypTool/DlgSideChannelAttackVisualizationHE.cpp +++ b/CrypTool/DlgSideChannelAttackVisualizationHE.cpp @@ -94,21 +94,21 @@ void CDlgSideChannelAttackVisualizationHE::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSideChannelAttackVisualizationHE, CDialog) //{{AFX_MSG_MAP(CDlgSideChannelAttackVisualizationHE) - ON_BN_CLICKED(IDC_INTRODUCTION, OnIntroduction) - ON_BN_CLICKED(IDC_PREPARATIONS, OnPreparations) - ON_BN_CLICKED(IDC_MESSAGETRANSMISSION, OnMessagetransmission) - ON_BN_CLICKED(IDC_MESSAGEINTERCEPTION, OnMessageinterception) - ON_BN_CLICKED(IDC_ATTACKCYCLE, OnAttackcycle) - ON_BN_CLICKED(IDC_REPORT, OnReport) - ON_BN_CLICKED(IDC_ALICE, OnAlice) - ON_BN_CLICKED(IDC_BOB, OnBob) - ON_BN_CLICKED(IDC_TRUDY, OnTrudy) - ON_BN_CLICKED(IDCLOSE, OnClose) + ON_BN_CLICKED(IDC_INTRODUCTION, &CDlgSideChannelAttackVisualizationHE::OnIntroduction) + ON_BN_CLICKED(IDC_PREPARATIONS, &CDlgSideChannelAttackVisualizationHE::OnPreparations) + ON_BN_CLICKED(IDC_MESSAGETRANSMISSION, &CDlgSideChannelAttackVisualizationHE::OnMessagetransmission) + ON_BN_CLICKED(IDC_MESSAGEINTERCEPTION, &CDlgSideChannelAttackVisualizationHE::OnMessageinterception) + ON_BN_CLICKED(IDC_ATTACKCYCLE, &CDlgSideChannelAttackVisualizationHE::OnAttackcycle) + ON_BN_CLICKED(IDC_REPORT, &CDlgSideChannelAttackVisualizationHE::OnReport) + ON_BN_CLICKED(IDC_ALICE, &CDlgSideChannelAttackVisualizationHE::OnAlice) + ON_BN_CLICKED(IDC_BOB, &CDlgSideChannelAttackVisualizationHE::OnBob) + ON_BN_CLICKED(IDC_TRUDY, &CDlgSideChannelAttackVisualizationHE::OnTrudy) + ON_BN_CLICKED(IDCLOSE, &CDlgSideChannelAttackVisualizationHE::OnClose) ON_WM_TIMER() - ON_BN_CLICKED(IDC_BUTTON_NEXTSINGLESTEP, OnButtonNextsinglestep) - ON_BN_CLICKED(IDC_BUTTON_ALLREMAININGSTEPS, OnButtonAllremainingsteps) - ON_BN_CLICKED(IDC_MESSAGERECEPTION, OnMessagereception) - ON_BN_CLICKED(IDC_CHECK_DISABLEHELP, OnCheckDisablehelp) + ON_BN_CLICKED(IDC_BUTTON_NEXTSINGLESTEP, &CDlgSideChannelAttackVisualizationHE::OnButtonNextsinglestep) + ON_BN_CLICKED(IDC_BUTTON_ALLREMAININGSTEPS, &CDlgSideChannelAttackVisualizationHE::OnButtonAllremainingsteps) + ON_BN_CLICKED(IDC_MESSAGERECEPTION, &CDlgSideChannelAttackVisualizationHE::OnMessagereception) + ON_BN_CLICKED(IDC_CHECK_DISABLEHELP, &CDlgSideChannelAttackVisualizationHE::OnCheckDisablehelp) ON_WM_PAINT() ON_WM_CTLCOLOR() //}}AFX_MSG_MAP @@ -1238,7 +1238,7 @@ void CDlgSideChannelAttackVisualizationHE::OnCheckDisablehelp() if ( CT_OPEN_REGISTRY_SETTINGS( KEY_WRITE, IDS_REGISTRY_SETTINGS ) == ERROR_SUCCESS ) { - CT_WRITE_REGISTRY(unsigned long(this->m_bShowInfoDialogues), "SCA_InfoDialogues"); + CT_WRITE_REGISTRY((unsigned long)(this->m_bShowInfoDialogues), "SCA_InfoDialogues"); CT_CLOSE_REGISTRY(); } else diff --git a/CrypTool/DlgSideChannelAttackVisualizationHE.h b/CrypTool/DlgSideChannelAttackVisualizationHE.h index 5f56bfbc4..5b5850311 100644 --- a/CrypTool/DlgSideChannelAttackVisualizationHE.h +++ b/CrypTool/DlgSideChannelAttackVisualizationHE.h @@ -30,9 +30,9 @@ // sub-dialogues #include "DlgSideChannelAttackVisualizationHEIntroduction.h" #include "DlgSideChannelAttackVisualizationHEPreparations.h" -#include "DlgSideChannelAttackVisualizationHEMessagetransmission.h" -#include "DlgSideChannelAttackVisualizationHEMessageinterception.h" -#include "DlgSideChannelAttackVisualizationHEAttackcycle.h" +#include "DlgSideChannelAttackVisualizationHEMessageTransmission.h" +#include "DlgSideChannelAttackVisualizationHEMessageInterception.h" +#include "DlgSideChannelAttackVisualizationHEAttackCycle.h" #include "DlgSideChannelAttackVisualizationHEReport.h" #include "DlgSideChannelAttackVisualizationHEPSEPINPrompt.h" #include "DlgHybridEncryptionDemo.h" // Hinzugefügt von der Klassenansicht diff --git a/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest1.cpp b/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest1.cpp index ede79f43a..a08ed6252 100644 --- a/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest1.cpp +++ b/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest1.cpp @@ -59,10 +59,10 @@ BOOL CDlgSideChannelAttackVisualizationHEPreparationsRequest1::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgSideChannelAttackVisualizationHEPreparationsRequest1, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel) - ON_BN_CLICKED(IDC_RADIO_CHOICE_1, OnBnClickedRadioChoice1) - ON_BN_CLICKED(IDC_RADIO_CHOICE_2, OnBnClickedRadioChoice2) + ON_BN_CLICKED(IDOK, &CDlgSideChannelAttackVisualizationHEPreparationsRequest1::OnBnClickedOk) + ON_BN_CLICKED(IDCANCEL, &CDlgSideChannelAttackVisualizationHEPreparationsRequest1::OnBnClickedCancel) + ON_BN_CLICKED(IDC_RADIO_CHOICE_1, &CDlgSideChannelAttackVisualizationHEPreparationsRequest1::OnBnClickedRadioChoice1) + ON_BN_CLICKED(IDC_RADIO_CHOICE_2, &CDlgSideChannelAttackVisualizationHEPreparationsRequest1::OnBnClickedRadioChoice2) END_MESSAGE_MAP() // CDlgSideChannelAttackVisualizationHEPreparationsRequest1 message handlers diff --git a/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest2.cpp b/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest2.cpp index da68d8a66..5bd8a3c57 100644 --- a/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest2.cpp +++ b/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest2.cpp @@ -62,11 +62,11 @@ BOOL CDlgSideChannelAttackVisualizationHEPreparationsRequest2::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgSideChannelAttackVisualizationHEPreparationsRequest2, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel) - ON_BN_CLICKED(IDC_RADIO_CHOICE_1, OnBnClickedRadioChoice1) - ON_BN_CLICKED(IDC_RADIO_CHOICE_2, OnBnClickedRadioChoice2) - ON_BN_CLICKED(IDC_RADIO_CHOICE_3, OnBnClickedRadioChoice3) + ON_BN_CLICKED(IDOK, &CDlgSideChannelAttackVisualizationHEPreparationsRequest2::OnBnClickedOk) + ON_BN_CLICKED(IDCANCEL, &CDlgSideChannelAttackVisualizationHEPreparationsRequest2::OnBnClickedCancel) + ON_BN_CLICKED(IDC_RADIO_CHOICE_1, &CDlgSideChannelAttackVisualizationHEPreparationsRequest2::OnBnClickedRadioChoice1) + ON_BN_CLICKED(IDC_RADIO_CHOICE_2, &CDlgSideChannelAttackVisualizationHEPreparationsRequest2::OnBnClickedRadioChoice2) + ON_BN_CLICKED(IDC_RADIO_CHOICE_3, &CDlgSideChannelAttackVisualizationHEPreparationsRequest2::OnBnClickedRadioChoice3) END_MESSAGE_MAP() // CDlgSideChannelAttackVisualizationHEPreparationsRequest2 message handlers diff --git a/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest3.cpp b/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest3.cpp index a99844f6f..76612905d 100644 --- a/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest3.cpp +++ b/CrypTool/DlgSideChannelAttackVisualizationHEPreparationsRequest3.cpp @@ -61,11 +61,11 @@ BOOL CDlgSideChannelAttackVisualizationHEPreparationsRequest3::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgSideChannelAttackVisualizationHEPreparationsRequest3, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel) - ON_BN_CLICKED(IDC_RADIO_CHOICE_1, OnBnClickedRadioChoice1) - ON_BN_CLICKED(IDC_RADIO_CHOICE_2, OnBnClickedRadioChoice2) - ON_BN_CLICKED(IDC_RADIO_CHOICE_3, OnBnClickedRadioChoice3) + ON_BN_CLICKED(IDOK, &CDlgSideChannelAttackVisualizationHEPreparationsRequest3::OnBnClickedOk) + ON_BN_CLICKED(IDCANCEL, &CDlgSideChannelAttackVisualizationHEPreparationsRequest3::OnBnClickedCancel) + ON_BN_CLICKED(IDC_RADIO_CHOICE_1, &CDlgSideChannelAttackVisualizationHEPreparationsRequest3::OnBnClickedRadioChoice1) + ON_BN_CLICKED(IDC_RADIO_CHOICE_2, &CDlgSideChannelAttackVisualizationHEPreparationsRequest3::OnBnClickedRadioChoice2) + ON_BN_CLICKED(IDC_RADIO_CHOICE_3, &CDlgSideChannelAttackVisualizationHEPreparationsRequest3::OnBnClickedRadioChoice3) END_MESSAGE_MAP() // CDlgSideChannelAttackVisualizationHEPreparationsRequest3 message handlers diff --git a/CrypTool/DlgSideChannelAttackVisualizationHETrudy.cpp b/CrypTool/DlgSideChannelAttackVisualizationHETrudy.cpp index 53cecc42f..a06f4d96c 100644 --- a/CrypTool/DlgSideChannelAttackVisualizationHETrudy.cpp +++ b/CrypTool/DlgSideChannelAttackVisualizationHETrudy.cpp @@ -25,7 +25,7 @@ #include "CrypToolApp.h" #include "DlgSideChannelAttackVisualizationHETrudy.h" #include "CrypToolTools.h" -#include ".\dlgsidechannelattackvisualizationhetrudy.h" +#include "DlgSideChannelAttackVisualizationHETrudy.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -82,7 +82,7 @@ void CDlgSideChannelAttackVisualizationHETrudy::DoDataExchange(CDataExchange* pD BEGIN_MESSAGE_MAP(CDlgSideChannelAttackVisualizationHETrudy, CDialog) //{{AFX_MSG_MAP(CDlgSideChannelAttackVisualizationHETrudy) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDOK, &CDlgSideChannelAttackVisualizationHETrudy::OnBnClickedOk) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// diff --git a/CrypTool/DlgSigAttModificDemo.cpp b/CrypTool/DlgSigAttModificDemo.cpp index f510e7493..17599ca76 100644 --- a/CrypTool/DlgSigAttModificDemo.cpp +++ b/CrypTool/DlgSigAttModificDemo.cpp @@ -78,13 +78,13 @@ void CDlgSigAttModificDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSigAttModificDemo, CDialog) //{{AFX_MSG_MAP(CDlgSigAttModificDemo) - ON_BN_CLICKED(IDOK, OnModify) - ON_BN_CLICKED(IDC_RADIO2, OnAttachment) - ON_BN_CLICKED(IDC_METHOD, OnMethod) - ON_BN_CLICKED(IDC_RADIO3, OnPrintable) - ON_BN_CLICKED(IDC_RADIO4, OnUnprintable) - ON_EN_UPDATE(IDC_HASHVALUE, OnUpdateHashvalue) - ON_EN_UPDATE(IDC_SIGBIT, OnUpdateSigbit) + ON_BN_CLICKED(IDOK, &CDlgSigAttModificDemo::OnModify) + ON_BN_CLICKED(IDC_RADIO2, &CDlgSigAttModificDemo::OnAttachment) + ON_BN_CLICKED(IDC_METHOD, &CDlgSigAttModificDemo::OnMethod) + ON_BN_CLICKED(IDC_RADIO3, &CDlgSigAttModificDemo::OnPrintable) + ON_BN_CLICKED(IDC_RADIO4, &CDlgSigAttModificDemo::OnUnprintable) + ON_EN_UPDATE(IDC_HASHVALUE, &CDlgSigAttModificDemo::OnUpdateHashvalue) + ON_EN_UPDATE(IDC_SIGBIT, &CDlgSigAttModificDemo::OnUpdateSigbit) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -210,7 +210,7 @@ void CDlgSigAttModificDemo::OnModify() NewDocument = theApp.OpenDocumentFileNoMRU(outfile); char title[1024]; - _snprintf(title, sizeof(title) - 1, "Modifikation von <%s>", m_Title); + _snprintf(title, sizeof(title) - 1, "Modifikation von <%s>", (LPCTSTR)m_Title); NewDocument->SetTitle(title); delete m_Document; diff --git a/CrypTool/DlgSignature.cpp b/CrypTool/DlgSignature.cpp index 3d1eedc9d..ccc10cf1c 100644 --- a/CrypTool/DlgSignature.cpp +++ b/CrypTool/DlgSignature.cpp @@ -209,19 +209,19 @@ void CDlgSignature::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSignature, CDialog) //{{AFX_MSG_MAP(CDlgSignature) - ON_NOTIFY(NM_CLICK, IDC_LIST2, OnClickList2) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST2, OnItemclickList2) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, OnColumnclickList2) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, OnKeydownList2) - ON_BN_CLICKED(IDC_CHECK_DSA_KEYS, OnCheckDsaKeys) - ON_BN_CLICKED(IDC_CHECK_EC_KEYS, OnCheckEcKeys) - ON_BN_CLICKED(IDC_CHECK_RSA_KEYS, OnCheckRsaKeys) - ON_BN_CLICKED(IDC_RADIO6, OnRadioRSA) - ON_BN_CLICKED(IDC_RADIO7, OnRadioDSA) - ON_BN_CLICKED(IDC_RADIO8, OnRadioECDSA) - ON_BN_CLICKED(IDC_RADIO9, OnRadioECNR) - ON_BN_CLICKED(IDC_RADIO10, OnRadioAffinCoord) - ON_BN_CLICKED(IDC_RADIO11, OnRadioProjectCoord) + ON_NOTIFY(NM_CLICK, IDC_LIST2, &CDlgSignature::OnClickList2) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST2, &CDlgSignature::OnItemclickList2) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, &CDlgSignature::OnColumnclickList2) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, &CDlgSignature::OnKeydownList2) + ON_BN_CLICKED(IDC_CHECK_DSA_KEYS, &CDlgSignature::OnCheckDsaKeys) + ON_BN_CLICKED(IDC_CHECK_EC_KEYS, &CDlgSignature::OnCheckEcKeys) + ON_BN_CLICKED(IDC_CHECK_RSA_KEYS, &CDlgSignature::OnCheckRsaKeys) + ON_BN_CLICKED(IDC_RADIO6, &CDlgSignature::OnRadioRSA) + ON_BN_CLICKED(IDC_RADIO7, &CDlgSignature::OnRadioDSA) + ON_BN_CLICKED(IDC_RADIO8, &CDlgSignature::OnRadioECDSA) + ON_BN_CLICKED(IDC_RADIO9, &CDlgSignature::OnRadioECNR) + ON_BN_CLICKED(IDC_RADIO10, &CDlgSignature::OnRadioAffinCoord) + ON_BN_CLICKED(IDC_RADIO11, &CDlgSignature::OnRadioProjectCoord) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgSignature.h b/CrypTool/DlgSignature.h index 3fac246bd..19db5d6d0 100644 --- a/CrypTool/DlgSignature.h +++ b/CrypTool/DlgSignature.h @@ -41,7 +41,7 @@ class CDlgSignature : public CDialog public: CDlgSignature(CWnd* pParent = NULL); // Standardkonstruktor - CDlgSignature::~CDlgSignature(); + ~CDlgSignature(); // Dialogfelddaten //{{AFX_DATA(CDlgSignature) diff --git a/CrypTool/DlgSignatureAttack.cpp b/CrypTool/DlgSignatureAttack.cpp index 436745c6f..82eb75eeb 100644 --- a/CrypTool/DlgSignatureAttack.cpp +++ b/CrypTool/DlgSignatureAttack.cpp @@ -47,7 +47,7 @@ using namespace std; #include "OptionsForSignatureAttack.h" #include "ErrorcodesForSignatureAttack.h" #include "DlgShowProgress.h" -#include ".\dlgsignatureattack.h" +#include "DlgSignatureAttack.h" // Verzeichnis, in dem CT gerade läuft (siehe CrypToolApp.cpp) extern char *Pfad; @@ -87,14 +87,14 @@ void CDlgSignatureAttack::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSignatureAttack, CDialog) //{{AFX_MSG_MAP(CDlgSignatureAttack) - ON_BN_CLICKED(IDC_OPTIONS, OnOptions) - ON_BN_CLICKED(IDC_BROWSE_HARMLESS, OnBrowseOriginal) - ON_BN_CLICKED(IDC_BROWSE_DANGEROUS, OnBrowseFake) - ON_BN_CLICKED(IDC_COMPUTE, OnCompute) - ON_EN_UPDATE(IDC_FILE_DANGEROUS, OnUpdateFileFake) - ON_EN_UPDATE(IDC_FILE_HARMLESS, OnUpdateFileOriginal) + ON_BN_CLICKED(IDC_OPTIONS, &CDlgSignatureAttack::OnOptions) + ON_BN_CLICKED(IDC_BROWSE_HARMLESS, &CDlgSignatureAttack::OnBrowseOriginal) + ON_BN_CLICKED(IDC_BROWSE_DANGEROUS, &CDlgSignatureAttack::OnBrowseFake) + ON_BN_CLICKED(IDC_COMPUTE, &CDlgSignatureAttack::OnCompute) + ON_EN_UPDATE(IDC_FILE_DANGEROUS, &CDlgSignatureAttack::OnUpdateFileFake) + ON_EN_UPDATE(IDC_FILE_HARMLESS, &CDlgSignatureAttack::OnUpdateFileOriginal) //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_BUTTON_USEDEFAULTMESSAGES, OnBnClickedButtonUsedefaultmessages) + ON_BN_CLICKED(IDC_BUTTON_USEDEFAULTMESSAGES, &CDlgSignatureAttack::OnBnClickedButtonUsedefaultmessages) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -258,9 +258,9 @@ void CDlgSignatureAttack::batchAttack() ifstr_Harmless.open(m_file_harmless, ios::in | ios::binary); ifstr_Dangerous.open(m_file_dangerous, ios::in | ios::binary); - _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", LogPath, StartTime, _SIG_ATT_HARMLESS); + _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", (LPCTSTR)LogPath, StartTime, _SIG_ATT_HARMLESS); ofstr_Harmless.open(FilePath, ios::out | ios::binary); - _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", LogPath, StartTime, _SIG_ATT_DANGEROUS); + _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", (LPCTSTR)LogPath, StartTime, _SIG_ATT_DANGEROUS); ofstr_Dangerous.open(FilePath, ios::out | ios::binary); if (!ifstr_Harmless || !ifstr_Dangerous || !ofstr_Harmless || !ofstr_Dangerous) { @@ -299,7 +299,7 @@ void CDlgSignatureAttack::batchAttack() delete []HarmlessText; delete []DangerousText; - _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", LogPath, StartTime, _SIG_ATT_HEADER); + _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", (LPCTSTR)LogPath, StartTime, _SIG_ATT_HEADER); SigAttTest = fopen(FilePath, "w+"); if (NULL == SigAttTest) { @@ -318,7 +318,7 @@ void CDlgSignatureAttack::batchAttack() "LogPath=%s\\\n", l_SignificantBitLengthMIN , l_SignificantBitLengthMAX, l_SignificantBitLengthJump, l_HashAlgorithmIDMIN, l_HashAlgorithmIDMAX, l_Attempts, - m_file_harmless, m_file_dangerous, LogPath); + (LPCTSTR)m_file_harmless, (LPCTSTR)m_file_dangerous, (LPCTSTR)LogPath); unsigned long u_SignatureAttackModificationMethod = 0; CT_OPEN_REGISTRY_SETTINGS( KEY_ALL_ACCESS, IDS_REGISTRY_SETTINGS, "SignatureAttack" ); @@ -326,8 +326,8 @@ void CDlgSignatureAttack::batchAttack() fprintf(SigAttTest, "\n\nInternal Information\n\nModificationMethod=%d\nHarmlessFile=%s\\%d%s\nHarmlessFileLength=%d\nDangerousFile=%s\\%d%s\nDangerousFileLength=%d", u_SignatureAttackModificationMethod, - LogPath, StartTime, _SIG_ATT_HARMLESS, HarmlessDocLength, - LogPath, StartTime, _SIG_ATT_DANGEROUS, DangerousDocLength); + (LPCTSTR)LogPath, StartTime, _SIG_ATT_HARMLESS, HarmlessDocLength, + (LPCTSTR)LogPath, StartTime, _SIG_ATT_DANGEROUS, DangerousDocLength); #ifdef _SIG_ATT_SPEED_INCREMENT fprintf(SigAttTest, "\nModifyOriginalDocumentBeforeRun=1"); @@ -355,7 +355,7 @@ void CDlgSignatureAttack::batchAttack() fprintf(SigAttTest, "\nComments=%s", tmpStr); fclose(SigAttTest); - _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", LogPath, StartTime, _SIG_ATT_LOG); + _snprintf(FilePath, sizeof(FilePath) - 1, "%s\\%d%s", (LPCTSTR)LogPath, StartTime, _SIG_ATT_LOG); SigAttTest = fopen(FilePath, "w+"); if (NULL == SigAttTest) { @@ -500,7 +500,7 @@ void CDlgSignatureAttack::OnCompute() hashhex[strlen - 1] = '\0'; _snprintf(doctitle, sizeof(doctitle) - 1, "%s%s, <%s>", - msg, OFSA.GetHashOp()->GetHashAlgorithmName(), hashhex); + (LPCTSTR)msg, OFSA.GetHashOp()->GetHashAlgorithmName(), hashhex); NewHarmlessDocument->SetTitle(doctitle); GetTmpName(outfile,"cry",".tmp"); @@ -519,7 +519,7 @@ void CDlgSignatureAttack::OnCompute() // Dokumenttitel für 2. Dokument erstellen: msg.Format(IDS_STRING_SIG_ATT_DOCUMENT_TITLE_DANGEROUS); _snprintf(doctitle, sizeof(doctitle) - 1, "%s%s, <%s>", - msg, OFSA.GetHashOp()->GetHashAlgorithmName(), hashhex); + (LPCTSTR)msg, OFSA.GetHashOp()->GetHashAlgorithmName(), hashhex); NewDangerousDocument->SetTitle(doctitle); HIDE_HOUR_GLASS diff --git a/CrypTool/DlgSignatureDemo.cpp b/CrypTool/DlgSignatureDemo.cpp index 211b72518..39e6c87a5 100644 --- a/CrypTool/DlgSignatureDemo.cpp +++ b/CrypTool/DlgSignatureDemo.cpp @@ -87,20 +87,20 @@ void CDlgSignatureDemo::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSignatureDemo, CDialog) //{{AFX_MSG_MAP(CDlgSignatureDemo) - ON_BN_CLICKED(IDC_SELECT_DOCUMENT, OnSelectDocument) - ON_BN_CLICKED(IDC_INFO_DOCUMENT, OnInfoDocument) - ON_BN_CLICKED(IDC_SELECT_KEY, OnSelectKey) - ON_BN_CLICKED(IDC_INFO_KEY, OnInfoKey) - ON_BN_CLICKED(IDC_SELECT_HASHALG, OnSelectHashAlg) - ON_BN_CLICKED(IDC_COMPUTE, OnCompute) - ON_BN_CLICKED(IDC_INFO_HASH, OnInfoHash) - ON_BN_CLICKED(IDC_ENCRYPT, OnEncrypt) - ON_BN_CLICKED(IDC_INFO_HASH_ENC, OnInfoHashEnc) - ON_BN_CLICKED(IDC_SELECT_CERT, OnSelectCert) - ON_BN_CLICKED(IDC_INFO_ALG, OnInfoAlg) - ON_BN_CLICKED(IDC_COMBINE, OnCombine) - ON_BN_CLICKED(IDC_INFO_CERT, OnInfoCert) - ON_BN_CLICKED(IDC_INFO_SIGN, OnInfoSign) + ON_BN_CLICKED(IDC_SELECT_DOCUMENT, &CDlgSignatureDemo::OnSelectDocument) + ON_BN_CLICKED(IDC_INFO_DOCUMENT, &CDlgSignatureDemo::OnInfoDocument) + ON_BN_CLICKED(IDC_SELECT_KEY, &CDlgSignatureDemo::OnSelectKey) + ON_BN_CLICKED(IDC_INFO_KEY, &CDlgSignatureDemo::OnInfoKey) + ON_BN_CLICKED(IDC_SELECT_HASHALG, &CDlgSignatureDemo::OnSelectHashAlg) + ON_BN_CLICKED(IDC_COMPUTE, &CDlgSignatureDemo::OnCompute) + ON_BN_CLICKED(IDC_INFO_HASH, &CDlgSignatureDemo::OnInfoHash) + ON_BN_CLICKED(IDC_ENCRYPT, &CDlgSignatureDemo::OnEncrypt) + ON_BN_CLICKED(IDC_INFO_HASH_ENC, &CDlgSignatureDemo::OnInfoHashEnc) + ON_BN_CLICKED(IDC_SELECT_CERT, &CDlgSignatureDemo::OnSelectCert) + ON_BN_CLICKED(IDC_INFO_ALG, &CDlgSignatureDemo::OnInfoAlg) + ON_BN_CLICKED(IDC_COMBINE, &CDlgSignatureDemo::OnCombine) + ON_BN_CLICKED(IDC_INFO_CERT, &CDlgSignatureDemo::OnInfoCert) + ON_BN_CLICKED(IDC_INFO_SIGN, &CDlgSignatureDemo::OnInfoSign) ON_WM_PAINT() //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -265,13 +265,13 @@ void CDlgSignatureDemo::OnInfoKey() m_DisplayContent.LoadString(IDS_CONTENT_KEY); sOutput.Format(IDS_BITLENGTH_MODN, m_Cert->GetBitLength()); m_DisplayInfo += sOutput; - sOutput.Format(IDS_MOD_N, sModN); + sOutput.Format(IDS_MOD_N, (LPCTSTR)sModN); m_DisplayInfo += sOutput; - sOutput.Format(IDS_PHI_N, sPhiN); + sOutput.Format(IDS_PHI_N, (LPCTSTR)sPhiN); m_DisplayInfo += sOutput; - sOutput.Format(IDS_KEY_PUBLIC, sKeyPublic); + sOutput.Format(IDS_KEY_PUBLIC, (LPCTSTR)sKeyPublic); m_DisplayInfo += sOutput; - sOutput.Format(IDS_KEY_PRIVATE, sKeyPrivate); + sOutput.Format(IDS_KEY_PRIVATE, (LPCTSTR)sKeyPrivate); m_DisplayInfo += sOutput; UpdateData(FALSE); } @@ -524,7 +524,7 @@ void CDlgSignatureDemo::OnInfoHash() UpdateData(TRUE); int srcSize = m_osHash.noctets; dataToHexDump(m_osHash.octets, m_osHash.noctets, m_DisplayInfo); /*FIXME*/ - m_DisplayContent.Format(IDS_STRING_HASH_VALUE_OF, m_Cert->GetHashAlg(), m_sFileName); + m_DisplayContent.Format(IDS_STRING_HASH_VALUE_OF, (LPCTSTR)m_Cert->GetHashAlg(), (LPCTSTR)m_sFileName); UpdateData(FALSE); } @@ -582,17 +582,17 @@ void CDlgSignatureDemo::OnInfoHashEnc() UpdateData(TRUE); m_DisplayInfo.Empty(); m_DisplayContent.LoadString(IDS_CONTENT_HASH_ENC); - Text.Format(IDS_PADDING, Padding); + Text.Format(IDS_PADDING, (LPCTSTR)Padding); m_DisplayInfo += Text; - Text.Format(IDS_DERCODE, Encoding); + Text.Format(IDS_DERCODE, (LPCTSTR)Encoding); m_DisplayInfo += Text; - Text.Format(IDS_HASHVALUE, Hash); + Text.Format(IDS_HASHVALUE, (LPCTSTR)Hash); m_DisplayInfo += Text+"\r\n"; - Text.Format(IDS_HASHDER, HashDER); + Text.Format(IDS_HASHDER, (LPCTSTR)HashDER); m_DisplayInfo += Text; Text.Format(IDS_BITLENGTH, m_osHashDER.noctets*8); m_DisplayInfo += Text+"\r\n"; - Text.Format(IDS_HASHENC, HashEnc); + Text.Format(IDS_HASHENC, (LPCTSTR)HashEnc); m_DisplayInfo += Text; Text.Format(IDS_BITLENGTH, m_osHashEnc.noctets*8); m_DisplayInfo += Text+"\r\n"; @@ -644,11 +644,11 @@ void CDlgSignatureDemo::OnInfoAlg() UpdateData(TRUE); m_DisplayInfo.Empty(); m_DisplayContent.LoadString(IDS_CONTENT_ALG); - Text.Format(IDS_NAME2, m_Cert->GetHashAlg(), ""); + Text.Format(IDS_NAME2, (LPCTSTR)m_Cert->GetHashAlg(), ""); m_DisplayInfo += Text; Text.Format(IDS_BITLENGTH, m_Cert->GetHashLength()); m_DisplayInfo += Text; - Text.Format(IDS_DERCODE, Encoding); + Text.Format(IDS_DERCODE, (LPCTSTR)Encoding); m_DisplayInfo += Text; UpdateData(FALSE); @@ -682,17 +682,17 @@ void CDlgSignatureDemo::OnOK() theApp.SecudeLib.aux_OctetString2file(&m_SignText, outfile,2); NewDoc = theApp.OpenDocumentFileNoMRU(outfile); remove(outfile); - m_sFileNameNew.Format(IDS_RSA_SIGNATURE_OF, m_Cert->GetHashAlg(), m_sFileName); + m_sFileNameNew.Format(IDS_RSA_SIGNATURE_OF, (LPCTSTR)m_Cert->GetHashAlg(), (LPCTSTR)m_sFileName); NewDoc->SetTitle(m_sFileNameNew); CString Text; CString Msg; Msg.LoadString(IDS_CONGRATULATIONS); - Text.Format(IDS_RSASGN_DOCNAME, m_sFileName); + Text.Format(IDS_RSASGN_DOCNAME, (LPCTSTR)m_sFileName); Msg += Text; - Text.Format(m_bPSEIsExtern? IDS_RSASGN_PSE_IMP: IDS_RSASGN_PSE, m_Cert->CreateUserKeyID()); + Text.Format(m_bPSEIsExtern? IDS_RSASGN_PSE_IMP: IDS_RSASGN_PSE, (LPCTSTR)m_Cert->CreateUserKeyID()); Msg += Text; - Text.Format(IDS_RSASGN_ALG, m_Cert->GetHashAlg()); + Text.Format(IDS_RSASGN_ALG, (LPCTSTR)m_Cert->GetHashAlg()); Msg += Text; AfxMessageBox(Msg, MB_OK | MB_ICONINFORMATION); } @@ -725,7 +725,7 @@ void CDlgSignatureDemo::OnInfoSign() if (!HexDumpMem(msgdata, destSize, reinterpret_cast(m_SignText.octets), srcSize, m_nCols)) return; UpdateData(TRUE); - m_DisplayContent.Format(IDS_CONTENT_SIGN, m_Cert->GetHashAlg(), m_sFileName); + m_DisplayContent.Format(IDS_CONTENT_SIGN, (LPCTSTR)m_Cert->GetHashAlg(), (LPCTSTR)m_sFileName); m_DisplayInfo = static_cast(msgdata); UpdateData(FALSE); } diff --git a/CrypTool/DlgSimpleTranspositions.cpp b/CrypTool/DlgSimpleTranspositions.cpp index 8595364b2..0e57ebf80 100644 --- a/CrypTool/DlgSimpleTranspositions.cpp +++ b/CrypTool/DlgSimpleTranspositions.cpp @@ -67,10 +67,10 @@ void CDlgSimpleTranspositions::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgSimpleTranspositions, CDialog) ON_BN_CLICKED(ID_ENCRYPT, &CDlgSimpleTranspositions::OnBnClickedEncrypt) ON_BN_CLICKED(ID_DECRYPT, &CDlgSimpleTranspositions::OnBnClickedDecrypt) - ON_BN_CLICKED(IDC_RADIO_SCYTALE, OnRadioScytale) - ON_BN_CLICKED(IDC_RADIO_RAIL_FENCE, OnRadioRailFence) + ON_BN_CLICKED(IDC_RADIO_SCYTALE, &CDlgSimpleTranspositions::OnRadioScytale) + ON_BN_CLICKED(IDC_RADIO_RAIL_FENCE, &CDlgSimpleTranspositions::OnRadioRailFence) ON_BN_CLICKED(ID_TEXTOPTIONS, &CDlgSimpleTranspositions::OnBnClickedTextoptions) - ON_BN_CLICKED(IDC_PASTE_KEY, OnPasteKey) + ON_BN_CLICKED(IDC_PASTE_KEY, &CDlgSimpleTranspositions::OnPasteKey) END_MESSAGE_MAP() BOOL CDlgSimpleTranspositions::OnInitDialog() diff --git a/CrypTool/DlgSolitaire.cpp b/CrypTool/DlgSolitaire.cpp index b48907242..c914bb42c 100644 --- a/CrypTool/DlgSolitaire.cpp +++ b/CrypTool/DlgSolitaire.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgSolitaire.h" -#include ".\dlgsolitaire.h" +#include "DlgSolitaire.h" #include "FileTools.h" #include "CrypToolTools.h" #include "KeyRepository.h" @@ -68,7 +68,7 @@ bool CDlgSolitaire::load_infile() { ifstream i_file; in_buffer_size = 0; - i_file.open( infile, ios::in || ios::binary ); + i_file.open( infile, ios::in ); // was "ios::in || ios::binary", which evaluates to ios::in if ( i_file.is_open() ) { if ( !in_buffer ) in_buffer = new unsigned char[4000]; @@ -270,7 +270,8 @@ void CDlgSolitaire::ChangeConfiguration() char str[256]; fin.read(str,255); fin.close(); - if ( deck.set_deck(CString(str)) ) + CString deckString(str); + if ( deck.set_deck(deckString) ) { InitialDeck = str; UpdateData(false); @@ -373,82 +374,82 @@ BOOL CDlgSolitaire::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgSolitaire, CDialog) - ON_CBN_SELCHANGE(IDC_Kartenanzahl, OnCbnSelchangeKartenanzahl) - ON_CBN_SELCHANGE(IDC_COMBO2, OnCbnSelchangeCombo2) - ON_BN_CLICKED(IDC_BUTTON61, OnBnClickedButton61) - ON_BN_CLICKED(IDC_BUTTON9, OnBnClickedButton9) - ON_BN_CLICKED(IDC_BUTTON4, OnBnClickedCryptStep1) - ON_BN_CLICKED(IDC_BUTTON5, OnBnClickedCryptStep2) - ON_BN_CLICKED(IDC_BUTTON6, OnBnClickedCryptStep3) - ON_BN_CLICKED(IDC_BUTTON7, OnBnClickedCryptStep4) - ON_BN_CLICKED(IDC_BUTTON8, OnBnClickedCryptStep5) - ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedDoCrypt) - ON_BN_CLICKED(IDC_BUTTON3, OnBnClickedDoCryptSteps) - ON_BN_CLICKED(IDC_BUTTON10, OnBnClickedButton10) - ON_BN_CLICKED(IDC_BUTTON11, OnBnClickedButton11) - ON_BN_CLICKED(IDC_BUTTON12, OnBnClickedButton12) - ON_BN_CLICKED(IDC_BUTTON13, OnBnClickedButton13) - ON_BN_CLICKED(IDC_BUTTON14, OnBnClickedButton14) - ON_BN_CLICKED(IDC_BUTTON15, OnBnClickedButton15) - ON_BN_CLICKED(IDC_BUTTON16, OnBnClickedButton16) - ON_BN_CLICKED(IDC_BUTTON17, OnBnClickedButton17) - ON_BN_CLICKED(IDC_BUTTON18, OnBnClickedButton18) - ON_BN_CLICKED(IDC_BUTTON19, OnBnClickedButton19) - ON_BN_CLICKED(IDC_BUTTON20, OnBnClickedButton20) - ON_BN_CLICKED(IDC_BUTTON21, OnBnClickedButton21) - ON_BN_CLICKED(IDC_BUTTON22, OnBnClickedButton22) - ON_BN_CLICKED(IDC_BUTTON23, OnBnClickedButton23) - ON_BN_CLICKED(IDC_BUTTON24, OnBnClickedButton24) - ON_BN_CLICKED(IDC_BUTTON25, OnBnClickedButton25) - ON_BN_CLICKED(IDC_BUTTON26, OnBnClickedButton26) - ON_BN_CLICKED(IDC_BUTTON27, OnBnClickedButton27) - ON_BN_CLICKED(IDC_BUTTON28, OnBnClickedButton28) - ON_BN_CLICKED(IDC_BUTTON29, OnBnClickedButton29) - ON_BN_CLICKED(IDC_BUTTON30, OnBnClickedButton30) - ON_BN_CLICKED(IDC_BUTTON31, OnBnClickedButton31) - ON_BN_CLICKED(IDC_BUTTON32, OnBnClickedButton32) - ON_BN_CLICKED(IDC_BUTTON33, OnBnClickedButton33) - ON_BN_CLICKED(IDC_BUTTON34, OnBnClickedButton34) - ON_BN_CLICKED(IDC_BUTTON35, OnBnClickedButton35) - ON_BN_CLICKED(IDC_BUTTON36, OnBnClickedButton36) - ON_BN_CLICKED(IDC_BUTTON37, OnBnClickedButton37) - ON_BN_CLICKED(IDC_BUTTON38, OnBnClickedButton38) - ON_BN_CLICKED(IDC_BUTTON39, OnBnClickedButton39) - ON_BN_CLICKED(IDC_BUTTON40, OnBnClickedButton40) - ON_BN_CLICKED(IDC_BUTTON41, OnBnClickedButton41) - ON_BN_CLICKED(IDC_BUTTON42, OnBnClickedButton42) - ON_BN_CLICKED(IDC_BUTTON43, OnBnClickedButton43) - ON_BN_CLICKED(IDC_BUTTON44, OnBnClickedButton44) - ON_BN_CLICKED(IDC_BUTTON45, OnBnClickedButton45) - ON_BN_CLICKED(IDC_BUTTON46, OnBnClickedButton46) - ON_BN_CLICKED(IDC_BUTTON47, OnBnClickedButton47) - ON_BN_CLICKED(IDC_BUTTON48, OnBnClickedButton48) - ON_BN_CLICKED(IDC_BUTTON49, OnBnClickedButton49) - ON_BN_CLICKED(IDC_BUTTON50, OnBnClickedButton50) - ON_BN_CLICKED(IDC_BUTTON51, OnBnClickedButton51) - ON_BN_CLICKED(IDC_BUTTON52, OnBnClickedButton52) - ON_BN_CLICKED(IDC_BUTTON53, OnBnClickedButton53) - ON_BN_CLICKED(IDC_BUTTON54, OnBnClickedButton54) - ON_BN_CLICKED(IDC_BUTTON55, OnBnClickedButton55) - ON_BN_CLICKED(IDC_BUTTON56, OnBnClickedButton56) - ON_BN_CLICKED(IDC_BUTTON57, OnBnClickedButton57) - ON_BN_CLICKED(IDC_BUTTON58, OnBnClickedButton58) - ON_BN_CLICKED(IDC_BUTTON59, OnBnClickedButton59) - ON_BN_CLICKED(IDC_BUTTON60, OnBnClickedButton60) - ON_BN_CLICKED(IDC_BUTTON62, OnBnClickedButton62) - ON_BN_CLICKED(IDC_BUTTON63, OnResetCardSettings) - ON_EN_CHANGE(IDC_EDIT4, OnEnChangePassword) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedModifyDeckByPassword) - ON_BN_CLICKED(IDC_BUTTON64, OnBnClickedSaveDeck) - ON_BN_CLICKED(IDC_BUTTON65, OnBnClickedSaveFinalDeck) - ON_BN_CLICKED(IDC_BUTTON67, OnBnCancel) - ON_BN_CLICKED(IDC_BUTTON66, OnEncrypt) - ON_BN_CLICKED(IDC_BUTTON68, OnDecrypt) - ON_BN_CLICKED(IDC_PASTE_KEY, OnPasteKey) - ON_BN_CLICKED(IDC_BUTTON69, OnBnFinishCrypt) - ON_BN_CLICKED(IDC_BUTTON71, OnBnReInit) - ON_BN_CLICKED(IDC_BUTTON70, OnBnNewShuffle) - ON_BN_CLICKED(IDC_BUTTON72, OnBnSaveKeyStream) + ON_CBN_SELCHANGE(IDC_Kartenanzahl, &CDlgSolitaire::OnCbnSelchangeKartenanzahl) + ON_CBN_SELCHANGE(IDC_COMBO2, &CDlgSolitaire::OnCbnSelchangeCombo2) + ON_BN_CLICKED(IDC_BUTTON61, &CDlgSolitaire::OnBnClickedButton61) + ON_BN_CLICKED(IDC_BUTTON9, &CDlgSolitaire::OnBnClickedButton9) + ON_BN_CLICKED(IDC_BUTTON4, &CDlgSolitaire::OnBnClickedCryptStep1) + ON_BN_CLICKED(IDC_BUTTON5, &CDlgSolitaire::OnBnClickedCryptStep2) + ON_BN_CLICKED(IDC_BUTTON6, &CDlgSolitaire::OnBnClickedCryptStep3) + ON_BN_CLICKED(IDC_BUTTON7, &CDlgSolitaire::OnBnClickedCryptStep4) + ON_BN_CLICKED(IDC_BUTTON8, &CDlgSolitaire::OnBnClickedCryptStep5) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgSolitaire::OnBnClickedDoCrypt) + ON_BN_CLICKED(IDC_BUTTON3, &CDlgSolitaire::OnBnClickedDoCryptSteps) + ON_BN_CLICKED(IDC_BUTTON10, &CDlgSolitaire::OnBnClickedButton10) + ON_BN_CLICKED(IDC_BUTTON11, &CDlgSolitaire::OnBnClickedButton11) + ON_BN_CLICKED(IDC_BUTTON12, &CDlgSolitaire::OnBnClickedButton12) + ON_BN_CLICKED(IDC_BUTTON13, &CDlgSolitaire::OnBnClickedButton13) + ON_BN_CLICKED(IDC_BUTTON14, &CDlgSolitaire::OnBnClickedButton14) + ON_BN_CLICKED(IDC_BUTTON15, &CDlgSolitaire::OnBnClickedButton15) + ON_BN_CLICKED(IDC_BUTTON16, &CDlgSolitaire::OnBnClickedButton16) + ON_BN_CLICKED(IDC_BUTTON17, &CDlgSolitaire::OnBnClickedButton17) + ON_BN_CLICKED(IDC_BUTTON18, &CDlgSolitaire::OnBnClickedButton18) + ON_BN_CLICKED(IDC_BUTTON19, &CDlgSolitaire::OnBnClickedButton19) + ON_BN_CLICKED(IDC_BUTTON20, &CDlgSolitaire::OnBnClickedButton20) + ON_BN_CLICKED(IDC_BUTTON21, &CDlgSolitaire::OnBnClickedButton21) + ON_BN_CLICKED(IDC_BUTTON22, &CDlgSolitaire::OnBnClickedButton22) + ON_BN_CLICKED(IDC_BUTTON23, &CDlgSolitaire::OnBnClickedButton23) + ON_BN_CLICKED(IDC_BUTTON24, &CDlgSolitaire::OnBnClickedButton24) + ON_BN_CLICKED(IDC_BUTTON25, &CDlgSolitaire::OnBnClickedButton25) + ON_BN_CLICKED(IDC_BUTTON26, &CDlgSolitaire::OnBnClickedButton26) + ON_BN_CLICKED(IDC_BUTTON27, &CDlgSolitaire::OnBnClickedButton27) + ON_BN_CLICKED(IDC_BUTTON28, &CDlgSolitaire::OnBnClickedButton28) + ON_BN_CLICKED(IDC_BUTTON29, &CDlgSolitaire::OnBnClickedButton29) + ON_BN_CLICKED(IDC_BUTTON30, &CDlgSolitaire::OnBnClickedButton30) + ON_BN_CLICKED(IDC_BUTTON31, &CDlgSolitaire::OnBnClickedButton31) + ON_BN_CLICKED(IDC_BUTTON32, &CDlgSolitaire::OnBnClickedButton32) + ON_BN_CLICKED(IDC_BUTTON33, &CDlgSolitaire::OnBnClickedButton33) + ON_BN_CLICKED(IDC_BUTTON34, &CDlgSolitaire::OnBnClickedButton34) + ON_BN_CLICKED(IDC_BUTTON35, &CDlgSolitaire::OnBnClickedButton35) + ON_BN_CLICKED(IDC_BUTTON36, &CDlgSolitaire::OnBnClickedButton36) + ON_BN_CLICKED(IDC_BUTTON37, &CDlgSolitaire::OnBnClickedButton37) + ON_BN_CLICKED(IDC_BUTTON38, &CDlgSolitaire::OnBnClickedButton38) + ON_BN_CLICKED(IDC_BUTTON39, &CDlgSolitaire::OnBnClickedButton39) + ON_BN_CLICKED(IDC_BUTTON40, &CDlgSolitaire::OnBnClickedButton40) + ON_BN_CLICKED(IDC_BUTTON41, &CDlgSolitaire::OnBnClickedButton41) + ON_BN_CLICKED(IDC_BUTTON42, &CDlgSolitaire::OnBnClickedButton42) + ON_BN_CLICKED(IDC_BUTTON43, &CDlgSolitaire::OnBnClickedButton43) + ON_BN_CLICKED(IDC_BUTTON44, &CDlgSolitaire::OnBnClickedButton44) + ON_BN_CLICKED(IDC_BUTTON45, &CDlgSolitaire::OnBnClickedButton45) + ON_BN_CLICKED(IDC_BUTTON46, &CDlgSolitaire::OnBnClickedButton46) + ON_BN_CLICKED(IDC_BUTTON47, &CDlgSolitaire::OnBnClickedButton47) + ON_BN_CLICKED(IDC_BUTTON48, &CDlgSolitaire::OnBnClickedButton48) + ON_BN_CLICKED(IDC_BUTTON49, &CDlgSolitaire::OnBnClickedButton49) + ON_BN_CLICKED(IDC_BUTTON50, &CDlgSolitaire::OnBnClickedButton50) + ON_BN_CLICKED(IDC_BUTTON51, &CDlgSolitaire::OnBnClickedButton51) + ON_BN_CLICKED(IDC_BUTTON52, &CDlgSolitaire::OnBnClickedButton52) + ON_BN_CLICKED(IDC_BUTTON53, &CDlgSolitaire::OnBnClickedButton53) + ON_BN_CLICKED(IDC_BUTTON54, &CDlgSolitaire::OnBnClickedButton54) + ON_BN_CLICKED(IDC_BUTTON55, &CDlgSolitaire::OnBnClickedButton55) + ON_BN_CLICKED(IDC_BUTTON56, &CDlgSolitaire::OnBnClickedButton56) + ON_BN_CLICKED(IDC_BUTTON57, &CDlgSolitaire::OnBnClickedButton57) + ON_BN_CLICKED(IDC_BUTTON58, &CDlgSolitaire::OnBnClickedButton58) + ON_BN_CLICKED(IDC_BUTTON59, &CDlgSolitaire::OnBnClickedButton59) + ON_BN_CLICKED(IDC_BUTTON60, &CDlgSolitaire::OnBnClickedButton60) + ON_BN_CLICKED(IDC_BUTTON62, &CDlgSolitaire::OnBnClickedButton62) + ON_BN_CLICKED(IDC_BUTTON63, &CDlgSolitaire::OnResetCardSettings) + ON_EN_CHANGE(IDC_EDIT4, &CDlgSolitaire::OnEnChangePassword) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgSolitaire::OnBnClickedModifyDeckByPassword) + ON_BN_CLICKED(IDC_BUTTON64, &CDlgSolitaire::OnBnClickedSaveDeck) + ON_BN_CLICKED(IDC_BUTTON65, &CDlgSolitaire::OnBnClickedSaveFinalDeck) + ON_BN_CLICKED(IDC_BUTTON67, &CDlgSolitaire::OnBnCancel) + ON_BN_CLICKED(IDC_BUTTON66, &CDlgSolitaire::OnEncrypt) + ON_BN_CLICKED(IDC_BUTTON68, &CDlgSolitaire::OnDecrypt) + ON_BN_CLICKED(IDC_PASTE_KEY, &CDlgSolitaire::OnPasteKey) + ON_BN_CLICKED(IDC_BUTTON69, &CDlgSolitaire::OnBnFinishCrypt) + ON_BN_CLICKED(IDC_BUTTON71, &CDlgSolitaire::OnBnReInit) + ON_BN_CLICKED(IDC_BUTTON70, &CDlgSolitaire::OnBnNewShuffle) + ON_BN_CLICKED(IDC_BUTTON72, &CDlgSolitaire::OnBnSaveKeyStream) END_MESSAGE_MAP() void CDlgSolitaire::enableVorgabe(bool art) @@ -800,7 +801,8 @@ void CDlgSolitaire::OnPasteKey() LoadString(AfxGetInstanceHandle(),IDS_CRYPT_SOLITAIRE,pc_str,STR_LAENGE_STRING_TABLE); if(PasteKey(pc_str, buffer)) { - if ( deck.set_deck(CString(buffer)) ) + CString deckString(buffer); + if ( deck.set_deck(deckString) ) { InitialDeck = buffer; UpdateData(false); diff --git a/CrypTool/DlgSolitaireAnalyse.cpp b/CrypTool/DlgSolitaireAnalyse.cpp index 017f43d4f..2909f804d 100644 --- a/CrypTool/DlgSolitaireAnalyse.cpp +++ b/CrypTool/DlgSolitaireAnalyse.cpp @@ -24,7 +24,7 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "DlgSolitaireAnalyse.h" -#include ".\dlgsolitaireanalyse.h" +#include "DlgSolitaireAnalyse.h" #include "FileTools.h" #include "DialogeMessage.h" #include "CrypToolTools.h" @@ -146,70 +146,70 @@ BOOL CDlgSolitaireAnalyse::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgSolitaireAnalyse, CDialog) - ON_CBN_SELCHANGE(IDC_Kartenanzahl, OnCbnSelchangeKartenanzahl) - ON_BN_CLICKED(IDC_BUTTON40, OnBnClickedButton40) - ON_BN_CLICKED(IDC_BUTTON9, OnBnClickedButton9) - ON_BN_CLICKED(IDC_BUTTON10, OnBnClickedButton10) - ON_BN_CLICKED(IDC_BUTTON11, OnBnClickedButton11) - ON_BN_CLICKED(IDC_BUTTON12, OnBnClickedButton12) - ON_BN_CLICKED(IDC_BUTTON13, OnBnClickedButton13) - ON_BN_CLICKED(IDC_BUTTON14, OnBnClickedButton14) - ON_BN_CLICKED(IDC_BUTTON15, OnBnClickedButton15) - ON_BN_CLICKED(IDC_BUTTON16, OnBnClickedButton16) - ON_BN_CLICKED(IDC_BUTTON17, OnBnClickedButton17) - ON_BN_CLICKED(IDC_BUTTON18, OnBnClickedButton18) - ON_BN_CLICKED(IDC_BUTTON19, OnBnClickedButton19) - ON_BN_CLICKED(IDC_BUTTON20, OnBnClickedButton20) - ON_BN_CLICKED(IDC_BUTTON21, OnBnClickedButton21) - ON_BN_CLICKED(IDC_BUTTON22, OnBnClickedButton22) - ON_BN_CLICKED(IDC_BUTTON23, OnBnClickedButton23) - ON_BN_CLICKED(IDC_BUTTON24, OnBnClickedButton24) - ON_BN_CLICKED(IDC_BUTTON25, OnBnClickedButton25) - ON_BN_CLICKED(IDC_BUTTON26, OnBnClickedButton26) - ON_BN_CLICKED(IDC_BUTTON27, OnBnClickedButton27) - ON_BN_CLICKED(IDC_BUTTON28, OnBnClickedButton28) - ON_BN_CLICKED(IDC_BUTTON29, OnBnClickedButton29) - ON_BN_CLICKED(IDC_BUTTON30, OnBnClickedButton30) - ON_BN_CLICKED(IDC_BUTTON31, OnBnClickedButton31) - ON_BN_CLICKED(IDC_BUTTON32, OnBnClickedButton32) - ON_BN_CLICKED(IDC_BUTTON33, OnBnClickedButton33) - ON_BN_CLICKED(IDC_BUTTON34, OnBnClickedButton34) - ON_BN_CLICKED(IDC_BUTTON35, OnBnClickedButton35) - ON_BN_CLICKED(IDC_BUTTON36, OnBnClickedButton36) - ON_BN_CLICKED(IDC_BUTTON37, OnBnClickedButton37) - ON_BN_CLICKED(IDC_BUTTON38, OnBnClickedButton38) - ON_BN_CLICKED(IDC_BUTTON39, OnBnClickedButton39) - ON_BN_CLICKED(IDC_BUTTON41, OnBnClickedButton41) - ON_BN_CLICKED(IDC_BUTTON42, OnBnClickedButton42) - ON_BN_CLICKED(IDC_BUTTON43, OnBnClickedButton43) - ON_BN_CLICKED(IDC_BUTTON44, OnBnClickedButton44) - ON_BN_CLICKED(IDC_BUTTON45, OnBnClickedButton45) - ON_BN_CLICKED(IDC_BUTTON46, OnBnClickedButton46) - ON_BN_CLICKED(IDC_BUTTON47, OnBnClickedButton47) - ON_BN_CLICKED(IDC_BUTTON48, OnBnClickedButton48) - ON_BN_CLICKED(IDC_BUTTON49, OnBnClickedButton49) - ON_BN_CLICKED(IDC_BUTTON50, OnBnClickedButton50) - ON_BN_CLICKED(IDC_BUTTON51, OnBnClickedButton51) - ON_BN_CLICKED(IDC_BUTTON52, OnBnClickedButton52) - ON_BN_CLICKED(IDC_BUTTON53, OnBnClickedButton53) - ON_BN_CLICKED(IDC_BUTTON54, OnBnClickedButton54) - ON_BN_CLICKED(IDC_BUTTON55, OnBnClickedButton55) - ON_BN_CLICKED(IDC_BUTTON56, OnBnClickedButton56) - ON_BN_CLICKED(IDC_BUTTON57, OnBnClickedButton57) - ON_BN_CLICKED(IDC_BUTTON58, OnBnClickedButton58) - ON_BN_CLICKED(IDC_BUTTON59, OnBnClickedButton59) - ON_BN_CLICKED(IDC_BUTTON60, OnBnClickedButton60) - ON_BN_CLICKED(IDC_BUTTON61, OnBnClickedButton61) - ON_BN_CLICKED(IDC_BUTTON62, OnBnClickedButton62) - ON_BN_CLICKED(IDC_BUTTON63, OnBnClickedButton63) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) - ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) - ON_BN_CLICKED(IDC_BUTTON3, OnBnClickedButton3) - ON_EN_CHANGE(IDC_EDIT132, OnEnChangeEdit132) - ON_BN_CLICKED(IDC_BUTTON4, OnBnClickedButton4) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDC_BUTTON5, OnBnClickedButton5) - ON_BN_CLICKED(IDC_BUTTON6, OnBnClickedButton6) + ON_CBN_SELCHANGE(IDC_Kartenanzahl, &CDlgSolitaireAnalyse::OnCbnSelchangeKartenanzahl) + ON_BN_CLICKED(IDC_BUTTON40, &CDlgSolitaireAnalyse::OnBnClickedButton40) + ON_BN_CLICKED(IDC_BUTTON9, &CDlgSolitaireAnalyse::OnBnClickedButton9) + ON_BN_CLICKED(IDC_BUTTON10, &CDlgSolitaireAnalyse::OnBnClickedButton10) + ON_BN_CLICKED(IDC_BUTTON11, &CDlgSolitaireAnalyse::OnBnClickedButton11) + ON_BN_CLICKED(IDC_BUTTON12, &CDlgSolitaireAnalyse::OnBnClickedButton12) + ON_BN_CLICKED(IDC_BUTTON13, &CDlgSolitaireAnalyse::OnBnClickedButton13) + ON_BN_CLICKED(IDC_BUTTON14, &CDlgSolitaireAnalyse::OnBnClickedButton14) + ON_BN_CLICKED(IDC_BUTTON15, &CDlgSolitaireAnalyse::OnBnClickedButton15) + ON_BN_CLICKED(IDC_BUTTON16, &CDlgSolitaireAnalyse::OnBnClickedButton16) + ON_BN_CLICKED(IDC_BUTTON17, &CDlgSolitaireAnalyse::OnBnClickedButton17) + ON_BN_CLICKED(IDC_BUTTON18, &CDlgSolitaireAnalyse::OnBnClickedButton18) + ON_BN_CLICKED(IDC_BUTTON19, &CDlgSolitaireAnalyse::OnBnClickedButton19) + ON_BN_CLICKED(IDC_BUTTON20, &CDlgSolitaireAnalyse::OnBnClickedButton20) + ON_BN_CLICKED(IDC_BUTTON21, &CDlgSolitaireAnalyse::OnBnClickedButton21) + ON_BN_CLICKED(IDC_BUTTON22, &CDlgSolitaireAnalyse::OnBnClickedButton22) + ON_BN_CLICKED(IDC_BUTTON23, &CDlgSolitaireAnalyse::OnBnClickedButton23) + ON_BN_CLICKED(IDC_BUTTON24, &CDlgSolitaireAnalyse::OnBnClickedButton24) + ON_BN_CLICKED(IDC_BUTTON25, &CDlgSolitaireAnalyse::OnBnClickedButton25) + ON_BN_CLICKED(IDC_BUTTON26, &CDlgSolitaireAnalyse::OnBnClickedButton26) + ON_BN_CLICKED(IDC_BUTTON27, &CDlgSolitaireAnalyse::OnBnClickedButton27) + ON_BN_CLICKED(IDC_BUTTON28, &CDlgSolitaireAnalyse::OnBnClickedButton28) + ON_BN_CLICKED(IDC_BUTTON29, &CDlgSolitaireAnalyse::OnBnClickedButton29) + ON_BN_CLICKED(IDC_BUTTON30, &CDlgSolitaireAnalyse::OnBnClickedButton30) + ON_BN_CLICKED(IDC_BUTTON31, &CDlgSolitaireAnalyse::OnBnClickedButton31) + ON_BN_CLICKED(IDC_BUTTON32, &CDlgSolitaireAnalyse::OnBnClickedButton32) + ON_BN_CLICKED(IDC_BUTTON33, &CDlgSolitaireAnalyse::OnBnClickedButton33) + ON_BN_CLICKED(IDC_BUTTON34, &CDlgSolitaireAnalyse::OnBnClickedButton34) + ON_BN_CLICKED(IDC_BUTTON35, &CDlgSolitaireAnalyse::OnBnClickedButton35) + ON_BN_CLICKED(IDC_BUTTON36, &CDlgSolitaireAnalyse::OnBnClickedButton36) + ON_BN_CLICKED(IDC_BUTTON37, &CDlgSolitaireAnalyse::OnBnClickedButton37) + ON_BN_CLICKED(IDC_BUTTON38, &CDlgSolitaireAnalyse::OnBnClickedButton38) + ON_BN_CLICKED(IDC_BUTTON39, &CDlgSolitaireAnalyse::OnBnClickedButton39) + ON_BN_CLICKED(IDC_BUTTON41, &CDlgSolitaireAnalyse::OnBnClickedButton41) + ON_BN_CLICKED(IDC_BUTTON42, &CDlgSolitaireAnalyse::OnBnClickedButton42) + ON_BN_CLICKED(IDC_BUTTON43, &CDlgSolitaireAnalyse::OnBnClickedButton43) + ON_BN_CLICKED(IDC_BUTTON44, &CDlgSolitaireAnalyse::OnBnClickedButton44) + ON_BN_CLICKED(IDC_BUTTON45, &CDlgSolitaireAnalyse::OnBnClickedButton45) + ON_BN_CLICKED(IDC_BUTTON46, &CDlgSolitaireAnalyse::OnBnClickedButton46) + ON_BN_CLICKED(IDC_BUTTON47, &CDlgSolitaireAnalyse::OnBnClickedButton47) + ON_BN_CLICKED(IDC_BUTTON48, &CDlgSolitaireAnalyse::OnBnClickedButton48) + ON_BN_CLICKED(IDC_BUTTON49, &CDlgSolitaireAnalyse::OnBnClickedButton49) + ON_BN_CLICKED(IDC_BUTTON50, &CDlgSolitaireAnalyse::OnBnClickedButton50) + ON_BN_CLICKED(IDC_BUTTON51, &CDlgSolitaireAnalyse::OnBnClickedButton51) + ON_BN_CLICKED(IDC_BUTTON52, &CDlgSolitaireAnalyse::OnBnClickedButton52) + ON_BN_CLICKED(IDC_BUTTON53, &CDlgSolitaireAnalyse::OnBnClickedButton53) + ON_BN_CLICKED(IDC_BUTTON54, &CDlgSolitaireAnalyse::OnBnClickedButton54) + ON_BN_CLICKED(IDC_BUTTON55, &CDlgSolitaireAnalyse::OnBnClickedButton55) + ON_BN_CLICKED(IDC_BUTTON56, &CDlgSolitaireAnalyse::OnBnClickedButton56) + ON_BN_CLICKED(IDC_BUTTON57, &CDlgSolitaireAnalyse::OnBnClickedButton57) + ON_BN_CLICKED(IDC_BUTTON58, &CDlgSolitaireAnalyse::OnBnClickedButton58) + ON_BN_CLICKED(IDC_BUTTON59, &CDlgSolitaireAnalyse::OnBnClickedButton59) + ON_BN_CLICKED(IDC_BUTTON60, &CDlgSolitaireAnalyse::OnBnClickedButton60) + ON_BN_CLICKED(IDC_BUTTON61, &CDlgSolitaireAnalyse::OnBnClickedButton61) + ON_BN_CLICKED(IDC_BUTTON62, &CDlgSolitaireAnalyse::OnBnClickedButton62) + ON_BN_CLICKED(IDC_BUTTON63, &CDlgSolitaireAnalyse::OnBnClickedButton63) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgSolitaireAnalyse::OnBnClickedButton1) + ON_BN_CLICKED(IDC_BUTTON2, &CDlgSolitaireAnalyse::OnBnClickedButton2) + ON_BN_CLICKED(IDC_BUTTON3, &CDlgSolitaireAnalyse::OnBnClickedButton3) + ON_EN_CHANGE(IDC_EDIT132, &CDlgSolitaireAnalyse::OnEnChangeEdit132) + ON_BN_CLICKED(IDC_BUTTON4, &CDlgSolitaireAnalyse::OnBnClickedButton4) + ON_BN_CLICKED(IDOK, &CDlgSolitaireAnalyse::OnBnClickedOk) + ON_BN_CLICKED(IDC_BUTTON5, &CDlgSolitaireAnalyse::OnBnClickedButton5) + ON_BN_CLICKED(IDC_BUTTON6, &CDlgSolitaireAnalyse::OnBnClickedButton6) END_MESSAGE_MAP() diff --git a/CrypTool/DlgStatRandTests.cpp b/CrypTool/DlgStatRandTests.cpp index d97ea6ada..d8b428911 100644 --- a/CrypTool/DlgStatRandTests.cpp +++ b/CrypTool/DlgStatRandTests.cpp @@ -28,7 +28,7 @@ #include "RandomTest.h" #include "ParseIniFile2.h" #include "DialogeMessage.h" -#include ".\dlgstatrandtests.h" +#include "DlgStatRandTests.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -150,13 +150,13 @@ void CDlgFreqTest::init (const char *Infile_, const char *OldTitle_) BEGIN_MESSAGE_MAP(CDlgFreqTest, CDialog) //{{AFX_MSG_MAP(CDlgFreqTest) - ON_BN_CLICKED(IDC_BUTTON_FREQTEST, OnButtonFreqtest) - ON_CBN_SELCHANGE(IDC_COMBO_ALPHA, OnSelchangeComboAlpha) - ON_BN_CLICKED(IDC_CHECK1, OnCheck1) - ON_BN_CLICKED(IDC_CHECK2, OnCheck2) - ON_CBN_SELCHANGE(IDC_TUPELCOMBO, OnSelchangeTupelcombo) + ON_BN_CLICKED(IDC_BUTTON_FREQTEST, &CDlgFreqTest::OnButtonFreqtest) + ON_CBN_SELCHANGE(IDC_COMBO_ALPHA, &CDlgFreqTest::OnSelchangeComboAlpha) + ON_BN_CLICKED(IDC_CHECK1, &CDlgFreqTest::OnCheck1) + ON_BN_CLICKED(IDC_CHECK2, &CDlgFreqTest::OnCheck2) + ON_CBN_SELCHANGE(IDC_TUPELCOMBO, &CDlgFreqTest::OnSelchangeTupelcombo) //}}AFX_MSG_MAP - ON_STN_CLICKED(IDC_INFO_STATIC, OnStnClickedInfoStatic) + ON_STN_CLICKED(IDC_INFO_STATIC, &CDlgFreqTest::OnStnClickedInfoStatic) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -405,11 +405,11 @@ void CDlgRunsTest::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgRunsTest, CDialog) //{{AFX_MSG_MAP(CDlgRunsTest) - ON_BN_CLICKED(IDC_TESTBUTTON, OnTestbutton) - ON_CBN_SELCHANGE(IDC_COMBO1, OnSelchangeCombo1) - ON_BN_CLICKED(IDC_CHECK2, OnCheck2) - ON_BN_CLICKED(IDC_CHECK3, OnCheck3) - ON_BN_CLICKED(IDC_CHECK1, OnCheck1) + ON_BN_CLICKED(IDC_TESTBUTTON, &CDlgRunsTest::OnTestbutton) + ON_CBN_SELCHANGE(IDC_COMBO1, &CDlgRunsTest::OnSelchangeCombo1) + ON_BN_CLICKED(IDC_CHECK2, &CDlgRunsTest::OnCheck2) + ON_BN_CLICKED(IDC_CHECK3, &CDlgRunsTest::OnCheck3) + ON_BN_CLICKED(IDC_CHECK1, &CDlgRunsTest::OnCheck1) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -679,7 +679,7 @@ void CDlgFIPSTest140_1::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgFIPSTest140_1, CDialog) //{{AFX_MSG_MAP(CDlgFIPSTest140_1) - ON_BN_CLICKED(IDC_BATTERIETEST, OnBatterietest) + ON_BN_CLICKED(IDC_BATTERIETEST, &CDlgFIPSTest140_1::OnBatterietest) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/DlgStatisticsSignatureAttack.cpp b/CrypTool/DlgStatisticsSignatureAttack.cpp index 5004385d8..45ded3060 100644 --- a/CrypTool/DlgStatisticsSignatureAttack.cpp +++ b/CrypTool/DlgStatisticsSignatureAttack.cpp @@ -70,7 +70,7 @@ void CDlgStatisticsSignatureAttack::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgStatisticsSignatureAttack, CDialog) //{{AFX_MSG_MAP(CDlgStatisticsSignatureAttack) - ON_BN_CLICKED(IDOK, OnPrintStatistics) + ON_BN_CLICKED(IDOK, &CDlgStatisticsSignatureAttack::OnPrintStatistics) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -171,15 +171,15 @@ void CDlgStatisticsSignatureAttack::PrintStatistics() HashingOperations HO(m_ResSigAtt->GetHashAlgorithmID()); msg.Format(IDS_SIGATT_STAT_HEADER, HO.GetHashAlgorithmName()); - strlen += _snprintf(doctext + strlen, sizeof(doctext) -1, "%s\n\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) -1, "%s\n\n", (LPCTSTR)msg); msg.Format(IDS_SIGATT_STAT_ORIGINAL_FILE, m_ResSigAtt->getStrFilenameOriginal()); - strlen += _snprintf(doctext + strlen, sizeof(doctext) -1, "%s\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) -1, "%s\n", (LPCTSTR)msg); msg.Format(IDS_SIGATT_STAT_FAKE_FILE, m_ResSigAtt->getStrFilenameFake()); - strlen += _snprintf(doctext + strlen, sizeof(doctext) -1, "%s\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) -1, "%s\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_EXPENSE); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "\n%s\n\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "\n%s\n\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_CALCTIME); @@ -187,23 +187,23 @@ void CDlgStatisticsSignatureAttack::PrintStatistics() double_fmt( ExpectedTC.GetSeconds(), strDuration, 2 ); Time.Format(IDS_STRING_SIG_ATT_STA_TIME, ExpectedTC.GetYears(), ExpectedTC.GetDays(), ExpectedTC.GetHours(), ExpectedTC.GetMinutes(), strDuration); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s: %s\n", msg, Time); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s: %s\n", (LPCTSTR)msg, (LPCTSTR)Time); msg.Format(IDS_STRING_SIG_ATT_STA_STEPS, itoa_fmt((__int64)m_ResSigAtt->GetExpectedSteps())); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n\n\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n\n\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_EFFEXPENSE); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_CALCTIME); double_fmt( EffectiveTC.GetSeconds(), strDuration, 2 ); Time.Format(IDS_STRING_SIG_ATT_STA_TIME, EffectiveTC.GetYears(), EffectiveTC.GetDays(), EffectiveTC.GetHours(), EffectiveTC.GetMinutes(), strDuration); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s: %s\n", msg, Time); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s: %s\n", (LPCTSTR)msg, (LPCTSTR)Time); msg.Format(IDS_STRING_SIG_ATT_STA_STEPS, itoa_fmt((__int64)m_ResSigAtt->GetTotalSteps())); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n",msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n",(LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_PERFORMED, itoa_fmt((__int64)m_ResSigAtt->GetHashOperationsPerformed())); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_TITLE); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s", (LPCTSTR)msg); for (ii = 0; ii < m_ResSigAtt->GetRuns(); ii ++) { @@ -216,18 +216,18 @@ void CDlgStatisticsSignatureAttack::PrintStatistics() } msg.Format(IDS_STRING_SIG_ATT_STA_ADDEDBYTES); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "\n\n\n%s\n\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "\n\n\n%s\n\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_HARMLESS, m_ModifiedBytesHarmless); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s\n", (LPCTSTR)msg); msg.Format(IDS_STRING_SIG_ATT_STA_DANGEROUS, m_ModifiedBytesDangerous); - strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s", msg); + strlen += _snprintf(doctext + strlen, sizeof(doctext) - 1, "%s", (LPCTSTR)msg); StatisticsFile.write(doctext, strlen); StatisticsFile.close(); Statistics = theApp.OpenDocumentFileNoMRU(outfile); msg.Format(IDS_STRING_SIG_ATT_STA_DOCTITLE); - _snprintf(doctitle, sizeof(doctitle) - 1, "%s", msg); + _snprintf(doctitle, sizeof(doctitle) - 1, "%s", (LPCTSTR)msg); Statistics->SetTitle(doctitle); HIDE_HOUR_GLASS } diff --git a/CrypTool/DlgTextOptions.cpp b/CrypTool/DlgTextOptions.cpp index 5279919e6..240b63ba9 100644 --- a/CrypTool/DlgTextOptions.cpp +++ b/CrypTool/DlgTextOptions.cpp @@ -176,21 +176,21 @@ void CDlgTextOptions::DoDataExchange(CDataExchange* pDX) { } BEGIN_MESSAGE_MAP(CDlgTextOptions, CDialog) - ON_BN_CLICKED(IDC_CHECK_KEEP_CHARACTERS_NOT_PRESENT_IN_ALPHABET_UNCHANGED, OnCheckKeepCharactersNotPresentInAlphabetUnchanged) - ON_BN_CLICKED(IDC_CHECK_KEEP_UPPER_LOWER_CASE_INFORMATION, OnCheckKeepUpperLowerCaseInformation) - ON_BN_CLICKED(IDC_CHECK_DISTINGUISH_UPPER_LOWER_CASE, OnCheckDistinguishUpperLowerCase) - ON_BN_CLICKED(IDC_CHECK_UPPER_CASE, OnCheckUpperCase) - ON_BN_CLICKED(IDC_CHECK_LOWER_CASE, OnCheckLowerCase) - ON_BN_CLICKED(IDC_CHECK_SPACE, OnCheckSpace) - ON_BN_CLICKED(IDC_CHECK_PUNCTUATION, OnCheckSpecial) - ON_BN_CLICKED(IDC_CHECK_DIGITS, OnCheckDigits) - ON_BN_CLICKED(IDC_CHECK_UMLAUTS, OnCheckUmlauts) - ON_EN_UPDATE(IDC_EDIT_ALPHABET, OnUpdateEditAlphabet) - ON_BN_CLICKED(IDC_BUTTON_SEARCH_REFERENCE_FILE, OnButtonSearchReferenceFile) - ON_CBN_SELENDOK(IDC_COMBO_SELECT_REFERENCE_FILE, OnComboSelectReferenceFile) - ON_BN_CLICKED(IDOK, OnButtonOK) - ON_BN_CLICKED(IDC_BUTTON_RESTORE_STANDARD, OnButtonRestoreStandard) - ON_BN_CLICKED(IDCANCEL, OnButtonCancel) + ON_BN_CLICKED(IDC_CHECK_KEEP_CHARACTERS_NOT_PRESENT_IN_ALPHABET_UNCHANGED, &CDlgTextOptions::OnCheckKeepCharactersNotPresentInAlphabetUnchanged) + ON_BN_CLICKED(IDC_CHECK_KEEP_UPPER_LOWER_CASE_INFORMATION, &CDlgTextOptions::OnCheckKeepUpperLowerCaseInformation) + ON_BN_CLICKED(IDC_CHECK_DISTINGUISH_UPPER_LOWER_CASE, &CDlgTextOptions::OnCheckDistinguishUpperLowerCase) + ON_BN_CLICKED(IDC_CHECK_UPPER_CASE, &CDlgTextOptions::OnCheckUpperCase) + ON_BN_CLICKED(IDC_CHECK_LOWER_CASE, &CDlgTextOptions::OnCheckLowerCase) + ON_BN_CLICKED(IDC_CHECK_SPACE, &CDlgTextOptions::OnCheckSpace) + ON_BN_CLICKED(IDC_CHECK_PUNCTUATION, &CDlgTextOptions::OnCheckSpecial) + ON_BN_CLICKED(IDC_CHECK_DIGITS, &CDlgTextOptions::OnCheckDigits) + ON_BN_CLICKED(IDC_CHECK_UMLAUTS, &CDlgTextOptions::OnCheckUmlauts) + ON_EN_UPDATE(IDC_EDIT_ALPHABET, &CDlgTextOptions::OnUpdateEditAlphabet) + ON_BN_CLICKED(IDC_BUTTON_SEARCH_REFERENCE_FILE, &CDlgTextOptions::OnButtonSearchReferenceFile) + ON_CBN_SELENDOK(IDC_COMBO_SELECT_REFERENCE_FILE, &CDlgTextOptions::OnComboSelectReferenceFile) + ON_BN_CLICKED(IDOK, &CDlgTextOptions::OnButtonOK) + ON_BN_CLICKED(IDC_BUTTON_RESTORE_STANDARD, &CDlgTextOptions::OnButtonRestoreStandard) + ON_BN_CLICKED(IDCANCEL, &CDlgTextOptions::OnButtonCancel) END_MESSAGE_MAP() void CDlgTextOptions::OnCheckKeepCharactersNotPresentInAlphabetUnchanged() { diff --git a/CrypTool/DlgVerifyECSignatureStepByStep.cpp b/CrypTool/DlgVerifyECSignatureStepByStep.cpp index d67f51615..0a33bcebf 100644 --- a/CrypTool/DlgVerifyECSignatureStepByStep.cpp +++ b/CrypTool/DlgVerifyECSignatureStepByStep.cpp @@ -135,11 +135,11 @@ void CDlgVerifyECSignatureStepByStep::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgVerifyECSignatureStepByStep, CDialog) //{{AFX_MSG_MAP(CDlgVerifyECSignatureStepByStep) - ON_BN_CLICKED(IDC_BUTTON_CONTINUE, OnButtonContinue) - ON_BN_CLICKED(IDC_RADIO1, OnRadioOktal) - ON_BN_CLICKED(IDC_RADIO2, OnRadioDezimal) - ON_BN_CLICKED(IDC_RADIO3, OnRadioHexadezimal) - ON_BN_CLICKED(IDC_RADIO4, OnRadioOctets) + ON_BN_CLICKED(IDC_BUTTON_CONTINUE, &CDlgVerifyECSignatureStepByStep::OnButtonContinue) + ON_BN_CLICKED(IDC_RADIO1, &CDlgVerifyECSignatureStepByStep::OnRadioOktal) + ON_BN_CLICKED(IDC_RADIO2, &CDlgVerifyECSignatureStepByStep::OnRadioDezimal) + ON_BN_CLICKED(IDC_RADIO3, &CDlgVerifyECSignatureStepByStep::OnRadioHexadezimal) + ON_BN_CLICKED(IDC_RADIO4, &CDlgVerifyECSignatureStepByStep::OnRadioOctets) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -715,7 +715,7 @@ int CDlgVerifyECSignatureStepByStep::UpdateDataDisplay() return -1; } LoadString(AfxGetInstanceHandle(),IDS_STRING_DOMAIN_PARAMETER_TO_USE,pc_str,STR_LAENGE_STRING_TABLE); - sprintf(pc_str1, pc_str, curveID); + sprintf(pc_str1, pc_str, (LPCTSTR)curveID); m_DataDisplay += (CString) pc_str1 + nl + nl; m_DataDisplay += ( sp2 + ((CString)"a = ") + DomParamAcString.a + nl ); m_DataDisplay += ( sp2 + ((CString)"b = ") + DomParamAcString.b + nl ); diff --git a/CrypTool/DlgVerifySignature.cpp b/CrypTool/DlgVerifySignature.cpp index 1a8e66902..a6ea2c6e3 100644 --- a/CrypTool/DlgVerifySignature.cpp +++ b/CrypTool/DlgVerifySignature.cpp @@ -231,20 +231,20 @@ void CDlgVerifySignature::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CDlgVerifySignature, CDialog) //{{AFX_MSG_MAP(CDlgVerifySignature) - ON_NOTIFY(NM_CLICK, IDC_LIST2, OnClickList2) - ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST2, OnItemclickList2) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, OnColumnclickList2) - ON_BN_CLICKED(IDC_CHECK_DSA_KEYS, OnCheckDsaKey) - ON_BN_CLICKED(IDC_CHECK_EC_KEYS, OnCheckEcKey) - ON_BN_CLICKED(IDC_CHECK_RSA_KEYS, OnCheckRsaKey) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, OnKeydownList2) - ON_BN_CLICKED(IDC_BUTTON1, OnButtonSearchKey) - ON_BN_CLICKED(IDC_RADIO5, OnRadioECDSA) - ON_BN_CLICKED(IDC_RADIO6, OnRadioECNR) - ON_BN_CLICKED(IDC_RADIO7, OnRadioSHA1) - ON_BN_CLICKED(IDC_RADIO8, OnRadioRIPEMD) - ON_BN_CLICKED(IDC_RADIO1, OnRadioAffineCoord) - ON_BN_CLICKED(IDC_RADIO2, OnRadioProjectCoord) + ON_NOTIFY(NM_CLICK, IDC_LIST2, &CDlgVerifySignature::OnClickList2) + ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST2, &CDlgVerifySignature::OnItemclickList2) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, &CDlgVerifySignature::OnColumnclickList2) + ON_BN_CLICKED(IDC_CHECK_DSA_KEYS, &CDlgVerifySignature::OnCheckDsaKey) + ON_BN_CLICKED(IDC_CHECK_EC_KEYS, &CDlgVerifySignature::OnCheckEcKey) + ON_BN_CLICKED(IDC_CHECK_RSA_KEYS, &CDlgVerifySignature::OnCheckRsaKey) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, &CDlgVerifySignature::OnKeydownList2) + ON_BN_CLICKED(IDC_BUTTON1, &CDlgVerifySignature::OnButtonSearchKey) + ON_BN_CLICKED(IDC_RADIO5, &CDlgVerifySignature::OnRadioECDSA) + ON_BN_CLICKED(IDC_RADIO6, &CDlgVerifySignature::OnRadioECNR) + ON_BN_CLICKED(IDC_RADIO7, &CDlgVerifySignature::OnRadioSHA1) + ON_BN_CLICKED(IDC_RADIO8, &CDlgVerifySignature::OnRadioRIPEMD) + ON_BN_CLICKED(IDC_RADIO1, &CDlgVerifySignature::OnRadioAffineCoord) + ON_BN_CLICKED(IDC_RADIO2, &CDlgVerifySignature::OnRadioProjectCoord) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -908,7 +908,7 @@ void CDlgVerifySignature::OnButtonSearchKey() // Info: Schlüsselbezeichner signKey nicht in Liste vorhanden, // obwohl alle Schlüsseltypen durchsucht wurden LoadString(AfxGetInstanceHandle(),IDS_STRING_MSG_KEY_IDENTIFIER_NOT_FOUND,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1, signKey); + sprintf(pc_str, pc_str1, (LPCTSTR)signKey); LoadString(AfxGetInstanceHandle(),IDS_STRING_ERR_UNKNOWN_SIGNATURE,pc_str1,STR_LAENGE_STRING_TABLE); MessageBox(pc_str,pc_str1,MB_ICONWARNING|MB_OK); return; // no selection @@ -931,7 +931,7 @@ void CDlgVerifySignature::OnButtonSearchKey() // Info: Schlüsselbezeichner nicht in Liste vorhanden, obwohl alle Schlüsseltypen // durchsucht wurden LoadString(AfxGetInstanceHandle(),IDS_STRING_MSG_KEY_IDENTIFIER_NOT_FOUND,pc_str1,STR_LAENGE_STRING_TABLE); - sprintf(pc_str, pc_str1, signKey); + sprintf(pc_str, pc_str1, (LPCTSTR)signKey); LoadString(AfxGetInstanceHandle(),IDS_STRING_ERR_UNKNOWN_SIGNATURE,pc_str1,STR_LAENGE_STRING_TABLE); MessageBox(pc_str,pc_str1,MB_ICONWARNING|MB_OK); return; // no selection diff --git a/CrypTool/DlgVerifySignature.h b/CrypTool/DlgVerifySignature.h index 167b9e79b..acd4b40d8 100644 --- a/CrypTool/DlgVerifySignature.h +++ b/CrypTool/DlgVerifySignature.h @@ -43,7 +43,7 @@ class CDlgVerifySignature : public CDialog public: CDlgVerifySignature(CWnd* pParent = NULL); // Standardkonstruktor CDlgVerifySignature(char* sig_id, char* hash_id, CString sig_key, CWnd* pParent = NULL); - CDlgVerifySignature::~CDlgVerifySignature(); // Destruktor + ~CDlgVerifySignature(); // Destruktor EcDomParam_ac_ptr DomParamAc; // The Domain Parameter (affine coordinates) of the selected elliptic Curve EcDomParam_pc_ptr DomParamPc; // The Domain Parameter (projective coordinates) of the selected elliptic Curve diff --git a/CrypTool/DlgVigenereAnalysisSchroedel.cpp b/CrypTool/DlgVigenereAnalysisSchroedel.cpp index 25d074ef2..9d596393d 100644 --- a/CrypTool/DlgVigenereAnalysisSchroedel.cpp +++ b/CrypTool/DlgVigenereAnalysisSchroedel.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "CryptoolApp.h" +#include "CrypToolApp.h" #include "DlgVigenereAnalysisSchroedel.h" #include "CrypToolTools.h" #include "FileTools.h" @@ -994,17 +994,17 @@ int VigenereAnalysisSchroedel::solveTrigram() { CString unitCharacters; unitCharacters.LoadStringA(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_UNIT_CHARACTERS); CString ciphertextLength; - ciphertextLength.Format("%s %d %s", ciphertextLengthTag, ciphertext.GetLength(), unitCharacters); + ciphertextLength.Format("%s %d %s", (LPCTSTR)ciphertextLengthTag, ciphertext.GetLength(), (LPCTSTR)unitCharacters); output(ciphertextLength, true); // dump the selected keyword language(s) CString selectedKeywordLanguagesTag; - selectedKeywordLanguagesTag.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_SELECTED_KEYWORD_LANGUAGES, theDialog->getSelectedCiphertextLanguageAsString()); + selectedKeywordLanguagesTag.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_SELECTED_KEYWORD_LANGUAGES, (LPCTSTR)theDialog->getSelectedCiphertextLanguageAsString()); output(selectedKeywordLanguagesTag, true); // dump the selected ciphertext language CString selectedCiphertextLanguageTag; - selectedCiphertextLanguageTag.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_SELECTED_CIPHERTEXT_LANGUAGE, theDialog->getSelectedCiphertextLanguageAsString()); + selectedCiphertextLanguageTag.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_SELECTED_CIPHERTEXT_LANGUAGE, (LPCTSTR)theDialog->getSelectedCiphertextLanguageAsString()); output(selectedCiphertextLanguageTag, true); output("", true); @@ -1475,9 +1475,9 @@ void CDlgVigenereAnalysisSchroedel::DoDataExchange(CDataExchange* pDX) } BEGIN_MESSAGE_MAP(CDlgVigenereAnalysisSchroedel, CDialog) - ON_BN_CLICKED(IDC_BUTTON_START_ANALYSIS, OnBnClickedStartAnalysis) - ON_BN_CLICKED(IDC_BUTTON_CANCEL_ANALYSIS, OnBnClickedCancelAnalysis) - ON_BN_CLICKED(IDC_BUTTON_SHOW_ANALYSIS_RESULTS, OnBnClickedShowAnalysisResults) + ON_BN_CLICKED(IDC_BUTTON_START_ANALYSIS, &CDlgVigenereAnalysisSchroedel::OnBnClickedStartAnalysis) + ON_BN_CLICKED(IDC_BUTTON_CANCEL_ANALYSIS, &CDlgVigenereAnalysisSchroedel::OnBnClickedCancelAnalysis) + ON_BN_CLICKED(IDC_BUTTON_SHOW_ANALYSIS_RESULTS, &CDlgVigenereAnalysisSchroedel::OnBnClickedShowAnalysisResults) ON_WM_TIMER() END_MESSAGE_MAP() @@ -1526,7 +1526,7 @@ void CDlgVigenereAnalysisSchroedel::updateSelectedLanguages(const CString &_sele // if our language is empty, we go with the default column header (language assumption not displayed) if(selectedCiphertextLanguageAsString.IsEmpty()) columnHeaderCleartext.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_COLUMNHEADERCLEARTEXT); // if our language is set, we add the language assumption - else columnHeaderCleartext.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_COLUMNHEADERCLEARTEXT_WITHLANGUAGE, selectedCiphertextLanguageAsString); + else columnHeaderCleartext.Format(IDS_STRING_VIGENERE_ANALYSIS_SCHROEDEL_COLUMNHEADERCLEARTEXT_WITHLANGUAGE, (LPCTSTR)selectedCiphertextLanguageAsString); // delete old column controlListPossibleResults.DeleteColumn(1); // add new column @@ -1669,7 +1669,7 @@ void CDlgVigenereAnalysisSchroedelChooseLanguages::DoDataExchange(CDataExchange* } BEGIN_MESSAGE_MAP(CDlgVigenereAnalysisSchroedelChooseLanguages, CDialog) - ON_BN_CLICKED(IDOK, OnOK) + ON_BN_CLICKED(IDOK, &CDlgVigenereAnalysisSchroedelChooseLanguages::OnOK) END_MESSAGE_MAP() BOOL CDlgVigenereAnalysisSchroedelChooseLanguages::OnInitDialog() diff --git a/CrypTool/DlgVigenereAnalysisSchroedel.h b/CrypTool/DlgVigenereAnalysisSchroedel.h index f1d338aa5..424e0489f 100644 --- a/CrypTool/DlgVigenereAnalysisSchroedel.h +++ b/CrypTool/DlgVigenereAnalysisSchroedel.h @@ -46,7 +46,7 @@ struct PossibleResult { // it wasn't very reliable; instead, we present ALL possible solutions to the // user; the order depends on (1) the length of the longest dictionary match, // and (2) the length of the longest key - bool operator<(const PossibleResult &_result) { + bool operator<(const PossibleResult &_result) const { if(longestDictionaryMatch.GetLength() == _result.longestDictionaryMatch.GetLength()) return (key.GetLength() > _result.key.GetLength()); else diff --git a/CrypTool/DlgX2ModNRandomParamater.cpp b/CrypTool/DlgX2ModNRandomParamater.cpp index 3ea240af7..12ba551f8 100644 --- a/CrypTool/DlgX2ModNRandomParamater.cpp +++ b/CrypTool/DlgX2ModNRandomParamater.cpp @@ -64,7 +64,7 @@ END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // Behandlungsroutinen für Nachrichten CDlgX2ModNRandomParamater -void CDlgX2ModNRandomParamater::SetModul(CString &NStr) +void CDlgX2ModNRandomParamater::SetModul(const CString &NStr) { m_EditModul_N = NStr; } diff --git a/CrypTool/DlgX2ModNRandomParamater.h b/CrypTool/DlgX2ModNRandomParamater.h index 0d913fce8..b107adafe 100644 --- a/CrypTool/DlgX2ModNRandomParamater.h +++ b/CrypTool/DlgX2ModNRandomParamater.h @@ -35,7 +35,7 @@ class CDlgX2ModNRandomParamater : public CDialog // Konstruktion public: CString GetModul(void); - void SetModul(CString &NStr); + void SetModul(const CString &NStr); CDlgX2ModNRandomParamater(CWnd* pParent = NULL); // Standardkonstruktor // Dialogfelddaten diff --git a/CrypTool/ELLIPTIC.CPP b/CrypTool/ELLIPTIC.CPP index e2fae843e..8d3702b2e 100644 --- a/CrypTool/ELLIPTIC.CPP +++ b/CrypTool/ELLIPTIC.CPP @@ -37,7 +37,7 @@ #include using namespace std; #endif -#include "elliptic.h" +#include "ELLIPTIC.H" int ECn::get(Big& x,Big& y) const {return epoint_get(p,x.getbig(),y.getbig());} diff --git a/CrypTool/FLASH.CPP b/CrypTool/FLASH.CPP index f861c128b..44068ff07 100644 --- a/CrypTool/FLASH.CPP +++ b/CrypTool/FLASH.CPP @@ -36,7 +36,7 @@ #include using namespace std; #endif -#include "flash.h" +#include "FLASH.H" #ifdef MR_FLASH @@ -52,7 +52,7 @@ return b;} Big Flash::num(void) {Big b; numer(fn,b.fn); return b;} Big Flash::den(void) {Big b; denom(fn,b.fn); return b;} -Flash operator-(const Flash& f) {Flash nf; negate(f.fn,nf.fn); return nf;} +Flash operator-(const Flash& f) {Flash nf; ::negate(f.fn,nf.fn); return nf;} Flash operator+(const Flash& f1, const Flash& f2) {Flash aff; fadd(f1.fn,f2.fn,aff.fn); return aff;} diff --git a/CrypTool/FLASH.H b/CrypTool/FLASH.H index b93ad8302..f53cca903 100644 --- a/CrypTool/FLASH.H +++ b/CrypTool/FLASH.H @@ -159,5 +159,7 @@ public: }; #endif +Flash pi(); + #endif diff --git a/CrypTool/FPOLY.CPP b/CrypTool/FPOLY.CPP index 6215a2aea..d57e17d27 100644 --- a/CrypTool/FPOLY.CPP +++ b/CrypTool/FPOLY.CPP @@ -36,7 +36,7 @@ #include using namespace std; #endif -#include "fpoly.h" +#include "FPOLY.H" FPoly::FPoly(const FPoly& p) diff --git a/CrypTool/FPOLY.H b/CrypTool/FPOLY.H index 33acef706..51bd337a2 100644 --- a/CrypTool/FPOLY.H +++ b/CrypTool/FPOLY.H @@ -33,7 +33,7 @@ #ifndef FPOLY_H #define FPOLY_H -#include "flash.h" +#include "FLASH.H" class fterm { diff --git a/CrypTool/HashingOperations.h b/CrypTool/HashingOperations.h index 116ea8305..45a833a84 100644 --- a/CrypTool/HashingOperations.h +++ b/CrypTool/HashingOperations.h @@ -48,7 +48,7 @@ struct HashAlgorithmsFP int HashOpsPerSecond; // ausgehend von einem Rechner mit ???-Prozessor und ??? MHz Taktfrequenz }; -struct HashAlgorithmsFP HAFP[]; +extern struct HashAlgorithmsFP HAFP[]; class HashingOperations { diff --git a/CrypTool/HexEdit.cpp b/CrypTool/HexEdit.cpp index 12e72a2d9..15ca7b08c 100644 --- a/CrypTool/HexEdit.cpp +++ b/CrypTool/HexEdit.cpp @@ -56,8 +56,8 @@ BEGIN_MESSAGE_MAP(CHexEdit, CEdit) //{{AFX_MSG_MAP(CHexEdit) ON_WM_CHAR() ON_WM_KEYDOWN() - ON_MESSAGE(WM_PASTE, OnPaste) - ON_CONTROL_REFLECT_EX(EN_UPDATE, OnUpdate) + ON_MESSAGE(WM_PASTE, &CHexEdit::OnPaste) + ON_CONTROL_REFLECT_EX(EN_UPDATE, &CHexEdit::OnUpdate) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/HexEditBase.cpp b/CrypTool/HexEditBase.cpp index 62b4d8a76..67b25498d 100644 --- a/CrypTool/HexEditBase.cpp +++ b/CrypTool/HexEditBase.cpp @@ -180,10 +180,10 @@ IMPLEMENT_DYNCREATE(CHexEditBase, CWnd) BEGIN_MESSAGE_MAP(CHexEditBase, CWnd) //{{AFX_MSG_MAP(CHexEditBase) - ON_MESSAGE(UM_SETSCROLRANGE, OnUmSetScrollRange) - ON_MESSAGE(WM_CHAR, OnWMChar) - ON_MESSAGE(WM_SETFONT, OnWMSetFont) - ON_MESSAGE(WM_GETFONT, OnWMGetFont) + ON_MESSAGE(UM_SETSCROLRANGE, &CHexEditBase::OnUmSetScrollRange) + ON_MESSAGE(WM_CHAR, &CHexEditBase::OnWMChar) + ON_MESSAGE(WM_SETFONT, &CHexEditBase::OnWMSetFont) + ON_MESSAGE(WM_GETFONT, &CHexEditBase::OnWMGetFont) ON_WM_DESTROY() ON_WM_TIMER() ON_WM_KILLFOCUS() @@ -201,12 +201,12 @@ BEGIN_MESSAGE_MAP(CHexEditBase, CWnd) ON_WM_KEYDOWN() ON_WM_MOUSEWHEEL() ON_WM_CONTEXTMENU() - ON_COMMAND(ID_EDIT_CUT, OnEditCut) - ON_COMMAND(ID_EDIT_COPY, OnEditCopy) - ON_COMMAND(ID_EDIT_PASTE, OnEditPaste) - ON_COMMAND(ID_EDIT_CLEAR, OnEditClear) - ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll) - ON_COMMAND(ID_TOTXT, OnToTxt) + ON_COMMAND(ID_EDIT_CUT, &CHexEditBase::OnEditCut) + ON_COMMAND(ID_EDIT_COPY, &CHexEditBase::OnEditCopy) + ON_COMMAND(ID_EDIT_PASTE, &CHexEditBase::OnEditPaste) + ON_COMMAND(ID_EDIT_CLEAR, &CHexEditBase::OnEditClear) + ON_COMMAND(ID_EDIT_SELECT_ALL, &CHexEditBase::OnEditSelectAll) + ON_COMMAND(ID_TOTXT, &CHexEditBase::OnToTxt) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -817,7 +817,8 @@ void CHexEditBase::PaintHexData(CDC& cDC) cRect.right -= (pBuf-1+m_tPaintDetails.nBytesPerRow*3-pSelectionBufPtrEnd) * m_tPaintDetails.nCharacterWidth; CRect cSelectionRect(cRect); cSelectionRect.InflateRect(0, -1, +1, 0); - cDC.FillRect(cSelectionRect, &CBrush(bHasFocus ? m_tSelectedFousBkgCol : m_tSelectedNoFocusBkgCol)); + CBrush cSelectionBrush(bHasFocus ? m_tSelectedFousBkgCol : m_tSelectedNoFocusBkgCol); + cDC.FillRect(cSelectionRect, &cSelectionBrush); *pSelectionBufPtrEnd = '\0'; // set "end-mark" cDC.SetTextColor(bHasFocus ? m_tSelectedFousTxtCol : m_tSelectedNoFocusTxtCol); cDC.SetBkColor(m_tHighlightBkgCol); @@ -1006,7 +1007,8 @@ ASSERT(m_tPaintDetails.nBytesPerRow > 0); cRect.right -= (pBuf + m_tPaintDetails.nBytesPerRow - pSelectionBufPtrEnd)*m_tPaintDetails.nCharacterWidth; CRect cSelectionRect(cRect); cSelectionRect.InflateRect(0, -1, +1, 0); - cDC.FillRect(cSelectionRect, &CBrush(bHasFocus ? m_tSelectedFousBkgCol : m_tSelectedNoFocusBkgCol)); + CBrush cSelectionBrush(bHasFocus ? m_tSelectedFousBkgCol : m_tSelectedNoFocusBkgCol); + cDC.FillRect(cSelectionRect, &cSelectionBrush); *pSelectionBufPtrEnd = '\0'; // set "end-mark" cDC.SetTextColor(bHasFocus ? m_tSelectedFousTxtCol : m_tSelectedNoFocusTxtCol); cDC.SetBkColor(m_tHighlightBkgCol); @@ -1181,7 +1183,7 @@ void CHexEditBase::OnKillFocus(CWnd* pNewWnd) void CHexEditBase::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); - CalculatePaintingDetails(CClientDC(this)); + { CClientDC cClientDC(this); CalculatePaintingDetails(cClientDC); } SetEditCaretPos(m_nCurrentAddress, m_bHighBits); SetScrollbarRanges(); } @@ -1350,7 +1352,7 @@ ASSERT(::IsWindow(m_hWnd)); return; } if(m_bRecalc) { - CalculatePaintingDetails(CClientDC(this)); + { CClientDC cClientDC(this); CalculatePaintingDetails(cClientDC); } } if(m_nCurrentAddress < m_nScrollPostionY*m_tPaintDetails.nBytesPerRow || (m_nCurrentAddress >= (m_nScrollPostionY + m_tPaintDetails.nVisibleLines)*m_tPaintDetails.nBytesPerRow) ) { diff --git a/CrypTool/HexEditCtrlDoc.cpp b/CrypTool/HexEditCtrlDoc.cpp index 8fb3f7ec0..3d9da06dd 100644 --- a/CrypTool/HexEditCtrlDoc.cpp +++ b/CrypTool/HexEditCtrlDoc.cpp @@ -57,7 +57,7 @@ IMPLEMENT_DYNCREATE(CHexEditCtrlDoc, CCryptDoc) BEGIN_MESSAGE_MAP(CHexEditCtrlDoc, CCryptDoc) //{{AFX_MSG_MAP(CHexEditCtrlDoc) - ON_COMMAND(ID_TOTXT, OnTotxt) + ON_COMMAND(ID_TOTXT, &CHexEditCtrlDoc::OnTotxt) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/HexEditCtrlView.cpp b/CrypTool/HexEditCtrlView.cpp index d85e834c2..af67a4066 100644 --- a/CrypTool/HexEditCtrlView.cpp +++ b/CrypTool/HexEditCtrlView.cpp @@ -34,10 +34,10 @@ #include "CrypToolApp.h" #include "CryptDoc.h" #include "FileTools.h" -#include "cryptography.h" +#include "Cryptography.h" #include "HexEditCtrlDoc.h" #include "HexEditCtrlView.h" -#include ".\hexeditctrlview.h" +#include "HexEditCtrlView.h" ///////////////////////////////////////////////////////////////////////////// @@ -60,23 +60,23 @@ IMPLEMENT_DYNCREATE(CHexEditCtrlView, CHexEditBaseView) BEGIN_MESSAGE_MAP(CHexEditCtrlView, CHexEditBaseView) //{{AFX_MSG_MAP(CHexEditCtrlView) - ON_COMMAND(ID_EDIT_CUT, OnEditCut) - ON_COMMAND(ID_EDIT_COPY, OnEditCopy) - ON_COMMAND(ID_EDIT_PASTE, OnEditPaste) - ON_COMMAND(ID_EDIT_CLEAR, OnEditClear) - ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll) - ON_COMMAND(ID_GOTO_VATER, OnGotoVater) - ON_UPDATE_COMMAND_UI(ID_INDICATOR_LINE, OnUpdateLine) - ON_UPDATE_COMMAND_UI(ID_INDICATOR_OVR, OnUpdateInsert) - ON_COMMAND(ID_EDIT_UNDO, OnEditUndo) - ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo) - ON_COMMAND(ID_EDIT_REDO, OnEditRedo) - ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateEditRedo) + ON_COMMAND(ID_EDIT_CUT, &CHexEditCtrlView::OnEditCut) + ON_COMMAND(ID_EDIT_COPY, &CHexEditCtrlView::OnEditCopy) + ON_COMMAND(ID_EDIT_PASTE, &CHexEditCtrlView::OnEditPaste) + ON_COMMAND(ID_EDIT_CLEAR, &CHexEditCtrlView::OnEditClear) + ON_COMMAND(ID_EDIT_SELECT_ALL, &CHexEditCtrlView::OnEditSelectAll) + ON_COMMAND(ID_GOTO_VATER, &CHexEditCtrlView::OnGotoVater) + ON_UPDATE_COMMAND_UI(ID_INDICATOR_LINE, &CHexEditCtrlView::OnUpdateLine) + ON_UPDATE_COMMAND_UI(ID_INDICATOR_OVR, &CHexEditCtrlView::OnUpdateInsert) + ON_COMMAND(ID_EDIT_UNDO, &CHexEditCtrlView::OnEditUndo) + ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CHexEditCtrlView::OnUpdateEditUndo) + ON_COMMAND(ID_EDIT_REDO, &CHexEditCtrlView::OnEditRedo) + ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, &CHexEditCtrlView::OnUpdateEditRedo) //}}AFX_MSG_MAP - ON_COMMAND(ID_ENTROPY, OnEntropy) - ON_COMMAND(ID_HISTOGRAM, OnHistogram) - ON_COMMAND(ID_TOTXT, OnTotxt) - ON_COMMAND(ID_EDIT_FIND, OnEditFind) + ON_COMMAND(ID_ENTROPY, &CHexEditCtrlView::OnEntropy) + ON_COMMAND(ID_HISTOGRAM, &CHexEditCtrlView::OnHistogram) + ON_COMMAND(ID_TOTXT, &CHexEditCtrlView::OnTotxt) + ON_COMMAND(ID_EDIT_FIND, &CHexEditCtrlView::OnEditFind) END_MESSAGE_MAP() diff --git a/CrypTool/HillAnalysis.cpp b/CrypTool/HillAnalysis.cpp index 207f22f78..4b6a5ac41 100644 --- a/CrypTool/HillAnalysis.cpp +++ b/CrypTool/HillAnalysis.cpp @@ -5,7 +5,7 @@ #include "FileTools.h" #include "DialogeMessage.h" #include "DlgTextOptions.h" -#include "keyHillBase.h" +#include "KeyHillBase.h" #include "assert.h" @@ -67,7 +67,7 @@ int CHillAnalysis::analyze(CString &err_str) err_str.LoadString(IDS_PA_COULDNOTOPEN_CIPHERFILE); return -1; } - if ( 0 >= d_plain || 0 >= d_cipher ) + if ( 0 >= s_plain || 0 >= s_cipher ) { err_str.LoadString(IDS_STRING_ERR_INPUT_TEXT_LENGTH); return -1; diff --git a/CrypTool/HomophonicSubstitution.cpp b/CrypTool/HomophonicSubstitution.cpp index 97590172e..d0654cdd9 100644 --- a/CrypTool/HomophonicSubstitution.cpp +++ b/CrypTool/HomophonicSubstitution.cpp @@ -108,7 +108,7 @@ CString HomophonicSubstitution::exportKeyAsString() const { stringKeyEntryHomophones.Append(","); } } - stringKeyEntry.Format("%s/%s/%s/%s/%s/%s", stringKeyEntryCode, stringKeyEntryCharacter, stringKeyEntryCount, stringKeyEntryFrequency, stringKeyEntryCountHomophones, stringKeyEntryHomophones); + stringKeyEntry.Format("%s/%s/%s/%s/%s/%s", (LPCTSTR)stringKeyEntryCode, (LPCTSTR)stringKeyEntryCharacter, (LPCTSTR)stringKeyEntryCount, (LPCTSTR)stringKeyEntryFrequency, (LPCTSTR)stringKeyEntryCountHomophones, (LPCTSTR)stringKeyEntryHomophones); stringKey.Append(stringKeyEntry); if(indexKeyEntry + 1 < m_keyEntries.size()) { stringKey.Append(";"); diff --git a/CrypTool/IntegerArithmetic.cpp b/CrypTool/IntegerArithmetic.cpp index d10cdd29a..9c706d449 100644 --- a/CrypTool/IntegerArithmetic.cpp +++ b/CrypTool/IntegerArithmetic.cpp @@ -27,7 +27,7 @@ #include "resource.h" #include "IntegerArithmetic.h" -#include +#include "MONTY.H" #include "DlgProgressFactorisation.h" #ifdef _DEBUG @@ -1607,13 +1607,13 @@ CTutorialFactorisation::~CTutorialFactorisation() } set_mip(mip); if(ww) - delete[mlf] ww; + delete[] ww; if(xx) - delete[mmm] xx; + delete[] xx; if(yy) - delete[mmm] yy; + delete[] yy; if(zz) - delete[mlf] zz; + delete[] zz; ww = xx = yy = zz = NULL; } diff --git a/CrypTool/IntegerArithmetic.h b/CrypTool/IntegerArithmetic.h index ea3f83c5d..ce1969b55 100644 --- a/CrypTool/IntegerArithmetic.h +++ b/CrypTool/IntegerArithmetic.h @@ -37,7 +37,7 @@ extern volatile long ExitFactorisationCode; #include "BIG.H" // Hinzugefügt von der Klassenansicht -#include +#include "MONTY.H" #include "ChrTools.h" diff --git a/CrypTool/KeyRepository.cpp b/CrypTool/KeyRepository.cpp index b9ecf230f..60291dd73 100644 --- a/CrypTool/KeyRepository.cpp +++ b/CrypTool/KeyRepository.cpp @@ -25,7 +25,7 @@ // #include "KeyRepository.h" -#include "Resource.h" +#include "resource.h" ////////////////////////////////////////////////////////////////////////////// KeyData keylist[KEYDATA_TABLE_SIZE]; diff --git a/CrypTool/ListResults.cpp b/CrypTool/ListResults.cpp index f156dab29..ca27d694b 100644 --- a/CrypTool/ListResults.cpp +++ b/CrypTool/ListResults.cpp @@ -24,8 +24,8 @@ #include "stdafx.h" #include "CrypToolApp.h" #include "ListResults.h" -#include ".\listresults.h" -#include "bruteforceheap.h" +#include "ListResults.h" +#include "BruteForceHeap.h" #include "DialogeMessage.h" // CListResults dialog @@ -53,7 +53,7 @@ void CListResults::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CListResults, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDOK, &CListResults::OnBnClickedOk) ON_WM_SIZE() END_MESSAGE_MAP() diff --git a/CrypTool/MONTY.CPP b/CrypTool/MONTY.CPP index 11acd87e1..4918f560d 100644 --- a/CrypTool/MONTY.CPP +++ b/CrypTool/MONTY.CPP @@ -38,7 +38,7 @@ #include using namespace std; #endif -#include "monty.h" +#include "MONTY.H" BOOL ZZn::iszero() const {return fn.iszero(); } diff --git a/CrypTool/MONTY.H b/CrypTool/MONTY.H index bdaeff117..2a5e0ad04 100644 --- a/CrypTool/MONTY.H +++ b/CrypTool/MONTY.H @@ -104,9 +104,11 @@ public: friend ZZn pow( int,ZZn *,Big *); friend ZZn sqrt(const ZZn&); // only works if modulus is prime - friend ZZn luc( const ZZn&, const Big&, ZZn* b3=NULL); + friend ZZn luc( const ZZn&, const Big&, ZZn* b3); ~ZZn() { } }; +ZZn luc(const ZZn&, const Big&, ZZn* b3=NULL); + #endif diff --git a/CrypTool/MakeZip.cpp b/CrypTool/MakeZip.cpp index 972df2053..cd7d455af 100644 --- a/CrypTool/MakeZip.cpp +++ b/CrypTool/MakeZip.cpp @@ -29,9 +29,9 @@ #include "FileTools.h" #include "Cryptography.h" #include "MakeZip.h" -#include "zip\zipup.h" -#include "zip\zunzip.h" -#include "zip\zip.h" +#include "zip/zipup.h" +#include "zip/zunzip.h" +#include "zip/zip.h" #include "AppDocument.h" const char MagicZipNumber[4] = "CTZ"; diff --git a/CrypTool/MonoSubstCracker.cpp b/CrypTool/MonoSubstCracker.cpp index 891753f15..89d9a55aa 100644 --- a/CrypTool/MonoSubstCracker.cpp +++ b/CrypTool/MonoSubstCracker.cpp @@ -455,7 +455,7 @@ UINT AutoAnaSubst(PVOID p) AfxMessageBox(message, MB_ICONINFORMATION|MB_OK); return 0; } - fprintf(file, "%s", Dialog.getText()); + fprintf(file, "%s", (LPCTSTR)Dialog.getText()); fclose(file); // Start manual analysis if requested and possible diff --git a/CrypTool/NumberEdit.cpp b/CrypTool/NumberEdit.cpp index 086d17885..baeee6dcc 100644 --- a/CrypTool/NumberEdit.cpp +++ b/CrypTool/NumberEdit.cpp @@ -55,10 +55,10 @@ CNumberEdit::~CNumberEdit() { BEGIN_MESSAGE_MAP(CNumberEdit, CEdit) ON_WM_CHAR() ON_WM_KEYDOWN() - ON_COMMAND(ID_EDIT_CUT, onEditCut) - ON_COMMAND(ID_EDIT_COPY, onEditCopy) - ON_COMMAND(ID_EDIT_PASTE, onEditPaste) - ON_COMMAND(ID_EDIT_SELECT_ALL, onEditSelectAll) + ON_COMMAND(ID_EDIT_CUT, &CNumberEdit::onEditCut) + ON_COMMAND(ID_EDIT_COPY, &CNumberEdit::onEditCopy) + ON_COMMAND(ID_EDIT_PASTE, &CNumberEdit::onEditPaste) + ON_COMMAND(ID_EDIT_SELECT_ALL, &CNumberEdit::onEditSelectAll) ON_WM_CONTEXTMENU() END_MESSAGE_MAP() diff --git a/CrypTool/OpenGLDoc.cpp b/CrypTool/OpenGLDoc.cpp index be339c5ce..6ce8c0b97 100644 --- a/CrypTool/OpenGLDoc.cpp +++ b/CrypTool/OpenGLDoc.cpp @@ -22,7 +22,7 @@ // #include "stdafx.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" #include "OpenGLDoc.h" #include diff --git a/CrypTool/OpenGLDoc.h b/CrypTool/OpenGLDoc.h index bd96b9e49..e42923384 100644 --- a/CrypTool/OpenGLDoc.h +++ b/CrypTool/OpenGLDoc.h @@ -30,7 +30,7 @@ #include "VolumeRenderer.h" #include "VolumeUtilities.h" #include "StreamToVolume.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" ///////////////////////////////////////////////////////////////////////////// diff --git a/CrypTool/OpenGLView.cpp b/CrypTool/OpenGLView.cpp index 6d3fba602..9d96b4918 100644 --- a/CrypTool/OpenGLView.cpp +++ b/CrypTool/OpenGLView.cpp @@ -30,7 +30,7 @@ #include "OpenGL.h" #include #include -#include ".\openglview.h" +#include "OpenGLView.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -114,9 +114,9 @@ BEGIN_MESSAGE_MAP(COpenGLView, CView) ON_WM_LBUTTONUP() ON_WM_SIZE() ON_WM_CONTEXTMENU() - ON_COMMAND(ID_POPUP_OPENGL_SHOW_BOX, OnPopupOpenglShowBox) + ON_COMMAND(ID_POPUP_OPENGL_SHOW_BOX, &COpenGLView::OnPopupOpenglShowBox) ON_WM_DESTROY() - ON_COMMAND(ID_POPUP_OPENGL_EIGENSCHAFTEN, OnPopupOpenglEigenschaften) + ON_COMMAND(ID_POPUP_OPENGL_EIGENSCHAFTEN, &COpenGLView::OnPopupOpenglEigenschaften) ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() //}}AFX_MSG_MAP @@ -201,8 +201,8 @@ int COpenGLView::Init() // Createan OpenGL rendering context m_hOpenGLContext = wglCreateContext(m_pDC->GetSafeHdc()); ASSERT(m_hOpenGLContext != NULL); - wglMakeCurrent(m_pDC->GetSafeHdc(), m_hOpenGLContext); - glEnable(GL_DEPTH_TEST); + if (wglMakeCurrent(m_pDC->GetSafeHdc(), m_hOpenGLContext)) + glEnable(GL_DEPTH_TEST); return 1; } diff --git a/CrypTool/OpenGLView.h b/CrypTool/OpenGLView.h index 110a4c03e..e65c025d2 100644 --- a/CrypTool/OpenGLView.h +++ b/CrypTool/OpenGLView.h @@ -29,7 +29,7 @@ #include "CrypToolVolRen.h" #include "OpenGLDoc.h" -#include "cryptoolapp.h" +#include "CrypToolApp.h" // we need those defines for our dynamic context menu #define CM_OPENGL_PROPERTIES 7777 diff --git a/CrypTool/POLY.CPP b/CrypTool/POLY.CPP index b3ffcebd6..c2ee5e3ee 100644 --- a/CrypTool/POLY.CPP +++ b/CrypTool/POLY.CPP @@ -31,7 +31,7 @@ * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 */ -#include "poly.h" +#include "POLY.H" Poly::Poly(const Poly& p) { @@ -719,10 +719,10 @@ ostream& operator<<(ostream& s,const Poly& p) s << " - "; } if (ptr->n==0) - cout << a; + cout << (Big)a; else { - if ((ZZn) a!=(ZZn)1) s << a << "*x"; + if ((ZZn) a!=(ZZn)1) s << (Big)a << "*x"; else s << "x"; if (ptr->n!=1) s << "^" << ptr->n; } diff --git a/CrypTool/POLY.H b/CrypTool/POLY.H index 3c44494a7..dbb3eb1ea 100644 --- a/CrypTool/POLY.H +++ b/CrypTool/POLY.H @@ -39,7 +39,7 @@ #include using namespace std; #endif -#include "monty.h" +#include "MONTY.H" #define FFT_BREAK_EVEN 16 diff --git a/CrypTool/POLYMOD.CPP b/CrypTool/POLYMOD.CPP index f7df009f0..2a16dd643 100644 --- a/CrypTool/POLYMOD.CPP +++ b/CrypTool/POLYMOD.CPP @@ -40,7 +40,7 @@ #include using namespace std; #endif -#include "polymod.h" +#include "POLYMOD.H" Poly modulus; @@ -98,7 +98,7 @@ static int window(Big x,int i,int *nbs,int * nzs) PolyMod& PolyMod::operator*=(const PolyMod &b) { - int i,m,deg,dega,degb,degm=degree(modulus); + int i,m,deg,dega,degb,degm=degree(::modulus); big *G,*B,*R; BOOL squaring; term *ptr=p.start; @@ -164,7 +164,7 @@ PolyMod& PolyMod::operator*=(const PolyMod &b) if (!mr_poly_rem(deg,G,R)) { // reset the modulus - things have changed - setmod(modulus); + setmod(::modulus); mr_poly_rem(deg,G,R); } @@ -211,7 +211,7 @@ void reduce(const Poly& p,PolyMod& rem) big *G,*R; term *ptr,*pos=NULL; int n=degree(p); - int degm=degree(modulus); + int degm=degree(::modulus); if (n-degm < FFT_BREAK_EVEN) { rem=(PolyMod)p; @@ -230,7 +230,7 @@ void reduce(const Poly& p,PolyMod& rem) } if (!mr_poly_rem(n,G,R)) { // reset the modulus - things have changed - setmod(modulus); + setmod(::modulus); mr_poly_rem(n,G,R); } @@ -256,7 +256,7 @@ void setmod(const Poly& p) Poly h; term *ptr; big *f,*rf; - modulus=p; + ::modulus=p; n=degree(p); if (n using namespace std; #endif -#include "poly.h" +#include "POLY.H" extern Poly modulus; @@ -52,7 +52,7 @@ public: Poly p; PolyMod() { } - PolyMod(const Poly& m) {p=m%modulus; } + PolyMod(const Poly& m) {p=m% ::modulus; } PolyMod(const PolyMod& m) {p=m.p; } void clear() {p.clear();} term* addterm(const ZZn& z,int i,term *pos=NULL) {return p.addterm(z,i,pos);} @@ -62,8 +62,8 @@ public: PolyMod& operator=(int m) {p=m; return *this;} PolyMod& operator=(const PolyMod& m) {p=m.p; return *this;} PolyMod& operator=(const Poly& m) {reduce(m,*this); return *this;} - PolyMod& operator+=(const PolyMod& m) {p=(p+m.p)%modulus;return *this;} - PolyMod& operator-=(const PolyMod& m) {p=(p-m.p)%modulus;return *this;} + PolyMod& operator+=(const PolyMod& m) {p=(p+m.p)% ::modulus;return *this;} + PolyMod& operator-=(const PolyMod& m) {p=(p-m.p)% ::modulus;return *this;} PolyMod& operator+=(const ZZn& m) {addterm(m,0); return *this;} PolyMod& operator-=(const ZZn& m) {addterm((-m),0); return *this;} PolyMod& operator*=(const ZZn& z) {p*=z;return *this;} @@ -94,5 +94,7 @@ public: ~PolyMod() {} }; +void setmod(const Poly&); + #endif diff --git a/CrypTool/PSEDemo.cpp b/CrypTool/PSEDemo.cpp index b986bcf3f..1fffb22b3 100644 --- a/CrypTool/PSEDemo.cpp +++ b/CrypTool/PSEDemo.cpp @@ -28,12 +28,12 @@ #include "PSEDemo.h" #include "IntegerArithmetic.h" #include "DlgKeyAsymGeneration.h" -#include "secudelib.h" +#include "SecudeLib.h" #include "secure.h" // Header-File für das SECUDE-Toolkit #include "af.h" // Header-File für den SECUDE Authentication Framework #include "CrypToolApp.h" #include "Cryptography.h" -#include "secudetools.h" +#include "SecudeTools.h" #include "DlgRSADecryption.h" #include "DialogeMessage.h" @@ -180,7 +180,7 @@ BOOL CPSEDemo::CreatePSE() // PSE-File erzeugen und öffnen m_sUserKeyId = CreateUserKeyID(); - m_sPseName.Format(IDS_CREATE_PSE, PseVerzeichnis, m_sUserKeyId); + m_sPseName.Format(IDS_CREATE_PSE, PseVerzeichnis, (LPCTSTR)m_sUserKeyId); m_hPSE = theApp.SecudeLib.af_create(const_cast(LPCTSTR(m_sPseName)), NULL, const_cast(LPCTSTR(m_sPIN)), NULL, TRUE); if(!m_hPSE) { @@ -442,7 +442,7 @@ CString CPSEDemo::CreateUserKeyID(const CString& sName, const CString& sFirstNam FirstName.TrimRight(); KeyID.TrimLeft(); KeyID.TrimRight(); - sUserKeyId.Format(KeyID.IsEmpty()? IDS_CREATE_USER_KEY_ID1: IDS_CREATE_USER_KEY_ID2, Name, FirstName, TUTORIAL_ALG_NAME, GetBitLength(), lTime, sKeyID); + sUserKeyId.Format(KeyID.IsEmpty()? IDS_CREATE_USER_KEY_ID1: IDS_CREATE_USER_KEY_ID2, (LPCTSTR)Name, (LPCTSTR)FirstName, TUTORIAL_ALG_NAME, GetBitLength(), lTime, (LPCTSTR)sKeyID); return sUserKeyId; } @@ -455,7 +455,7 @@ CString CPSEDemo::CreateDisName(const CString& sName, const CString& sFirstName, Name.TrimRight(); FirstName.TrimLeft(); FirstName.TrimRight(); - sDisName.Format("CN=%s %s [%I64i], %s", FirstName, Name, lTime, DN_SUFFIX); + sDisName.Format("CN=%s %s [%I64i], %s", (LPCTSTR)FirstName, (LPCTSTR)Name, lTime, DN_SUFFIX); return sDisName; } @@ -678,7 +678,7 @@ BOOL CPSEDemo::AccessPSE_DLG() SetTime(DlgPSE.CreatTime); SetPIN(DlgPSE.m_PinCode); m_sUserKeyId = DlgPSE.UserKeyId; - m_sPseName.Format(IDS_CREATE_PSE, PseVerzeichnis, m_sUserKeyId); + m_sPseName.Format(IDS_CREATE_PSE, PseVerzeichnis, (LPCTSTR)m_sUserKeyId); return TestAccess() && AccessPSE(); } return FALSE; diff --git a/CrypTool/PictureEx.h b/CrypTool/PictureEx.h index a8069e646..72940587f 100644 --- a/CrypTool/PictureEx.h +++ b/CrypTool/PictureEx.h @@ -106,6 +106,10 @@ #include +#ifndef _WIN32 +class wxImage; +#endif + //#define GIF_TRACING // uncomment it if you want detailed TRACEs @@ -119,7 +123,11 @@ class CPictureEx : public CStatic struct TFrame // structure that keeps a single frame info { +#ifdef _WIN32 IPicture *m_pPicture; // pointer to the interface used for drawing +#else + wxImage *m_pPicture; +#endif SIZE m_frameSize; SIZE m_frameOffset; UINT m_nDelay; // delay (in 1/100s of a second) @@ -299,7 +307,14 @@ struct TGIFImageDescriptor // image descriptor block HBITMAP m_hOldBitmap; HANDLE m_hThread; HANDLE m_hExitEvent; +#ifdef _WIN32 IPicture * m_pPicture; +#else + // wxWidgets implementation (PictureEx_wx.cpp): images replace IPicture and the memory DCs + wxImage * m_pPicture; + wxImage * m_pCanvas; + wxImage * m_pDispCanvas; +#endif TGIFHeader * m_pGIFHeader; unsigned char * m_pRawData; TGIFLSDescriptor * m_pGIFLSDescriptor; @@ -323,6 +338,9 @@ struct TGIFImageDescriptor // image descriptor block afx_msg void OnDestroy(); afx_msg void OnPaint(); //}}AFX_MSG +#ifndef _WIN32 + afx_msg void OnTimer(UINT_PTR nIDEvent); +#endif DECLARE_MESSAGE_MAP() }; diff --git a/CrypTool/PictureExLoop.h b/CrypTool/PictureExLoop.h index a84fcec55..4e2f824d4 100644 --- a/CrypTool/PictureExLoop.h +++ b/CrypTool/PictureExLoop.h @@ -104,6 +104,10 @@ #include +#ifndef _WIN32 +class wxImage; +#endif + //#define GIF_TRACING // uncomment it if you want detailed TRACEs @@ -117,7 +121,11 @@ class CPictureExLoop : public CStatic struct TFrame // structure that keeps a single frame info { +#ifdef _WIN32 IPicture *m_pPicture; // pointer to the interface used for drawing +#else + wxImage *m_pPicture; +#endif SIZE m_frameSize; SIZE m_frameOffset; UINT m_nDelay; // delay (in 1/100s of a second) @@ -297,7 +305,14 @@ struct TGIFImageDescriptor // image descriptor block HBITMAP m_hOldBitmap; HANDLE m_hThread; HANDLE m_hExitEvent; +#ifdef _WIN32 IPicture * m_pPicture; +#else + // wxWidgets implementation (PictureEx_wx.cpp): images replace IPicture and the memory DCs + wxImage * m_pPicture; + wxImage * m_pCanvas; + wxImage * m_pDispCanvas; +#endif TGIFHeader * m_pGIFHeader; unsigned char * m_pRawData; TGIFLSDescriptor * m_pGIFLSDescriptor; @@ -321,6 +336,9 @@ struct TGIFImageDescriptor // image descriptor block afx_msg void OnDestroy(); afx_msg void OnPaint(); //}}AFX_MSG +#ifndef _WIN32 + afx_msg void OnTimer(UINT_PTR nIDEvent); +#endif DECLARE_MESSAGE_MAP() }; \ No newline at end of file diff --git a/CrypTool/PictureExLoop_wx.cpp b/CrypTool/PictureExLoop_wx.cpp new file mode 100644 index 000000000..5b909ba3e --- /dev/null +++ b/CrypTool/PictureExLoop_wx.cpp @@ -0,0 +1,27 @@ +/************************************************************************** + + Copyright [2009] [CrypTool Team] + + This file is part of CrypTool. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**************************************************************************/ + +// wxWidgets implementation of CPictureExLoop (PictureExLoop.cpp is the Windows implementation). + +#include "stdafx.h" +#include "PictureExLoop.h" + +#define PICTUREEX_WX_CLASS CPictureExLoop +#include "PictureEx_wx.cpp" diff --git a/CrypTool/PictureEx_wx.cpp b/CrypTool/PictureEx_wx.cpp new file mode 100644 index 000000000..9e570800b --- /dev/null +++ b/CrypTool/PictureEx_wx.cpp @@ -0,0 +1,636 @@ +/************************************************************************** + + Copyright [2009] [CrypTool Team] + + This file is part of CrypTool. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**************************************************************************/ + +////////////////////////////////////////////////////////////////////// +// PictureEx_wx.cpp: wxWidgets implementation of CPictureEx for platforms +// without OLE (IPicture). PictureEx.cpp remains the Windows implementation. +// +// GIF frames are decoded with wxGIFDecoder, other formats with wxImage. +// The memory DCs of the Windows version are replaced by wxImage canvases +// (m_pCanvas, m_pDispCanvas); the animation is advanced by a window timer +// on the GUI thread instead of a worker thread. +// +// PictureExLoop_wx.cpp compiles this file once more for CPictureExLoop. +////////////////////////////////////////////////////////////////////// + +#ifndef PICTUREEX_WX_CLASS +#include "stdafx.h" +#include "PictureEx.h" +#define PICTUREEX_WX_CLASS CPictureEx +#endif + +#include +#include +#include +#include +#include + +namespace { + +const UINT_PTR ANIMATION_TIMER_ID = 1; + +void FillArea(wxImage &img, int x, int y, int w, int h, COLORREF clr) +{ + wxRect rect(x, y, w, h); + rect.Intersect(wxRect(0, 0, img.GetWidth(), img.GetHeight())); + if (!rect.IsEmpty()) + img.SetRGB(rect, GetRValue(clr), GetGValue(clr), GetBValue(clr)); +} + +// copies the rectangle (x, y, w, h) from src to dst (both of the same size) +void CopyArea(wxImage &dst, const wxImage &src, int x, int y, int w, int h) +{ + wxRect rect(x, y, w, h); + rect.Intersect(wxRect(0, 0, dst.GetWidth(), dst.GetHeight())); + rect.Intersect(wxRect(0, 0, src.GetWidth(), src.GetHeight())); + if (rect.IsEmpty()) + return; + for (int j = rect.y; j < rect.y + rect.height; j++) + memcpy(dst.GetData() + 3 * (j * dst.GetWidth() + rect.x), + src.GetData() + 3 * (j * src.GetWidth() + rect.x), 3 * rect.width); +} + +// draws src onto dst at (x, y); masked or transparent pixels of src leave dst unchanged +void Compose(wxImage &dst, const wxImage &src, int x, int y) +{ + const int dw = dst.GetWidth(), dh = dst.GetHeight(); + const int sw = src.GetWidth(), sh = src.GetHeight(); + const unsigned char *s = src.GetData(); + const unsigned char *alpha = src.HasAlpha() ? src.GetAlpha() : NULL; + const bool bMask = src.HasMask(); + const unsigned char mr = src.GetMaskRed(), mg = src.GetMaskGreen(), mb = src.GetMaskBlue(); + unsigned char *d = dst.GetData(); + + for (int j = 0; j < sh; j++) + { + const int dy = y + j; + if (dy < 0 || dy >= dh) + continue; + for (int i = 0; i < sw; i++) + { + const int dx = x + i; + if (dx < 0 || dx >= dw) + continue; + const unsigned char *sp = s + 3 * (j * sw + i); + unsigned char *dp = d + 3 * (dy * dw + dx); + if (bMask && sp[0] == mr && sp[1] == mg && sp[2] == mb) + continue; + const unsigned a = alpha ? alpha[j * sw + i] : 255; + for (int c = 0; c < 3; c++) + dp[c] = (unsigned char)((sp[c] * a + dp[c] * (255 - a)) / 255); + } + } +} + +UINT GifDisposal(wxAnimationDisposal disposal) +{ + switch (disposal) + { + case wxANIM_DONOTREMOVE: return 1; + case wxANIM_TOBACKGROUND: return 2; + case wxANIM_TOPREVIOUS: return 3; + default: return 0; + } +} + +} + +inline int PICTUREEX_WX_CLASS::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value) +{ + int nRet = (int)m_cPacked; + + switch (Value) + { + case LSD_PACKED_GLOBALCT: + nRet = nRet >> 7; + break; + + case LSD_PACKED_CRESOLUTION: + nRet = ((nRet & 0x70) >> 4) + 1; + break; + + case LSD_PACKED_SORT: + nRet = (nRet & 8) >> 3; + break; + + case LSD_PACKED_GLOBALCTSIZE: + nRet &= 7; + break; + }; + + return nRet; +} + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +PICTUREEX_WX_CLASS::PICTUREEX_WX_CLASS() +{ + m_pGIFLSDescriptor = NULL; + m_pGIFHeader = NULL; + m_pPicture = NULL; + m_pCanvas = NULL; + m_pDispCanvas = NULL; + m_pRawData = NULL; + m_hThread = NULL; + m_hBitmap = NULL; + m_hOldBitmap = NULL; + m_hMemDC = NULL; + m_hDispMemDC = NULL; + m_hDispMemBM = NULL; + m_hDispOldBM = NULL; + m_hExitEvent = NULL; + + m_bIsInitialized = FALSE; + m_bExitThread = FALSE; + m_bIsPlaying = FALSE; + m_bIsGIF = FALSE; + m_clrBackground = RGB(255,255,255); // white by default + m_nGlobalCTSize = 0; + m_nCurrOffset = 0; + m_nCurrFrame = 0; + m_nDataSize = 0; + m_PictureSize.cx = m_PictureSize.cy = 0; + SetRect(&m_PaintRect,0,0,0,0); +} + +PICTUREEX_WX_CLASS::~PICTUREEX_WX_CLASS() +{ + UnLoad(); +} + +BEGIN_MESSAGE_MAP(PICTUREEX_WX_CLASS, CStatic) + ON_WM_DESTROY() + ON_WM_PAINT() + ON_WM_TIMER() +END_MESSAGE_MAP() + +BOOL PICTUREEX_WX_CLASS::Load(HGLOBAL hGlobal, DWORD dwSize) +{ + UnLoad(); + + if (!(m_pRawData = reinterpret_cast (GlobalLock(hGlobal))) ) + { + TRACE(_T("Load: Error locking memory\n")); + return FALSE; + }; + + m_nDataSize = dwSize; + m_pGIFHeader = reinterpret_cast (m_pRawData); + wxMemoryInputStream stream(m_pRawData, dwSize); + + if (dwSize < sizeof(TGIFHeader) + sizeof(TGIFLSDescriptor) || + memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) + { + // it's not a GIF: let wxImage decode it + if (!wxImage::FindHandler(wxBITMAP_TYPE_JPEG)) + wxInitAllImageHandlers(); + + wxImage image; + bool bLoaded = image.LoadFile(stream, wxBITMAP_TYPE_ANY); + m_pRawData = NULL; + m_pGIFHeader = NULL; + GlobalUnlock(hGlobal); + if (!bLoaded || !image.IsOk()) + return FALSE; + + m_pPicture = new wxImage(image); + m_PictureSize.cx = image.GetWidth(); + m_PictureSize.cy = image.GetHeight(); + } + else + { + // it's a GIF + m_bIsGIF = TRUE; + m_pGIFLSDescriptor = reinterpret_cast + (m_pRawData + sizeof(TGIFHeader)); + if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1) + { + // calculate the globat color table size + m_nGlobalCTSize = static_cast + (3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1))); + // get the background color if GCT is present + UINT nBkOffset = sizeof(TGIFHeader) + sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex; + if (nBkOffset + 3 <= dwSize) + { + unsigned char *pBkClr = m_pRawData + nBkOffset; + m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]); + } + }; + + // store the picture's size + m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth; + m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight; + + wxGIFDecoder decoder; + wxGIFErrorCode err = decoder.LoadGIF(stream); + UINT nFrameCount = (err == wxGIF_OK || err == wxGIF_TRUNCATED) ? decoder.GetFrameCount() : 0; + + m_pRawData = NULL; + m_pGIFHeader = NULL; + m_pGIFLSDescriptor = NULL; + GlobalUnlock(hGlobal); + + if (nFrameCount == 0) // it's an empty GIF! + return FALSE; + + for (UINT i = 0; i < nFrameCount; i++) + { + wxImage image; + if (!decoder.ConvertToImage(i, &image) || !image.IsOk()) + continue; + + TFrame frame; + wxSize size = decoder.GetFrameSize(i); + wxPoint pos = decoder.GetFramePosition(i); + long nDelay = decoder.GetDelay(i); // milliseconds + frame.m_pPicture = new wxImage(image); + frame.m_frameSize.cx = size.GetWidth(); + frame.m_frameSize.cy = size.GetHeight(); + frame.m_frameOffset.cx = pos.x; + frame.m_frameOffset.cy = pos.y; + frame.m_nDelay = nDelay > 0 ? (UINT)(nDelay / 10) : 0; + frame.m_nDisposal = GifDisposal(decoder.GetDisposalMethod(i)); + m_arrFrames.push_back(frame); + } + + if (m_arrFrames.empty()) // couldn't load any frames + return FALSE; + + // a GIF with a single frame is not animated: Draw() renders m_arrFrames[0] like any other pic + }; // if (!IsGIF... + + return PrepareDC(m_PictureSize.cx,m_PictureSize.cy); +} + +void PICTUREEX_WX_CLASS::UnLoad() +{ + Stop(); + delete m_pPicture; + m_pPicture = NULL; + + std::vector::iterator it; + for (it=m_arrFrames.begin();it= m_arrFrames.size()) + { + // a single run has finished: start again with the first frame + m_nCurrFrame = 0; + FillArea(*m_pCanvas, 0, 0, m_PictureSize.cx, m_PictureSize.cy, m_clrBackground); + } + + // first, restore background (for stop/draw support) + const TFrame &frame = m_arrFrames[m_nCurrFrame]; + if (frame.m_nDisposal == 2) + FillArea(*m_pCanvas, frame.m_frameOffset.cx, frame.m_frameOffset.cy, + frame.m_frameSize.cx, frame.m_frameSize.cy, m_clrBackground); + else if (m_pDispCanvas && frame.m_nDisposal == 3) + { + CopyArea(*m_pCanvas, *m_pDispCanvas, frame.m_frameOffset.cx, frame.m_frameOffset.cy, + frame.m_frameSize.cx, frame.m_frameSize.cy); + delete m_pDispCanvas; + m_pDispCanvas = NULL; + } + + m_bIsPlaying = TRUE; + ThreadAnimation(); + return TRUE; + } + + if (m_arrFrames.size() == 1 && m_arrFrames[0].m_pPicture) + { + Compose(*m_pCanvas, *m_arrFrames[0].m_pPicture, m_arrFrames[0].m_frameOffset.cx, m_arrFrames[0].m_frameOffset.cy); + if (m_hWnd) + Invalidate(FALSE); + return TRUE; + }; + + if (m_pPicture) + { + if (m_pPicture->GetWidth() == m_PictureSize.cx && m_pPicture->GetHeight() == m_PictureSize.cy) + Compose(*m_pCanvas, *m_pPicture, 0, 0); + else + Compose(*m_pCanvas, m_pPicture->Scale(m_PictureSize.cx, m_PictureSize.cy, wxIMAGE_QUALITY_HIGH), 0, 0); + if (m_hWnd) + Invalidate(FALSE); + return TRUE; + }; + + return FALSE; +} + +// renders the current animation frame and schedules the next one +void PICTUREEX_WX_CLASS::ThreadAnimation() +{ + const TFrame &frame = m_arrFrames[m_nCurrFrame]; + UINT nDelay = 1; + + if (frame.m_pPicture) + { + // disposal method #3: store the background + if (frame.m_nDisposal == 3) + { + delete m_pDispCanvas; + m_pDispCanvas = new wxImage(m_pCanvas->Copy()); + }; + + Compose(*m_pCanvas, *frame.m_pPicture, frame.m_frameOffset.cx, frame.m_frameOffset.cy); + if (m_hWnd) + Invalidate(FALSE); + + // if the delay time is too short (like in old GIFs), wait for 100ms + nDelay = frame.m_nDelay < 5 ? 100 : 10*frame.m_nDelay; + }; + + if (m_hWnd) + SetTimer(ANIMATION_TIMER_ID, nDelay, NULL); + else + m_bIsPlaying = FALSE; +} + +void PICTUREEX_WX_CLASS::OnTimer(UINT_PTR nIDEvent) +{ + if (nIDEvent != ANIMATION_TIMER_ID) + { + CStatic::OnTimer(nIDEvent); + return; + } + + KillTimer(ANIMATION_TIMER_ID); + if (!m_bIsPlaying || m_nCurrFrame >= m_arrFrames.size()) + return; + + const TFrame &frame = m_arrFrames[m_nCurrFrame]; + if (frame.m_nDisposal == 2) + FillArea(*m_pCanvas, frame.m_frameOffset.cx, frame.m_frameOffset.cy, + frame.m_frameSize.cx, frame.m_frameSize.cy, m_clrBackground); + else if (m_pDispCanvas && frame.m_nDisposal == 3) + { + CopyArea(*m_pCanvas, *m_pDispCanvas, frame.m_frameOffset.cx, frame.m_frameOffset.cy, + frame.m_frameSize.cx, frame.m_frameSize.cy); + delete m_pDispCanvas; + m_pDispCanvas = NULL; + } + + m_nCurrFrame++; + if (m_nCurrFrame == m_arrFrames.size()) + { +// Animation nur ein einziges Mal abspielen? +#ifdef PLAY_ANIM_ONLY_ONCE + m_bIsPlaying = FALSE; + return; +#else + m_nCurrFrame = 0; + // init the screen for the first frame, + FillArea(*m_pCanvas, 0, 0, m_PictureSize.cx, m_PictureSize.cy, m_clrBackground); +#endif + }; + + ThreadAnimation(); +} + +SIZE PICTUREEX_WX_CLASS::GetSize() const +{ + return m_PictureSize; +} + +BOOL PICTUREEX_WX_CLASS::Load(LPCTSTR szFileName) +{ + ASSERT(szFileName); + + CFile file; + if (!file.Open(szFileName, CFile::modeRead | CFile::shareDenyWrite)) + { + TRACE(_T("Load (file): Error opening file %s\n"),szFileName); + return FALSE; + }; + + DWORD dwSize = (DWORD)file.GetLength(); + HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE,dwSize); + if (!hGlobal) + { + TRACE(_T("Load (file): Error allocating memory\n")); + return FALSE; + }; + + char *pData = reinterpret_cast(GlobalLock(hGlobal)); + if (!pData) + { + TRACE(_T("Load (file): Error locking memory\n")); + GlobalFree(hGlobal); + return FALSE; + }; + + UINT nRead = 0; + TRY + { + nRead = file.Read(pData,dwSize); + } + CATCH(CFileException, e) + { + TRACE(_T("Load (file): An exception occured while reading the file %s\n"), szFileName); + e->Delete(); + } + END_CATCH + GlobalUnlock(hGlobal); + file.Close(); + + BOOL bRetValue = nRead == dwSize && Load(hGlobal,dwSize); + GlobalFree(hGlobal); + return bRetValue; +} + +BOOL PICTUREEX_WX_CLASS::Load(LPCTSTR szResourceName, LPCTSTR szResourceType) +{ + ASSERT(szResourceName); + ASSERT(szResourceType); + + HRSRC hPicture = FindResource(AfxGetResourceHandle(),szResourceName,szResourceType); + HGLOBAL hResData; + if (!hPicture || !(hResData = LoadResource(AfxGetResourceHandle(),hPicture))) + { + TRACE(_T("Load (resource): Error loading resource %s\n"),szResourceName); + return FALSE; + }; + DWORD dwSize = SizeofResource(AfxGetResourceHandle(),hPicture); + + HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE,dwSize); + if (!hGlobal) + { + TRACE(_T("Load (resource): Error allocating memory\n")); + FreeResource(hResData); + return FALSE; + }; + + char *pDest = reinterpret_cast (GlobalLock(hGlobal)); + char *pSrc = reinterpret_cast (LockResource(hResData)); + if (!pSrc || !pDest) + { + TRACE(_T("Load (resource): Error locking memory\n")); + GlobalFree(hGlobal); + FreeResource(hResData); + return FALSE; + }; + CopyMemory(pDest,pSrc,dwSize); + FreeResource(hResData); + GlobalUnlock(hGlobal); + + BOOL bRetValue = Load(hGlobal,dwSize); + GlobalFree(hGlobal); + return bRetValue; +} + +void PICTUREEX_WX_CLASS::Stop() +{ + m_bIsPlaying = FALSE; + if (m_hWnd && ::IsWindow(m_hWnd)) + KillTimer(ANIMATION_TIMER_ID); + m_bExitThread = FALSE; +} + +BOOL PICTUREEX_WX_CLASS::IsGIF() const +{ + return m_bIsGIF; +} + +BOOL PICTUREEX_WX_CLASS::IsAnimatedGIF() const +{ + return (m_bIsGIF && (m_arrFrames.size() > 1)); +} + +BOOL PICTUREEX_WX_CLASS::IsPlaying() const +{ + return m_bIsPlaying; +} + +int PICTUREEX_WX_CLASS::GetFrameCount() const +{ + if (!IsAnimatedGIF()) + return 0; + + return (int)m_arrFrames.size(); +} + +COLORREF PICTUREEX_WX_CLASS::GetBkColor() const +{ + return m_clrBackground; +} + +void PICTUREEX_WX_CLASS::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + wxDC *pDC = dc.GetWx(); + if (!m_pCanvas || !pDC) + return; + + LONG nPaintWidth = m_PaintRect.right-m_PaintRect.left; + + if (nPaintWidth > 0) + { + wxRect rect(m_PaintRect.left, m_PaintRect.top, nPaintWidth, m_PaintRect.bottom - m_PaintRect.top); + rect.Intersect(wxRect(0, 0, m_pCanvas->GetWidth(), m_pCanvas->GetHeight())); + if (!rect.IsEmpty()) + pDC->DrawBitmap(wxBitmap(m_pCanvas->GetSubImage(rect)), + rect.x - m_PaintRect.left, rect.y - m_PaintRect.top, false); + } + else + { + pDC->DrawBitmap(wxBitmap(*m_pCanvas), 0, 0, false); + }; +} + +BOOL PICTUREEX_WX_CLASS::PrepareDC(int nWidth, int nHeight) +{ + if (m_hWnd) + SetWindowPos(NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER); + + if (nWidth <= 0 || nHeight <= 0) + return FALSE; + + m_pCanvas = new wxImage(nWidth, nHeight, false); + + // fill the background + m_clrBackground = GetSysColor(COLOR_3DFACE); + FillArea(*m_pCanvas, 0, 0, nWidth, nHeight, m_clrBackground); + + m_bIsInitialized = TRUE; + return TRUE; +} + +void PICTUREEX_WX_CLASS::OnDestroy() +{ + Stop(); + CStatic::OnDestroy(); +} + +void PICTUREEX_WX_CLASS::SetBkColor(COLORREF clr) +{ + if (!m_bIsInitialized) return; + + m_clrBackground = clr; + FillArea(*m_pCanvas, 0, 0, m_PictureSize.cx, m_PictureSize.cy, clr); +} + +BOOL PICTUREEX_WX_CLASS::SetPaintRect(const RECT *lpRect) +{ + return CopyRect(&m_PaintRect, lpRect); +} + +BOOL PICTUREEX_WX_CLASS::GetPaintRect(RECT *lpRect) +{ + return CopyRect(lpRect, &m_PaintRect); +} diff --git a/CrypTool/PlayfairAnalysis.cpp b/CrypTool/PlayfairAnalysis.cpp index df615e0f8..944841acb 100644 --- a/CrypTool/PlayfairAnalysis.cpp +++ b/CrypTool/PlayfairAnalysis.cpp @@ -2370,7 +2370,7 @@ void playfair_liste::init( int msize ) playfair_liste::~playfair_liste(void) { - if(d) delete[n+2] d; + if(d) delete[] d; } playfair_liste::playfair_liste(int msize, int l) diff --git a/CrypTool/PlayfairEdit.cpp b/CrypTool/PlayfairEdit.cpp index 393dc28b2..82e6c355a 100644 --- a/CrypTool/PlayfairEdit.cpp +++ b/CrypTool/PlayfairEdit.cpp @@ -49,7 +49,7 @@ CPlayfairEdit::~CPlayfairEdit() BEGIN_MESSAGE_MAP(CPlayfairEdit, CEdit) //{{AFX_MSG_MAP(CPlayfairEdit) ON_WM_CHAR() - ON_COMMAND(ID_EDIT_PASTE, OnEditPaste) + ON_COMMAND(ID_EDIT_PASTE, &CPlayfairEdit::OnEditPaste) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/CrypTool/PlayfairStructures.cpp b/CrypTool/PlayfairStructures.cpp index 4c1706abc..dd6c41c2a 100644 --- a/CrypTool/PlayfairStructures.cpp +++ b/CrypTool/PlayfairStructures.cpp @@ -68,7 +68,7 @@ CPlayfairAlphabet::CPlayfairAlphabet(char lower_letter/* = A*/, char upper_lette CPlayfairLetter CPlayfairAlphabet::addLetter(char let) { CPlayfairLetter ret_let; - if ((int)&(ret_let = getLetter(let, true)) != NULL) + if (&(ret_let = getLetter(let, true)) != NULL) return ret_let; if (my_count 1000 #include -#include "scintillawnd.h" +#include "ScintillaWnd.h" #include "CrypToolView.h" #ifdef SCFIND #include "FindDlg.h" diff --git a/CrypTool/ScintillaWnd.cpp b/CrypTool/ScintillaWnd.cpp index 30e311770..c13075aee 100644 --- a/CrypTool/ScintillaWnd.cpp +++ b/CrypTool/ScintillaWnd.cpp @@ -28,7 +28,7 @@ #include "stdafx.h" #include "ScintillaWnd.h" //#include "Tokenizer.h" -#include "scintilla.h" +#include "Scintilla.h" #include "SciLexer.h" #include @@ -276,7 +276,7 @@ LPSTR CScintillaWnd::GetText () if (pReturn != NULL) { *pReturn = '\0'; - SendMessage(SCI_GETTEXT, lLen, (long)pReturn); + SendMessage(SCI_GETTEXT, lLen, (LPARAM)pReturn); return pReturn; } } @@ -366,7 +366,7 @@ void CScintillaWnd::Serialize(CArchive& ar) do { tr.chrg.cpMin = i; tr.chrg.cpMax = i + nbuffer < len ? i + nbuffer : len; - n = SendMessage(SCI_GETTEXTRANGE, 0,(long)&tr); + n = SendMessage(SCI_GETTEXTRANGE, 0,(LPARAM)&tr); ar.Write(buffer,n); i += n; } while (i < len); @@ -402,7 +402,7 @@ BOOL CScintillaWnd::SaveFile ( tr.chrg.cpMax = -1; tr.lpstrText = pBuffer; //SendMessage(SCI_GETTEXT, buflen,(long)pBuffer); - SendMessage(SCI_GETTEXTRANGE, 0,(long)&tr); + SendMessage(SCI_GETTEXTRANGE, 0,(LPARAM)&tr); file.write(pBuffer, buflen-1); delete [] pBuffer; } @@ -462,7 +462,7 @@ int CScintillaWnd::GetLinenumberWidth () // get number of chars needed to display highest linenumber int nChars = GetLinenumberChars ()+1; // get width of character '9' in pixels - LRESULT lWidth = SendMessage(SCI_TEXTWIDTH, STYLE_LINENUMBER, (long)_T("9")); + LRESULT lWidth = SendMessage(SCI_TEXTWIDTH, STYLE_LINENUMBER, (LPARAM)_T("9")); return nChars * lWidth; } ///////////////////////////////////// @@ -685,7 +685,7 @@ int CScintillaWnd::GetTextLength() // void CScintillaWnd::SetFontname(int nStyle, LPCSTR szFontname) { - SendMessage(SCI_STYLESETFONT, nStyle, (long)szFontname); + SendMessage(SCI_STYLESETFONT, nStyle, (LPARAM)szFontname); } ///////////////////////////////////// // @mfunc Set the font height in points @@ -980,13 +980,13 @@ BOOL CScintillaWnd::SearchForward( // added new search behaviour to be compliant to common search tools (tf.chrg.cpMin = lPos+1;) tf.chrg.cpMin = lPos; tf.chrg.cpMax = SendMessage(SCI_GETLENGTH, 0, 0); - lPos = SendMessage(SCI_FINDTEXT, m_nSearchflags, (long)&tf); + lPos = SendMessage(SCI_FINDTEXT, m_nSearchflags, (LPARAM)&tf); if (lPos >= 0) { SetFocus(); GotoPosition(lPos); SendMessage(SCI_SETSEL, tf.chrgText.cpMin, tf.chrgText.cpMax); - SendMessage(SCI_FINDTEXT, m_nSearchflags, (long)&tf); + SendMessage(SCI_FINDTEXT, m_nSearchflags, (LPARAM)&tf); return TRUE; } return FALSE; @@ -1009,13 +1009,13 @@ BOOL CScintillaWnd::SearchBackward( else tf.chrg.cpMin = lPos-1; tf.chrg.cpMax = 0; - lPos = SendMessage(SCI_FINDTEXT, m_nSearchflags, (long)&tf); + lPos = SendMessage(SCI_FINDTEXT, m_nSearchflags, (LPARAM)&tf); if (lPos >= 0) { SetFocus(); GotoPosition(lPos); SendMessage(SCI_SETSEL, tf.chrgText.cpMin, tf.chrgText.cpMax); - SendMessage(SCI_FINDTEXT, m_nSearchflags, (long)&tf); + SendMessage(SCI_FINDTEXT, m_nSearchflags, (LPARAM)&tf); return TRUE; } return FALSE; @@ -1031,9 +1031,9 @@ void CScintillaWnd::ReplaceSearchedText( return; SendMessage(SCI_TARGETFROMSELECTION, 0, 0); if (m_nSearchflags & SCFIND_REGEXP) - SendMessage(SCI_REPLACETARGETRE, strlen(szText), (long)szText); + SendMessage(SCI_REPLACETARGETRE, strlen(szText), (LPARAM)szText); else - SendMessage(SCI_REPLACETARGET, strlen(szText), (long)szText); + SendMessage(SCI_REPLACETARGET, strlen(szText), (LPARAM)szText); } ///////////////////////////////////// // @mfunc Set lexer format - see scintilla.h @@ -1073,7 +1073,7 @@ CString CScintillaWnd::GetSelectedText() if (p != NULL) { *p = '\0'; - SendMessage(SCI_GETSELTEXT, 0, (long)p); + SendMessage(SCI_GETSELTEXT, 0, (LPARAM)p); CString strReturn = p; delete [] p; return strReturn; @@ -1102,21 +1102,21 @@ int CScintillaWnd::ReplaceAll( SendMessage(SCI_SETTARGETSTART, lStart); SendMessage(SCI_SETTARGETEND, lEnd); // try to find text in target for the first time - long lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (long)szFind); + long lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (LPARAM)szFind); // loop over selection until end of selection reached - moving the target start each time while (lPos < lEnd && lPos >= 0) { if (m_nSearchflags & SCFIND_REGEXP) // check for regular expression flag - lLen = SendMessage(SCI_REPLACETARGETRE, strlen(szReplace), (long)szReplace); + lLen = SendMessage(SCI_REPLACETARGETRE, strlen(szReplace), (LPARAM)szReplace); else - lLen = SendMessage(SCI_REPLACETARGET, strlen(szReplace), (long)szReplace); + lLen = SendMessage(SCI_REPLACETARGET, strlen(szReplace), (LPARAM)szReplace); // the end of the selection was changed - recalc the end lEnd = GetSelectionEnd(); // move start of target behind last change and end of target to new end of selection SendMessage(SCI_SETTARGETSTART, lPos+lLen); SendMessage(SCI_SETTARGETEND, lEnd); // find again - if nothing found loop exits - lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (long)szFind); + lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (LPARAM)szFind); nCount++; } } @@ -1130,21 +1130,21 @@ int CScintillaWnd::ReplaceAll( SendMessage(SCI_SETTARGETSTART, lStart, 0); SendMessage(SCI_SETTARGETEND, lEnd, 0); // try to find text in target for the first time - long lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (long)szFind); + long lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (LPARAM)szFind); // loop over selection until end of selection reached - moving the target start each time while (lPos < lEnd && lPos >= 0) { if (m_nSearchflags & SCFIND_REGEXP) // check for regular expression flag - lLen = SendMessage(SCI_REPLACETARGETRE, strlen(szReplace), (long)szReplace); + lLen = SendMessage(SCI_REPLACETARGETRE, strlen(szReplace), (LPARAM)szReplace); else - lLen = SendMessage(SCI_REPLACETARGET, strlen(szReplace), (long)szReplace); + lLen = SendMessage(SCI_REPLACETARGET, strlen(szReplace), (LPARAM)szReplace); // the end of the selection was changed - recalc the end lEnd = SendMessage(SCI_GETTEXTLENGTH, 0, 0);; // move start of target behind last change and end of target to new end of buffer SendMessage(SCI_SETTARGETSTART, lPos+lLen); SendMessage(SCI_SETTARGETEND, lEnd); // find again - if nothing found loop exits - lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (long)szFind); + lPos = SendMessage(SCI_SEARCHINTARGET, strlen(szFind), (LPARAM)szFind); nCount++; } } diff --git a/CrypTool/ScintillaWnd.h b/CrypTool/ScintillaWnd.h index 4d54533e7..6f0264dae 100644 --- a/CrypTool/ScintillaWnd.h +++ b/CrypTool/ScintillaWnd.h @@ -29,9 +29,9 @@ #ifndef __SCINTILLAWND_H__ #define __SCINTILLAWND_H__ -#include "platform.h" -#include "scintilla.h" -#include "scilexer.h" +#include "Platform.h" +#include "Scintilla.h" +#include "SciLexer.h" //////////////////////////////////// // @class CScintillaWnd | Class of a GCL Scintilla syntax coloring edit control for MFC diff --git a/CrypTool/SecudeLib.cpp b/CrypTool/SecudeLib.cpp index e8d68d4fd..556b6315b 100644 --- a/CrypTool/SecudeLib.cpp +++ b/CrypTool/SecudeLib.cpp @@ -35,7 +35,12 @@ static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif +#ifdef _WIN32 #define DYNAMICSECUDE +#else +// SECUDE.DLL is replaced by the statically linked compatibility library (port/secude) +#include "secude_compat.h" +#endif ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// @@ -89,6 +94,9 @@ int CSecudeLib::OpenSecudeLib() #ifdef DYNAMICSECUDE #define DoOneFn( a, b, c ,d) c = (c##_t) GetProcAddress(hDLL,"_"###c##d); if(c==NULL) errcnt++; #define DoOneData(a, b) b = (a *) GetProcAddress(hDLL, #b); if(b==NULL) errcnt++; +#elif !defined(_WIN32) +#define DoOneFn( a, b, c ,d) c = (c##_t) secude_compat_symbol(#c); if(c==NULL) errcnt++; +#define DoOneData(a, b) b = (a *) secude_compat_symbol(#b); if(b==NULL) errcnt++; #else #define DoOneFn(a,b,c,d) c=(c##_t) ::c; #define DoOneData(a,b) b=(a *) &::b; @@ -98,7 +106,7 @@ int CSecudeLib::OpenSecudeLib() #undef DoOneFn #undef DoOneData -#ifdef DYNAMICSECUDE +#if defined(DYNAMICSECUDE) || !defined(_WIN32) if(errcnt > 0) { // MessageBox(NULL,"SECUDE Lib konnte nicht geladen werden!","Test", MB_OK); Message(IDS_SECUDE_COULD_NOT_BE_LOADED, MB_ICONEXCLAMATION); diff --git a/CrypTool/SecudeTools.cpp b/CrypTool/SecudeTools.cpp index 000c48169..10a82fdf6 100644 --- a/CrypTool/SecudeTools.cpp +++ b/CrypTool/SecudeTools.cpp @@ -82,7 +82,7 @@ ObjId * CrypToolPSEName_OID() } -static char * basename(char *psename) +static char * pse_basename(char *psename) { char *pos; @@ -169,7 +169,7 @@ OctetString *PKCS12_encode(PSE pse, OctetString * PIN, int iterationcount, int e P12safe.bags = NULL; P12bagp = &P12safe.bags; - name = basename(pse->pse_name); + name = pse_basename(pse->pse_name); // cryptool only supports one key pair per PSE. if this changes in the future, // this code must be extended @@ -255,7 +255,7 @@ OctetString *PKCS12_encode(PSE pse, OctetString * PIN, int iterationcount, int e int PKCS12_import(PSE pse, OctetString *input, OctetString *password, int newpse) { P12_Safe P12safe; - char verified; + Boolean verified; P12_Bag *thisbag; int rc, keys, certs, ii, ok, bags; Certificate *thiscert; diff --git a/CrypTool/SideChannelAttack.cpp b/CrypTool/SideChannelAttack.cpp index 1d2b353c8..3c146e9c7 100644 --- a/CrypTool/SideChannelAttack.cpp +++ b/CrypTool/SideChannelAttack.cpp @@ -717,7 +717,8 @@ Big SCA_Attacker::computeZ(Big N, Big B) char temp[SCA_MAXIMUM_KEY_LENGTH_IN_BYTE+1]; temp << N; std::string strModul = temp; - double bitLengthModul = ceil(BitLength((CString)strModul.c_str(),10)); + CString cstrModul = strModul.c_str(); + double bitLengthModul = ceil(BitLength(cstrModul,10)); // Bitlänge der bekannten Grenzen berechnen (2^b = B) int b = log2( B ); @@ -1430,7 +1431,8 @@ void generateSCAReport(SCA_Client *_alice, SCA_Server *_bob, SCA_Attacker *_trud LoadString(AfxGetInstanceHandle(), IDS_SCA_REPORT_TRUDYINTERCEPTEDMESSAGE, pc_str, STR_LAENGE_STRING_TABLE); strcat(protocolString, pc_str); // Ausgabe des abgefangenen, verschlüsselten Session Keys - convertOctetStringToHexString( &_trudy->getInterceptedSessionKey(), temp); + OctetString interceptedSessionKey = _trudy->getInterceptedSessionKey(); + convertOctetStringToHexString( &interceptedSessionKey, temp); strcat(protocolString, temp); // *** ATTACK CYCLE *** diff --git a/CrypTool/SideChannelAttack.h b/CrypTool/SideChannelAttack.h index 95c54d7a6..7933b1c61 100644 --- a/CrypTool/SideChannelAttack.h +++ b/CrypTool/SideChannelAttack.h @@ -51,7 +51,7 @@ class SCA_Attacker; #include #include #include "AsymmetricEncryption.h" -#include "../libmiracl/include/BIG.H" +#include "big.h" #include "DlgKeyAsymGeneration.h" #include "KeyFileHandling.h" diff --git a/CrypTool/SignatureAttack.cpp b/CrypTool/SignatureAttack.cpp index d83da1b2a..55f6b66d3 100644 --- a/CrypTool/SignatureAttack.cpp +++ b/CrypTool/SignatureAttack.cpp @@ -339,7 +339,7 @@ UINT SignatureAttack::Do_Floyd() } HashStore[jj] = 0; - fprintf(m_TestFile, "\nRun_No=%2.2d\nHashInit=%s\nCollSteps=%I64i\nConfSteps=%I64i", + fprintf(m_TestFile, "\nRun_No=%2.2d\nHashInit=%s\nCollSteps=%lld\nConfSteps=%lld", m_ResSigAtt->GetRuns(), HashStore, m_ResSigAtt->GetCollisionStepsOfRun(m_ResSigAtt->GetRuns() - 1), m_ResSigAtt->GetConfirmationStepsOfRun(m_ResSigAtt->GetRuns() - 1)); @@ -372,7 +372,7 @@ UINT SignatureAttack::Do_Floyd() if (m_OptSigAtt->GetTestMode()) { - fprintf(m_TestFile, "\nResult=%d\nTotalSteps=%I64i\nExpectedSteps=%I64i\nHashOps=%I64i\nElapsedTime=%.3f", + fprintf(m_TestFile, "\nResult=%d\nTotalSteps=%lld\nExpectedSteps=%lld\nHashOps=%lld\nElapsedTime=%.3f", m_ResSigAtt->GetFloydResult(), m_ResSigAtt->GetTotalSteps(), m_ResSigAtt->GetExpectedSteps(), m_ResSigAtt->GetHashOperationsPerformed(), m_ResSigAtt->GetEffectiveTime()); } diff --git a/CrypTool/SignatureAttack.h b/CrypTool/SignatureAttack.h index 06a138748..0f1d19991 100644 --- a/CrypTool/SignatureAttack.h +++ b/CrypTool/SignatureAttack.h @@ -34,7 +34,7 @@ #include "HashingOperations.h" #include "OptionsForSignatureAttack.h" #include "ResultsOfSignatureAttack.h" -#include "sys\timeb.h" +#include class SignatureAttack { diff --git a/CrypTool/SizingDialog.cpp b/CrypTool/SizingDialog.cpp index a2aa50d7b..806c15d98 100644 --- a/CrypTool/SizingDialog.cpp +++ b/CrypTool/SizingDialog.cpp @@ -35,7 +35,7 @@ #include "stdafx.h" #include "SizingDialog.h" -#include ".\SizingDialog.h" +#include "SizingDialog.h" #include "CrypToolTools.h" //////////////////////////////////////////////////////////////////////////// @@ -168,7 +168,7 @@ BOOL CCtrlInfo::ExtractOptions(LPCTSTR lpszSection, else { CString strErr; - strErr.Format(_T("'%s' is not predefined keyword"), strWord); + strErr.Format(_T("'%s' is not predefined keyword"), (LPCTSTR)strWord); MessageBox(NULL, strErr, _T("There is something wrong in the expression describing control position"), MB_OK | MB_ICONEXCLAMATION); return FALSE; diff --git a/CrypTool/Solitaire.cpp b/CrypTool/Solitaire.cpp index 727f1105d..d2c913840 100644 --- a/CrypTool/Solitaire.cpp +++ b/CrypTool/Solitaire.cpp @@ -419,7 +419,7 @@ long c_solitaire::crypt( solitaire_action encrypt, const char *f_in, const char { long error = 0; fstream fin, fout; - fin.open( f_in, ios::in || ios::binary ); + fin.open( f_in, ios::in ); // was "ios::in || ios::binary", which evaluates to ios::in if ( fin.is_open() ) { fout.open( f_out, ios::out ); diff --git a/CrypTool/Solitaire.h b/CrypTool/Solitaire.h index aefb2c370..05c89c2d0 100644 --- a/CrypTool/Solitaire.h +++ b/CrypTool/Solitaire.h @@ -41,7 +41,7 @@ class c_solitaire { unsigned char crypt_c( solitaire_action encrypt, unsigned char c ); long crypt( solitaire_action encrypt, const char *f_in, const char *f_out ); - friend long crypt_solitaire( solitaire_action encrypt, const char *f_in, const char *f_out, long cards, long ID, unsigned char *cardset, char *password = 0 ); + friend long crypt_solitaire( solitaire_action encrypt, const char *f_in, const char *f_out, long cards, long ID, unsigned char *cardset, char *password ); friend long crypt_solitaire( solitaire_action encrypt, const char *f_in, const char *f_out, CString &cardset ); public: @@ -63,6 +63,8 @@ class c_solitaire { void set_inner_state(long state) { inner_state = state; } }; +long crypt_solitaire( solitaire_action encrypt, const char *f_in, const char *f_out, long cards, long ID, unsigned char *cardset, char *password = 0 ); +long crypt_solitaire( solitaire_action encrypt, const char *f_in, const char *f_out, CString &cardset ); #if 1 class Deck diff --git a/CrypTool/StereotypedAttack.cpp b/CrypTool/StereotypedAttack.cpp index 515299e58..35f0d4ee3 100644 --- a/CrypTool/StereotypedAttack.cpp +++ b/CrypTool/StereotypedAttack.cpp @@ -248,7 +248,7 @@ bool StereotypedAttack::FindRoots(ZZX f, vec_ZZ& r){ } // Getters and setters -void StereotypedAttack::setN(ZZ& N){ +void StereotypedAttack::setN(const ZZ& N){ this->N=N; updateX(); } @@ -257,7 +257,7 @@ ZZ& StereotypedAttack::getN(){ return N; } -void StereotypedAttack::setE(ZZ& e){ +void StereotypedAttack::setE(const ZZ& e){ this->e=e; updateX(); } @@ -266,7 +266,7 @@ ZZ& StereotypedAttack::getE(){ return e; } -void StereotypedAttack::setH(ZZ& h){ +void StereotypedAttack::setH(const ZZ& h){ this->h=h; updateX(); } @@ -275,15 +275,15 @@ ZZ& StereotypedAttack::getH(){ return h; } -void StereotypedAttack::setLeftText(ZZ& leftText){ +void StereotypedAttack::setLeftText(const ZZ& leftText){ this->leftText=leftText; } -void StereotypedAttack::setRightText(ZZ& rightText){ +void StereotypedAttack::setRightText(const ZZ& rightText){ this->rightText=rightText; } -void StereotypedAttack::setCiphertext(ZZ& ciphertext){ +void StereotypedAttack::setCiphertext(const ZZ& ciphertext){ this->ciphertext=ciphertext; } diff --git a/CrypTool/StereotypedAttack.h b/CrypTool/StereotypedAttack.h index 643236195..d697f3e9d 100644 --- a/CrypTool/StereotypedAttack.h +++ b/CrypTool/StereotypedAttack.h @@ -42,13 +42,13 @@ class StereotypedAttack{ // StereotypedAttack(); // get/set-methods - void setN(ZZ&); - void setE(ZZ&); - void setLeftText(ZZ&); - void setRightText(ZZ&); + void setN(const ZZ&); + void setE(const ZZ&); + void setLeftText(const ZZ&); + void setRightText(const ZZ&); void setUnknownLength(int); - void setCiphertext(ZZ&); - void setH(ZZ&); + void setCiphertext(const ZZ&); + void setH(const ZZ&); ZZ& getBound(); ZZ& getSolution(); diff --git a/CrypTool/SymEncBase.cpp b/CrypTool/SymEncBase.cpp index ee4a28abf..45c0a4280 100644 --- a/CrypTool/SymEncBase.cpp +++ b/CrypTool/SymEncBase.cpp @@ -19,13 +19,12 @@ **************************************************************************/ #include "stdafx.h" #include "CrypToolApp.h" -#include ".\symencbase.h" +#include "SymEncBase.h" #include "SecudeCryptography.h" #include "CoreCryptography.h" #include "secure.h" // Include-File von SECUDE -inline int sym_encrypt(int crypt_id, cryptProvider provider, char *key_hex, int key_bitlength, char *in, int in_bytelength, @@ -44,7 +43,6 @@ int sym_encrypt(int crypt_id, cryptProvider provider, return -1; } -inline int sym_decrypt(int crypt_id, cryptProvider provider, char *key_hex, int key_bitlength, char *in, int in_bytelength, diff --git a/CrypTool/ZZXY.cpp b/CrypTool/ZZXY.cpp index 49170d99e..96ed0f22d 100644 --- a/CrypTool/ZZXY.cpp +++ b/CrypTool/ZZXY.cpp @@ -116,7 +116,7 @@ ZZXY ZZXY::operator *(ZZX &B) return retval; } -ZZXY ZZXY::operator *(ZZ &B) +ZZXY ZZXY::operator *(const ZZ &B) { ZZXY retval; retval.data.SetLength(1); diff --git a/CrypTool/ZZXY.h b/CrypTool/ZZXY.h index 6aae5994d..ec76e1e2e 100644 --- a/CrypTool/ZZXY.h +++ b/CrypTool/ZZXY.h @@ -48,7 +48,7 @@ class ZZXY{ const ZZXY operator-(ZZXY& B); ZZXY operator*(ZZX& B); const ZZXY operator*(ZZXY& B); - ZZXY operator *(ZZ &B); + ZZXY operator *(const ZZ &B); const ZZXY operator+(ZZXY& B); const ZZXY operator /(ZZ d); const ZZXY operator /(ZZX b); diff --git a/CrypTool/adfgvx.cpp b/CrypTool/adfgvx.cpp index 020f91eac..74500beed 100644 --- a/CrypTool/adfgvx.cpp +++ b/CrypTool/adfgvx.cpp @@ -28,7 +28,7 @@ using namespace std; // necessary to access the CrypTool alphabet #include "CrypToolApp.h" -#include "libanalyse\NGram.h" +#include "libanalyse/NGram.h" adfgvx::adfgvx () { codeMatrix[0][0] = 'A'; diff --git a/CrypTool/adfgvx.h b/CrypTool/adfgvx.h index 24502a8ab..1654a63ab 100644 --- a/CrypTool/adfgvx.h +++ b/CrypTool/adfgvx.h @@ -65,7 +65,7 @@ class adfgvx { char subChars[2]; pmlist permMatrix; pmlist::iterator permMatrixIterator; - int adfgvx::valueOf (char ch); + int valueOf (char ch); CString lastPasswordFound; char m_szFrequency[36]; int m_iHighestFrequency; @@ -73,7 +73,7 @@ class adfgvx { public: cblist countBigrammVector; - void adfgvx::countBigram(); + void countBigram(); float countMatrix[6][6]; adfgvx(); @@ -109,16 +109,16 @@ class adfgvx { //***** ANALYSIS FUNCTIONS *****// - CString adfgvx::nextPassword(int minlength, int maxlength, CString start); - bool adfgvx::goodenough(bool forcePassword); - void adfgvx::ForcePassword(CString pwd); - void adfgvx::SetFrequencyTable(char* szFrequency, int iHighestFrequency); + CString nextPassword(int minlength, int maxlength, CString start); + bool goodenough(bool forcePassword); + void ForcePassword(CString pwd); + void SetFrequencyTable(char* szFrequency, int iHighestFrequency); //***** INPUT VALIDATION *****// - int adfgvx::CheckPassword(int minLength, int maxLength, CString password); - CString adfgvx::CleansePassword(int errorCode, CString password); - CString adfgvx::LettersToNumbers(CString password); - int adfgvx::CheckStringBox(CString input); + int CheckPassword(int minLength, int maxLength, CString password); + CString CleansePassword(int errorCode, CString password); + CString LettersToNumbers(CString password); + int CheckStringBox(CString input); }; bool alphaSort (pmlistelem l1, pmlistelem l2); diff --git a/CrypTool/automated_permanalysis.cpp b/CrypTool/automated_permanalysis.cpp index 719f937e4..2b73ac398 100644 --- a/CrypTool/automated_permanalysis.cpp +++ b/CrypTool/automated_permanalysis.cpp @@ -293,6 +293,6 @@ int automated_permanalysis::iterate_key_param() for (it_plain = row_dir; it_plain <= col_dir; it_plain++) if (check(it_plain, rangePlain)) analyse(permSize, it_plain, it_perm, it_cipher); - return (int)(keyList); + return keyList != 0; } diff --git a/CrypTool/base64.h b/CrypTool/base64.h index 1494df673..a24338c3a 100644 --- a/CrypTool/base64.h +++ b/CrypTool/base64.h @@ -37,7 +37,9 @@ #ifndef _HLIB_Base64EncDec_H_ #define _HLIB_Base64EncDec_H_ 1 +#ifndef __GNUC__ #define __attribute__(x) +#endif // ERROR CODES #define B64_CODE_NOERROR 0 #define B64_DECODE_PREMATURE_END -1 @@ -54,7 +56,9 @@ extern "C" { #endif typedef unsigned int u_int32_t __attribute__((__mode__(__SI__))); +#ifdef _WIN32 typedef signed int ssize_t; +#endif /* ---ENCODE--- diff --git a/CrypTool/base64error.cpp b/CrypTool/base64error.cpp index 367e32f9e..937121d63 100644 --- a/CrypTool/base64error.cpp +++ b/CrypTool/base64error.cpp @@ -40,15 +40,15 @@ void base64error(std::string text, char errchar,ssize_t errcode, ssize_t positio AfxMessageBox(result, MB_OK); break; case -3: - result.Format(IDS_BASE64_DECODE_MISSING_CHARS, chlb,text); + result.Format(IDS_BASE64_DECODE_MISSING_CHARS, chlb,text.c_str()); AfxMessageBox(result, MB_OK); break; case -4: - result.Format(IDS_BASE64_FILE_WRITE_ERROR,text); + result.Format(IDS_BASE64_FILE_WRITE_ERROR,text.c_str()); AfxMessageBox(result, MB_OK); break; case -5: - result.Format(IDS_BASE64_FILE_OPEN_ERROR,text); + result.Format(IDS_BASE64_FILE_OPEN_ERROR,text.c_str()); AfxMessageBox(result, MB_OK); break; } diff --git a/CrypTool/keyHillBase.cpp b/CrypTool/keyHillBase.cpp index 5d7dd5dbf..17db89d66 100644 --- a/CrypTool/keyHillBase.cpp +++ b/CrypTool/keyHillBase.cpp @@ -326,7 +326,7 @@ int CKeyHillBase::isInvertable() { CString msg, cs; cs.Format( "%dx%d", dim, dim ); - msg.Format( IDS_HILL_BAD_KEY_INV, cs, modul); + msg.Format( IDS_HILL_BAD_KEY_INV, (LPCTSTR)cs, modul); cs.LoadStringA( IDS_HILL_BAD_KEY ); currentDialog->MessageBoxA(msg, cs, MB_ICONWARNING|MB_OK); } @@ -517,7 +517,7 @@ int CKeyHillBase::strToKey( CString &cs, CString *alphabet ) else theApp.TextOptions.setAlphabet( cs.Mid( laenge, l ) ); laenge = cs.Find( HILLSTR_ALPHABETOFFSET ) + strlen(HILLSTR_ALPHABETOFFSET) +1; - HillOptions.m_offset = unsigned long(cs.GetAt(laenge) - '0'); + HillOptions.m_offset = (unsigned long)(cs.GetAt(laenge) - '0'); laenge = cs.Find(HILLSTR_MULTVARIANT); ASSERT(laenge > 0); laenge += strlen(HILLSTR_MULTVARIANT) +1; @@ -596,10 +596,10 @@ void CKeyHillBase::writeRegistry() { if ( CT_OPEN_REGISTRY_SETTINGS( KEY_WRITE, IDS_REGISTRY_SETTINGS, "Hill" ) == ERROR_SUCCESS ) { - CT_WRITE_REGISTRY( unsigned long(matType), "EditKeyChrMatrix" ); + CT_WRITE_REGISTRY( (unsigned long)(matType), "EditKeyChrMatrix" ); CT_WRITE_REGISTRY( dim, "MatrixDimension" ); - CT_WRITE_REGISTRY( unsigned long(verbose), "ShowExample" ); - CT_WRITE_REGISTRY( unsigned long(multType), "MultType" ); + CT_WRITE_REGISTRY( (unsigned long)(verbose), "ShowExample" ); + CT_WRITE_REGISTRY( (unsigned long)(multType), "MultType" ); CT_CLOSE_REGISTRY(); } HillOptions.writeRegistry(); diff --git a/CrypTool/passwordchecker.cpp b/CrypTool/passwordchecker.cpp index 8f7ca9ce0..272e54c52 100644 --- a/CrypTool/passwordchecker.cpp +++ b/CrypTool/passwordchecker.cpp @@ -777,7 +777,7 @@ char *checkPassword(char *password, char *path, int hidePassword, double *determ CString reconstructionDictionaryWords; // flomar, 01/24/2012: add integral separators (i.e. '1999' -> '1.999') CString stringDictSize = createStringNumberWithDigitGrouping(dict_size); - reconstructionDictionaryWords.Format(IDS_PQM_PASSWORD_RECONSTRUCTION_DICTIONARYWORDS, stringDictSize); + reconstructionDictionaryWords.Format(IDS_PQM_PASSWORD_RECONSTRUCTION_DICTIONARYWORDS, (LPCTSTR)stringDictSize); strcat(str_fnds, (LPCTSTR)(reconstructionDictionaryWords)); get_pwd_substrings( pwd_len, closure_matrix, DICT_WORDS, password, hidePassword, str_fnds, word_list, word_listSize); diff --git a/CrypTool/rsastereotypedmsgdlg.cpp b/CrypTool/rsastereotypedmsgdlg.cpp index bd5cc290b..45ac43a6e 100644 --- a/CrypTool/rsastereotypedmsgdlg.cpp +++ b/CrypTool/rsastereotypedmsgdlg.cpp @@ -23,7 +23,7 @@ #include "stdafx.h" #include "CrypToolApp.h" -#include "RSAStereotypedMSGDlg.h" +#include "rsastereotypedmsgdlg.h" #include "NTLExpPars.h" #include "FileTools.h" #ifdef _DEBUG @@ -74,31 +74,31 @@ BEGIN_MESSAGE_MAP(CRSAStereotypedMSGDlg, CDialog) //{{AFX_MSG_MAP(CRSAStereotypedMSGDlg) ON_WM_PAINT() ON_WM_QUERYDRAGICON() - ON_EN_CHANGE(IDC_EDITPLAIN, OnChangeEditplain) - ON_EN_CHANGE(IDC_EDITLENGTH, OnChangeEditlength) - ON_EN_CHANGE(IDC_EDITPOS, OnChangeEditpos) - ON_EN_CHANGE(IDC_EDITBITSOFN, OnChangeEditbitsofn) - ON_EN_CHANGE(IDC_EDITN, OnChangeEditn) - ON_EN_CHANGE(IDC_EDITE, OnChangeEdite) - ON_BN_CLICKED(IDC_BUTTONENCRYPT, OnButtonencrypt) - ON_BN_CLICKED(IDC_RADIONUMBER, OnRadionumber) - ON_BN_CLICKED(IDC_RADIOHEX, OnRadiohex) - ON_EN_KILLFOCUS(IDC_EDITCIPHER, OnKillfocusEditcipher) - ON_EN_CHANGE(IDC_EDITH, OnChangeEdith) - ON_EN_UPDATE(IDC_EDITCIPHER, OnUpdateEditcipher) - ON_BN_CLICKED(IDC_BUTTONSTART, OnButtonstart) + ON_EN_CHANGE(IDC_EDITPLAIN, &CRSAStereotypedMSGDlg::OnChangeEditplain) + ON_EN_CHANGE(IDC_EDITLENGTH, &CRSAStereotypedMSGDlg::OnChangeEditlength) + ON_EN_CHANGE(IDC_EDITPOS, &CRSAStereotypedMSGDlg::OnChangeEditpos) + ON_EN_CHANGE(IDC_EDITBITSOFN, &CRSAStereotypedMSGDlg::OnChangeEditbitsofn) + ON_EN_CHANGE(IDC_EDITN, &CRSAStereotypedMSGDlg::OnChangeEditn) + ON_EN_CHANGE(IDC_EDITE, &CRSAStereotypedMSGDlg::OnChangeEdite) + ON_BN_CLICKED(IDC_BUTTONENCRYPT, &CRSAStereotypedMSGDlg::OnButtonencrypt) + ON_BN_CLICKED(IDC_RADIONUMBER, &CRSAStereotypedMSGDlg::OnRadionumber) + ON_BN_CLICKED(IDC_RADIOHEX, &CRSAStereotypedMSGDlg::OnRadiohex) + ON_EN_KILLFOCUS(IDC_EDITCIPHER, &CRSAStereotypedMSGDlg::OnKillfocusEditcipher) + ON_EN_CHANGE(IDC_EDITH, &CRSAStereotypedMSGDlg::OnChangeEdith) + ON_EN_UPDATE(IDC_EDITCIPHER, &CRSAStereotypedMSGDlg::OnUpdateEditcipher) + ON_BN_CLICKED(IDC_BUTTONSTART, &CRSAStereotypedMSGDlg::OnButtonstart) ON_WM_TIMER() - ON_BN_CLICKED(IDC_BUTTONCANCELATTACK, OnButtoncancelattack) - ON_BN_CLICKED(IDC_RANDOM, OnRandom) + ON_BN_CLICKED(IDC_BUTTONCANCELATTACK, &CRSAStereotypedMSGDlg::OnButtoncancelattack) + ON_BN_CLICKED(IDC_RANDOM, &CRSAStereotypedMSGDlg::OnRandom) ON_WM_SETCURSOR() ON_WM_CLOSE() - ON_BN_CLICKED(IDC_BUTTONLOG, OnButtonlog) - ON_BN_CLICKED(IDC_RADIOCHOICE, OnRadiochoice) - ON_BN_CLICKED(IDC_BUTTONDELETE, OnButtondelete) - ON_EN_CHANGE(IDC_EDITPLAINFULL, OnChangeEditplainfull) - ON_EN_KILLFOCUS(IDC_EDITE, OnKillfocusEdite) - ON_BN_CLICKED(IDC_RADIOCHOICE2, OnRadiochoice) - ON_EN_KILLFOCUS(IDC_EDITN, OnKillfocusEditn) + ON_BN_CLICKED(IDC_BUTTONLOG, &CRSAStereotypedMSGDlg::OnButtonlog) + ON_BN_CLICKED(IDC_RADIOCHOICE, &CRSAStereotypedMSGDlg::OnRadiochoice) + ON_BN_CLICKED(IDC_BUTTONDELETE, &CRSAStereotypedMSGDlg::OnButtondelete) + ON_EN_CHANGE(IDC_EDITPLAINFULL, &CRSAStereotypedMSGDlg::OnChangeEditplainfull) + ON_EN_KILLFOCUS(IDC_EDITE, &CRSAStereotypedMSGDlg::OnKillfocusEdite) + ON_BN_CLICKED(IDC_RADIOCHOICE2, &CRSAStereotypedMSGDlg::OnRadiochoice) + ON_EN_KILLFOCUS(IDC_EDITN, &CRSAStereotypedMSGDlg::OnKillfocusEditn) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -798,7 +798,7 @@ void CRSAStereotypedMSGDlg::OnChangeEditplainfull() MaxChars = to_ZZ(floor(log(N+255)/log(256.0))); else MaxChars = 0; - chars.Format("%d (%s)",tmp.GetLength(),toString(MaxChars,10,0)); + chars.Format("%d (%s)",tmp.GetLength(),(LPCTSTR)toString(MaxChars,10,0)); SetDlgItemText(IDC_EDITPLAINLENGTH,chars); SetDlgItemText(IDC_EDITCIPHER,""); UpdateSliders(); diff --git a/CrypTool/stdafx.h b/CrypTool/stdafx.h index 237500bc4..c4b01e956 100644 --- a/CrypTool/stdafx.h +++ b/CrypTool/stdafx.h @@ -75,8 +75,8 @@ #undef min #undef max -#include "libanalyse\la_string.h" -#include "libanalyse\analyse.h" +#include "libanalyse/la_string.h" +#include "libanalyse/analyse.h" #include diff --git a/CrypTool/uucode.h b/CrypTool/uucode.h index 17dac1789..aa3eed00d 100644 --- a/CrypTool/uucode.h +++ b/CrypTool/uucode.h @@ -37,7 +37,9 @@ #ifndef _HLIB_UUEncDec_H_ #define _HLIB_UUEncDec_H_ 1 +#ifndef __GNUC__ #define __attribute__(x) +#endif // ERROR CODES #define UU_CODE_NOERROR 0 #define UU_DECODE_MISSING_BEGIN -1 @@ -59,7 +61,9 @@ extern "C" { #endif typedef unsigned int u_int32_t __attribute__((__mode__(__SI__))); +#ifdef _WIN32 typedef signed int ssize_t; +#endif /* ---ENCODE--- diff --git a/CrypTool/uucodeerror.cpp b/CrypTool/uucodeerror.cpp index 3c99ad9de..b6cfd3c2b 100644 --- a/CrypTool/uucodeerror.cpp +++ b/CrypTool/uucodeerror.cpp @@ -41,11 +41,11 @@ void uucodeerror(std::string text, char errchar,ssize_t errcode, ssize_t positio AfxMessageBox(result, MB_OK); break; case -3: - result.Format(IDS_UU_DECODE_MISSING_CHAR, chlb,text); + result.Format(IDS_UU_DECODE_MISSING_CHAR, chlb,text.c_str()); AfxMessageBox(result, MB_OK); break; case -4: - result.Format(IDS_UU_FILE_WRITE_ERROR,text); + result.Format(IDS_UU_FILE_WRITE_ERROR,text.c_str()); AfxMessageBox(result, MB_OK); break; case -5: diff --git a/CrypTool/zip/zunzip.h b/CrypTool/zip/zunzip.h index 2ca975ad0..64635d1b2 100644 --- a/CrypTool/zip/zunzip.h +++ b/CrypTool/zip/zunzip.h @@ -221,7 +221,12 @@ extern "C" { typedef long longint; typedef unsigned short UWORD; #ifndef OS2 +#ifdef _WIN32 typedef unsigned long ULONG; +#else +#include +typedef uint32_t ULONG; /* 32 bits as on Windows (and as mfcwx defines it) */ +#endif #endif /*************************/ diff --git a/NumberShark/ColoredListCtrl.cpp b/NumberShark/ColoredListCtrl.cpp index 3f69c2709..4229153c5 100644 --- a/NumberShark/ColoredListCtrl.cpp +++ b/NumberShark/ColoredListCtrl.cpp @@ -50,7 +50,7 @@ CColoredListCtrl::~CColoredListCtrl() BEGIN_MESSAGE_MAP(CColoredListCtrl, CListCtrl) //{{AFX_MSG_MAP(CColoredListCtrl) ON_WM_ERASEBKGND() - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CColoredListCtrl::OnCustomDraw) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/NumberShark/DlgShowPrecalculatedScores.cpp b/NumberShark/DlgShowPrecalculatedScores.cpp index 92f243c3d..6f0f6a07d 100644 --- a/NumberShark/DlgShowPrecalculatedScores.cpp +++ b/NumberShark/DlgShowPrecalculatedScores.cpp @@ -109,7 +109,7 @@ BOOL CDlgShowPrecalculatedScores::OnInitDialog() } BEGIN_MESSAGE_MAP(CDlgShowPrecalculatedScores, CDialog) - ON_BN_CLICKED(ID_SHOW_DETAILS, OnBnClickedShowSequence) + ON_BN_CLICKED(ID_SHOW_DETAILS, &CDlgShowPrecalculatedScores::OnBnClickedShowSequence) END_MESSAGE_MAP() diff --git a/NumberShark/GameRules.cpp b/NumberShark/GameRules.cpp index 536556066..9fe9b188d 100644 --- a/NumberShark/GameRules.cpp +++ b/NumberShark/GameRules.cpp @@ -47,7 +47,7 @@ void GameRules::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(GameRules, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDOK, &GameRules::OnBnClickedOk) ON_WM_ACTIVATE() END_MESSAGE_MAP() diff --git a/NumberShark/GameSummary.cpp b/NumberShark/GameSummary.cpp index 34dd15a13..7d0ef5fe1 100644 --- a/NumberShark/GameSummary.cpp +++ b/NumberShark/GameSummary.cpp @@ -50,10 +50,10 @@ void CGameSummary::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CGameSummary, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDOK, &CGameSummary::OnBnClickedOk) ON_WM_ACTIVATE() - ON_BN_CLICKED(IDC_RADIO1, OnBnClickedRadio1) - ON_BN_CLICKED(IDC_RADIO2, OnBnClickedRadio2) + ON_BN_CLICKED(IDC_RADIO1, &CGameSummary::OnBnClickedRadio1) + ON_BN_CLICKED(IDC_RADIO2, &CGameSummary::OnBnClickedRadio2) END_MESSAGE_MAP() diff --git a/NumberShark/MFC-ZahlenHaiDlg.cpp b/NumberShark/MFC-ZahlenHaiDlg.cpp index 143db0d5f..5a835e799 100644 --- a/NumberShark/MFC-ZahlenHaiDlg.cpp +++ b/NumberShark/MFC-ZahlenHaiDlg.cpp @@ -188,26 +188,26 @@ BEGIN_MESSAGE_MAP(CMFCZahlenHaiDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP - ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON01, IDC_BUTTON30, OnBnClickedButton) - - ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) - - ON_BN_CLICKED(IDC_BUTTON_OK, OnBnClickedButtonOk) - ON_BN_CLICKED(ID_BUTTON_END, OnBnClickedButtonEnd) - ON_BN_CLICKED(IDC_BUTTON_STARTNEW, OnBnClickedButtonStartnew) - ON_BN_CLICKED(ID_BUTTON_RULES, OnBnClickedButtonRules) - ON_BN_CLICKED(IDC_BUTTON_REST, OnBnClickedButtonRest) - ON_BN_CLICKED(IDC_BUTTON_OPTION, OnBnClickedButtonOption) - ON_BN_CLICKED(IDC_BUTTON_HELP, OnBnClickedButtonHelp) - ON_BN_CLICKED(IDC_BUTTON_FINISH, OnBnClickedButtonFinish) - ON_BN_CLICKED(IDC_BUTTON_UNDO, OnBnClickedButtonUndo) - ON_BN_CLICKED(IDC_BUTTON_REDO, OnBnClickedButtonRedo) - ON_BN_CLICKED(IDC_BUTTON_SWITCH_STYLE, OnBnClickedButtonSwitchStyle) + ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON01, IDC_BUTTON30, &CMFCZahlenHaiDlg::OnBnClickedButton) + + ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CMFCZahlenHaiDlg::OnTcnSelchangeTab1) + + ON_BN_CLICKED(IDC_BUTTON_OK, &CMFCZahlenHaiDlg::OnBnClickedButtonOk) + ON_BN_CLICKED(ID_BUTTON_END, &CMFCZahlenHaiDlg::OnBnClickedButtonEnd) + ON_BN_CLICKED(IDC_BUTTON_STARTNEW, &CMFCZahlenHaiDlg::OnBnClickedButtonStartnew) + ON_BN_CLICKED(ID_BUTTON_RULES, &CMFCZahlenHaiDlg::OnBnClickedButtonRules) + ON_BN_CLICKED(IDC_BUTTON_REST, &CMFCZahlenHaiDlg::OnBnClickedButtonRest) + ON_BN_CLICKED(IDC_BUTTON_OPTION, &CMFCZahlenHaiDlg::OnBnClickedButtonOption) + ON_BN_CLICKED(IDC_BUTTON_HELP, &CMFCZahlenHaiDlg::OnBnClickedButtonHelp) + ON_BN_CLICKED(IDC_BUTTON_FINISH, &CMFCZahlenHaiDlg::OnBnClickedButtonFinish) + ON_BN_CLICKED(IDC_BUTTON_UNDO, &CMFCZahlenHaiDlg::OnBnClickedButtonUndo) + ON_BN_CLICKED(IDC_BUTTON_REDO, &CMFCZahlenHaiDlg::OnBnClickedButtonRedo) + ON_BN_CLICKED(IDC_BUTTON_SWITCH_STYLE, &CMFCZahlenHaiDlg::OnBnClickedButtonSwitchStyle) ON_WM_TIMER() ON_WM_SETCURSOR() - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, OnLvnColumnclickList2) - ON_BN_CLICKED(IDC_BUTTON_LOAD, OnBnClickedButtonLoad) - ON_BN_CLICKED(IDC_BUTTON_SAVE, OnBnClickedButtonSave) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, &CMFCZahlenHaiDlg::OnLvnColumnclickList2) + ON_BN_CLICKED(IDC_BUTTON_LOAD, &CMFCZahlenHaiDlg::OnBnClickedButtonLoad) + ON_BN_CLICKED(IDC_BUTTON_SAVE, &CMFCZahlenHaiDlg::OnBnClickedButtonSave) END_MESSAGE_MAP() // CMFCZahlenHaiDlg Meldungshandler diff --git a/NumberShark/ZahlenHaiOptionen.cpp b/NumberShark/ZahlenHaiOptionen.cpp index 54bb44eef..53568e60c 100644 --- a/NumberShark/ZahlenHaiOptionen.cpp +++ b/NumberShark/ZahlenHaiOptionen.cpp @@ -86,16 +86,16 @@ void ZahlenHaiOptionen::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(ZahlenHaiOptionen, CDialog) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_BN_CLICKED(IDC_CHECK1, OnBnClickedCheck1) - ON_BN_CLICKED(IDC_CHECK2, OnBnClickedCheck2) - ON_BN_CLICKED(IDC_CHECK3, OnBnClickedCheck3) + ON_BN_CLICKED(IDOK, &ZahlenHaiOptionen::OnBnClickedOk) + ON_BN_CLICKED(IDC_CHECK1, &ZahlenHaiOptionen::OnBnClickedCheck1) + ON_BN_CLICKED(IDC_CHECK2, &ZahlenHaiOptionen::OnBnClickedCheck2) + ON_BN_CLICKED(IDC_CHECK3, &ZahlenHaiOptionen::OnBnClickedCheck3) - ON_BN_CLICKED(IDC_BUTTON_MAX, OnBnClickedButtonMax) + ON_BN_CLICKED(IDC_BUTTON_MAX, &ZahlenHaiOptionen::OnBnClickedButtonMax) ON_WM_ACTIVATE() - ON_BN_CLICKED(IDC_RADIO_MAX1, OnBnClickedRadioMax1) - ON_BN_CLICKED(IDC_RADIO_MAX2, OnBnClickedRadioMax2) - ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) + ON_BN_CLICKED(IDC_RADIO_MAX1, &ZahlenHaiOptionen::OnBnClickedRadioMax1) + ON_BN_CLICKED(IDC_RADIO_MAX2, &ZahlenHaiOptionen::OnBnClickedRadioMax2) + ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &ZahlenHaiOptionen::OnTcnSelchangeTab1) END_MESSAGE_MAP() diff --git a/NumberShark/propPage1.cpp b/NumberShark/propPage1.cpp index c6d35d847..f636eea87 100644 --- a/NumberShark/propPage1.cpp +++ b/NumberShark/propPage1.cpp @@ -48,7 +48,7 @@ void propPage1::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(propPage1, CPropertyPage) - ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) + ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &propPage1::OnTcnSelchangeTab1) END_MESSAGE_MAP() diff --git a/README.md b/README.md index 46f78eb6c..9373d1702 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # CrypTool 1 + +![macOS/Linux port](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/wroclaw-tech/cryptool1/port-status/badge.json) — see [STATUS.md](https://github.com/wroclaw-tech/cryptool1/blob/port-status/STATUS.md) [CrypTool 1](https://www.cryptool.org/ct1/) (CT1) is a free Windows program for cryptography and cryptanalysis. It is part of the [CrypTool Project](https://www.cryptool.org/). diff --git a/aes/RC6/rc6.c b/aes/RC6/rc6.c index b5d5c05b3..b16f9d3cc 100644 --- a/aes/RC6/rc6.c +++ b/aes/RC6/rc6.c @@ -32,10 +32,10 @@ * shifts: when shifting a [32-bit] dword, the shift count is treated as * a number modulo 32. */ #define ROTL(x,count) \ - (((x) >> (thirtytwo-(count))) | ((x) << (count))) + (((x) >> ((thirtytwo-(count)) & 31)) | ((x) << ((count) & 31))) #define ROTR(x,count) \ - (((x) << (thirtytwo-(count))) | ((x) >> (count))) + (((x) << ((thirtytwo-(count)) & 31)) | ((x) >> ((count) & 31))) diff --git a/aestool/HexEdit1.cpp b/aestool/HexEdit1.cpp index 9662f1d9b..915593f4e 100644 --- a/aestool/HexEdit1.cpp +++ b/aestool/HexEdit1.cpp @@ -56,8 +56,8 @@ BEGIN_MESSAGE_MAP(CHexEdit, CEdit) //{{AFX_MSG_MAP(CHexEdit) ON_WM_CHAR() ON_WM_KEYDOWN() - ON_MESSAGE(WM_PASTE, OnPaste) - ON_CONTROL_REFLECT_EX(EN_UPDATE, OnUpdate) + ON_MESSAGE(WM_PASTE, &CHexEdit::OnPaste) + ON_CONTROL_REFLECT_EX(EN_UPDATE, &CHexEdit::OnUpdate) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/aestool/aestoolDlg.cpp b/aestool/aestoolDlg.cpp index 10a4103aa..db82699eb 100644 --- a/aestool/aestoolDlg.cpp +++ b/aestool/aestoolDlg.cpp @@ -151,17 +151,17 @@ BEGIN_MESSAGE_MAP(CAestoolDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() - ON_BN_CLICKED(IDC_BUTTON_SRC, OnSucheSrc) - ON_BN_CLICKED(IDC_BUTTON3, OnHelp) - ON_EN_CHANGE(IDC_EDIT_KEY_HEX, updateEncryptDecryptButtons) - ON_EN_CHANGE(IDC_EDIT_KEY_ASCII, updateEncryptDecryptButtons) - ON_EN_CHANGE(IDC_EDIT_SRC, OnChangeSrc) - ON_BN_CLICKED(IDC_CHECK_SHOW_PASSWORD, OnCheckShowPassword) - ON_BN_CLICKED(IDC_CHECK_ENTER_PASSWORD_AS_HEX, OnCheckEnterPasswordAsHex) - ON_BN_CLICKED(IDC_RADIO_EXE, OnRadioFormat) - ON_BN_CLICKED(IDC_RADIO_AES, OnRadioFormat) - ON_BN_CLICKED(IDC_BUTTON_ENCRYPT, OnOK) - ON_BN_CLICKED(IDC_BUTTON_DECRYPT, OnOK) + ON_BN_CLICKED(IDC_BUTTON_SRC, &CAestoolDlg::OnSucheSrc) + ON_BN_CLICKED(IDC_BUTTON3, &CAestoolDlg::OnHelp) + ON_EN_CHANGE(IDC_EDIT_KEY_HEX, &CAestoolDlg::updateEncryptDecryptButtons) + ON_EN_CHANGE(IDC_EDIT_KEY_ASCII, &CAestoolDlg::updateEncryptDecryptButtons) + ON_EN_CHANGE(IDC_EDIT_SRC, &CAestoolDlg::OnChangeSrc) + ON_BN_CLICKED(IDC_CHECK_SHOW_PASSWORD, &CAestoolDlg::OnCheckShowPassword) + ON_BN_CLICKED(IDC_CHECK_ENTER_PASSWORD_AS_HEX, &CAestoolDlg::OnCheckEnterPasswordAsHex) + ON_BN_CLICKED(IDC_RADIO_EXE, &CAestoolDlg::OnRadioFormat) + ON_BN_CLICKED(IDC_RADIO_AES, &CAestoolDlg::OnRadioFormat) + ON_BN_CLICKED(IDC_BUTTON_ENCRYPT, &CAestoolDlg::OnOK) + ON_BN_CLICKED(IDC_BUTTON_DECRYPT, &CAestoolDlg::OnOK) //}}AFX_MSG_MAP END_MESSAGE_MAP() diff --git a/cracklib-2.7/cracklib_Win32/fascist.c b/cracklib-2.7/cracklib_Win32/fascist.c index 0e326b12f..7b9609022 100644 --- a/cracklib-2.7/cracklib_Win32/fascist.c +++ b/cracklib-2.7/cracklib_Win32/fascist.c @@ -15,6 +15,7 @@ static char vers_id[] = "fascist.c : v2.3p3 Alec Muffett 14 dec 1997"; #include "pwd.h" #else #include +#include #endif #define ISSKIP(x) (isspace(x) || ispunct(x)) diff --git a/cracklib-2.7/cracklib_Win32/packer.h b/cracklib-2.7/cracklib_Win32/packer.h index e7df9e949..c465810dd 100644 --- a/cracklib-2.7/cracklib_Win32/packer.h +++ b/cracklib-2.7/cracklib_Win32/packer.h @@ -10,6 +10,8 @@ #include #include +#include +#include #ifdef _WIN32 #define CRACKLIB_WIN32_API __declspec(dllexport) @@ -59,17 +61,17 @@ typedef struct #define PW_WORDS(x) ((x)->header.pih_numwords) #define PIH_MAGIC 0x70775631 -extern CRACKLIB_WIN32_API PWDICT *PWOpen(); -extern CRACKLIB_WIN32_API char *Mangle(); -extern CRACKLIB_WIN32_API char *FascistCheck(); -extern CRACKLIB_WIN32_API char * FascistLook(pwp, instring); -extern CRACKLIB_WIN32_API char * Trim(string); -extern CRACKLIB_WIN32_API int PMatch(control, string); -extern CRACKLIB_WIN32_API int32 FindPW(pwp, string); -extern CRACKLIB_WIN32_API int PWClose(pwp); -extern CRACKLIB_WIN32_API int PutPW(pwp, string); -extern CRACKLIB_WIN32_API char * GetPW(pwp, number); -extern CRACKLIB_WIN32_API char Chop(string); +extern CRACKLIB_WIN32_API PWDICT *PWOpen(char *prefix, char *mode); +extern CRACKLIB_WIN32_API char *Mangle(char *input, char *control); +extern CRACKLIB_WIN32_API char *FascistCheck(char *password, char *path); +extern CRACKLIB_WIN32_API char * FascistLook(PWDICT *pwp, char *instring); +extern CRACKLIB_WIN32_API char * Trim(char *string); +extern CRACKLIB_WIN32_API int PMatch(char *control, char *string); +extern CRACKLIB_WIN32_API int32 FindPW(PWDICT *pwp, char *string); +extern CRACKLIB_WIN32_API int PWClose(PWDICT *pwp); +extern CRACKLIB_WIN32_API int PutPW(PWDICT *pwp, char *string); +extern CRACKLIB_WIN32_API char * GetPW(PWDICT *pwp, int32 number); +extern CRACKLIB_WIN32_API char Chop(char *string); #define CRACK_TOLOWER(a) (isupper(a)?tolower(a):(a)) #define CRACK_TOUPPER(a) (islower(a)?toupper(a):(a)) diff --git a/cracklib-2.7/cracklib_Win32/packlib.c b/cracklib-2.7/cracklib_Win32/packlib.c index 038a05b38..af98caee5 100644 --- a/cracklib-2.7/cracklib_Win32/packlib.c +++ b/cracklib-2.7/cracklib_Win32/packlib.c @@ -10,6 +10,68 @@ static char vers_id[] = "packlib.c : v2.3p2 Alec Muffett 18 May 1993"; +/* On-disk fields are 32-bit little-endian regardless of sizeof(int32). */ +#define PI_HEADER_DISK_SIZE 12 + +static int32 GetU32(const unsigned char *b) +{ + return (int32) b[0] | ((int32) b[1] << 8) | ((int32) b[2] << 16) | ((int32) b[3] << 24); +} + +static void PutU32(unsigned char *b, int32 v) +{ + b[0] = (unsigned char) (v & 0xff); + b[1] = (unsigned char) ((v >> 8) & 0xff); + b[2] = (unsigned char) ((v >> 16) & 0xff); + b[3] = (unsigned char) ((v >> 24) & 0xff); +} + +static size_t ReadU32(FILE *fp, int32 *out, size_t n) +{ + unsigned char b[4]; + size_t i; + for (i = 0; i < n && fread(b, 1, 4, fp) == 4; i++) + out[i] = GetU32(b); + return i; +} + +static size_t WriteU32(FILE *fp, const int32 *in, size_t n) +{ + unsigned char b[4]; + size_t i; + for (i = 0; i < n; i++) + { + PutU32(b, in[i]); + if (fwrite(b, 1, 4, fp) != 4) + break; + } + return i; +} + +static int ReadHeader(FILE *fp, struct pi_header *h) +{ + unsigned char b[PI_HEADER_DISK_SIZE]; + if (fread(b, 1, sizeof(b), fp) != sizeof(b)) + return 0; + h->pih_magic = GetU32(b); + h->pih_numwords = GetU32(b + 4); + h->pih_blocklen = (int16) (b[8] | (b[9] << 8)); + h->pih_pad = (int16) (b[10] | (b[11] << 8)); + return 1; +} + +static int WriteHeader(FILE *fp, const struct pi_header *h) +{ + unsigned char b[PI_HEADER_DISK_SIZE]; + PutU32(b, h->pih_magic); + PutU32(b + 4, h->pih_numwords); + b[8] = (unsigned char) (h->pih_blocklen & 0xff); + b[9] = (unsigned char) ((h->pih_blocklen >> 8) & 0xff); + b[10] = (unsigned char) (h->pih_pad & 0xff); + b[11] = (unsigned char) ((h->pih_pad >> 8) & 0xff); + return fwrite(b, 1, sizeof(b), fp) == sizeof(b); +} + PWDICT * PWOpen(prefix, mode) char *prefix; @@ -64,12 +126,12 @@ PWOpen(prefix, mode) pdesc.header.pih_blocklen = NUMWORDS; pdesc.header.pih_numwords = 0; - fwrite((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp); + WriteHeader(ifp, &pdesc.header); } else { pdesc.flags &= ~PFOR_WRITE; - if (!fread((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp)) + if (!ReadHeader(ifp, &pdesc.header)) { fprintf(stderr, "%s: error reading header\n", prefix); @@ -101,7 +163,7 @@ PWOpen(prefix, mode) if (pdesc.flags & PFOR_USEHWMS) { - if (fread(pdesc.hwms, 1, sizeof(pdesc.hwms), wfp) != sizeof(pdesc.hwms)) + if (ReadU32(wfp, pdesc.hwms, 256) != 256) { pdesc.flags &= ~PFOR_USEHWMS; } @@ -132,7 +194,7 @@ PWClose(pwp) return (-1); } - if (!fwrite((char *) &pwp->header, sizeof(pwp->header), 1, pwp->ifp)) + if (!WriteHeader(pwp->ifp, &pwp->header)) { fprintf(stderr, "index magic fwrite failed\n"); return (-1); @@ -151,7 +213,7 @@ PWClose(pwp) printf("hwm[%02x] = %d\n", i, pwp->hwms[i]); #endif } - fwrite(pwp->hwms, 1, sizeof(pwp->hwms), pwp->wfp); + WriteU32(pwp->wfp, pwp->hwms, 256); } } @@ -159,7 +221,8 @@ PWClose(pwp) fclose(pwp->dfp); // TEST - fclose(pwp->wfp); + if (pwp->wfp) + fclose(pwp->wfp); pwp->header.pih_magic = 0; @@ -199,7 +262,7 @@ PutPW(pwp, string) datum = (int32) ftell(pwp->dfp); - fwrite((char *) &datum, sizeof(datum), 1, pwp->ifp); + WriteU32(pwp->ifp, &datum, 1); fputs(pwp->data[0], pwp->dfp); putc(0, pwp->dfp); @@ -250,13 +313,13 @@ GetPW(pwp, number) { return (data[number % NUMWORDS]); } - if (fseek(pwp->ifp, sizeof(struct pi_header) + (thisblock * sizeof(int32)), 0)) + if (fseek(pwp->ifp, (long) (PI_HEADER_DISK_SIZE + thisblock * 4), 0)) { perror("(index fseek failed)"); return ((char *) 0); } - if (!fread((char *) &datum, sizeof(datum), 1, pwp->ifp)) + if (!ReadU32(pwp->ifp, &datum, 1)) { perror("(index fread failed)"); if(ferror(pwp->ifp)) diff --git a/cracklib-2.7/cracklib_Win32/rules.c b/cracklib-2.7/cracklib_Win32/rules.c index 05d46abda..77373ed97 100644 --- a/cracklib-2.7/cracklib_Win32/rules.c +++ b/cracklib-2.7/cracklib_Win32/rules.c @@ -15,13 +15,15 @@ static char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993"; #else #include "packer.h" +#include static void -Debug(val, a, b, c, d, e, f, g) - int val; - char *a, *b, *c, *d, *e, *f, *g; +Debug(int val, char *a, ...) { - fprintf(stderr, a, b, c, d, e, f); + va_list ap; + va_start(ap, a); + vfprintf(stderr, a, ap); + va_end(ap); } #endif diff --git a/libNTL/include/NTL/mach_desc.h b/libNTL/include/NTL/mach_desc.h index 8957c5719..638767cef 100644 --- a/libNTL/include/NTL/mach_desc.h +++ b/libNTL/include/NTL/mach_desc.h @@ -1,6 +1,9 @@ #ifndef NTL_mach_desc__H #define NTL_mach_desc__H +#if defined(__SIZEOF_LONG__) && (__SIZEOF_LONG__ != 4) +#error "This mach_desc.h assumes 32-bit long; put the generated NTL/mach_desc.h (port/thirdparty, target cryptool_ntl) first in the include path" +#endif #define NTL_BITS_PER_LONG (32) #define NTL_MAX_LONG (2147483647L) diff --git a/libVolRen/ArcBall.cpp b/libVolRen/ArcBall.cpp index 81acc2c9f..08914bc8f 100644 --- a/libVolRen/ArcBall.cpp +++ b/libVolRen/ArcBall.cpp @@ -36,13 +36,13 @@ CArcBall::~CArcBall() } -void CArcBall::place(CPosition &vec2Center, double dRadius) +void CArcBall::place(const CPosition &vec2Center, double dRadius) { m_vec2Center = vec2Center; m_dRadius = dRadius; } -void CArcBall::setMouse(CPosition &vec2Now) +void CArcBall::setMouse(const CPosition &vec2Now) { m_vec2Now = vec2Now; } diff --git a/libVolRen/ArcBall.h b/libVolRen/ArcBall.h index 6c49c43d4..2fbdedcf3 100644 --- a/libVolRen/ArcBall.h +++ b/libVolRen/ArcBall.h @@ -22,8 +22,8 @@ class CArcBall virtual ~CArcBall(); /* Public routines */ - void place(CPosition &vecPos, double dRadius); - void setMouse(CPosition &vecNow); + void place(const CPosition &vecPos, double dRadius); + void setMouse(const CPosition &vecNow); void startDragging(); void finishDragging(); CMatrix getRotatonMatrix(); diff --git a/libVolRen/EditorDialog.cpp b/libVolRen/EditorDialog.cpp index 05ceb6259..d8f90cbd4 100644 --- a/libVolRen/EditorDialog.cpp +++ b/libVolRen/EditorDialog.cpp @@ -1,7 +1,7 @@ // EditorDialog.cpp : implementation file // -#include "stdafx.h" +#include "StdAfx.h" #include "resource.h" #include "EditorDialog.h" #include "VolumeRenderer.h" @@ -53,11 +53,13 @@ void CEditorDialog::Create() CDialog::ShowWindow(SW_SHOW); } +#ifdef _WIN32 BEGIN_EVENTSINK_MAP(CEditorDialog, CDialog) //{{AFX_EVENTSINK_MAP(CEditorDialog) ON_EVENT(CEditorDialog, IDC_GTTRAPEZEDITORCTRL1, 1 /* ColorTableChanged */, OnColorTableChanged, VTS_NONE) //}}AFX_EVENTSINK_MAP END_EVENTSINK_MAP() +#endif /*void CEditorDialog::OnTransferFunctionChanged(LPUNKNOWN colortable) { diff --git a/libVolRen/EditorDialog.h b/libVolRen/EditorDialog.h index 88aaf65b1..461f3614a 100644 --- a/libVolRen/EditorDialog.h +++ b/libVolRen/EditorDialog.h @@ -43,7 +43,9 @@ class CEditorDialog : public CDialog // Generated message map functions //{{AFX_MSG(CEditorDialog) afx_msg void OnColorTableChanged(); +#ifdef _WIN32 DECLARE_EVENTSINK_MAP() +#endif //}}AFX_MSG DECLARE_MESSAGE_MAP() private: diff --git a/libVolRen/StdAfx.cpp b/libVolRen/StdAfx.cpp index caeb97372..e2f27e1cb 100644 --- a/libVolRen/StdAfx.cpp +++ b/libVolRen/StdAfx.cpp @@ -2,7 +2,7 @@ // VolRen.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information -#include "stdafx.h" +#include "StdAfx.h" diff --git a/libVolRen/Trapezeditor.cpp b/libVolRen/Trapezeditor.cpp index 8b2ef3ef4..f91001e74 100644 --- a/libVolRen/Trapezeditor.cpp +++ b/libVolRen/Trapezeditor.cpp @@ -4,7 +4,7 @@ // Microsoft Visual C++, your modifications will be overwritten. -#include "stdafx.h" +#include "StdAfx.h" #include "Trapezeditor.h" ///////////////////////////////////////////////////////////////////////////// @@ -15,6 +15,7 @@ IMPLEMENT_DYNCREATE(CTrapezEditor, CWnd) ///////////////////////////////////////////////////////////////////////////// // CTrapezEditor properties +#ifdef _WIN32 BOOL CTrapezEditor::GetDisplayColorTable() { BOOL result; @@ -98,6 +99,23 @@ void CTrapezEditor::SetDisplayHistogram(BOOL propVal) { SetProperty(0x3, VT_BOOL, propVal); } +#else +// no ActiveX control behind the wrapper: properties read as 0, writes are ignored +BOOL CTrapezEditor::GetDisplayColorTable() { return FALSE; } +void CTrapezEditor::SetDisplayColorTable(BOOL) {} +LPUNKNOWN CTrapezEditor::GetColortable() { return NULL; } +void CTrapezEditor::SetColortable(LPUNKNOWN) {} +long CTrapezEditor::GetResolution() { return 0; } +void CTrapezEditor::SetResolution(long) {} +float CTrapezEditor::GetHistScale() { return 0.0f; } +void CTrapezEditor::SetHistScale(float) {} +LPUNKNOWN CTrapezEditor::GetHistogram() { return NULL; } +void CTrapezEditor::SetHistogram(LPUNKNOWN) {} +short CTrapezEditor::GetDrawstyle() { return 0; } +void CTrapezEditor::SetDrawstyle(short) {} +BOOL CTrapezEditor::GetDisplayHistogram() { return FALSE; } +void CTrapezEditor::SetDisplayHistogram(BOOL) {} +#endif ///////////////////////////////////////////////////////////////////////////// // CTrapezEditor operations diff --git a/libVolRen/Trapezeditor.h b/libVolRen/Trapezeditor.h index 8d46665c7..4893d9bbc 100644 --- a/libVolRen/Trapezeditor.h +++ b/libVolRen/Trapezeditor.h @@ -23,6 +23,7 @@ class CTrapezEditor : public CWnd = { 0x90393a34, 0x2f31, 0x48a4, { 0x93, 0x23, 0x8c, 0xec, 0x42, 0xc7, 0x39, 0x54 } }; return clsid; } +#ifdef _WIN32 virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, @@ -36,6 +37,14 @@ class CTrapezEditor : public CWnd BSTR bstrLicKey = NULL) { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID, pPersist, bStorage, bstrLicKey); } +#else + // ActiveX controls are not available: the transfer function editor cannot be created + virtual BOOL Create(LPCTSTR, LPCTSTR, DWORD, const RECT&, CWnd*, UINT, CCreateContext* = NULL) + { return FALSE; } + + BOOL Create(LPCTSTR, DWORD, const RECT&, CWnd*, UINT, CFile* = NULL, BOOL = FALSE, BSTR = NULL) + { return FALSE; } +#endif // Attributes public: diff --git a/libVolRen/VolRen.cpp b/libVolRen/VolRen.cpp index e0f3a889a..3a388e212 100644 --- a/libVolRen/VolRen.cpp +++ b/libVolRen/VolRen.cpp @@ -1,7 +1,7 @@ // VolRen.cpp : Defines the initialization routines for the DLL. // -#include "stdafx.h" +#include "StdAfx.h" #include #ifdef _DEBUG diff --git a/libVolRen/Volume.h b/libVolRen/Volume.h index dc217ce50..c1c1a5dd0 100644 --- a/libVolRen/Volume.h +++ b/libVolRen/Volume.h @@ -26,6 +26,15 @@ #define VOLUME_MODE_STANDART_OPENGL #define VOLUME_MODE_STANDARD_OPENGL +#ifndef _WIN32 +// modes 2-4 need NVIDIA/WGL extensions loaded through glh_extensions: Windows only +#undef VOLUME_MODE_TEXTURE_PALETTE +#undef VOLUME_MODE_DEPENDENT_TEXTURE +#undef VOLUME_MODE_FRAGMENT_SHADER +#ifndef VOLUME_MODE_STANDARD_OPENGL +#define VOLUME_MODE_STANDARD_OPENGL +#endif +#endif #ifdef VOLUME_MODE_STANDARD_OPENGL #define VOLUME_MODE_SET diff --git a/libVolRen/VolumeRenderer.cpp b/libVolRen/VolumeRenderer.cpp index cd62a7f69..157fa2d79 100644 --- a/libVolRen/VolumeRenderer.cpp +++ b/libVolRen/VolumeRenderer.cpp @@ -6,7 +6,7 @@ #include #include #include "ArcBall.h" -#include "Volume.H" +#include "Volume.h" #include "VolumeRenderer.h" #ifdef _DEBUG diff --git a/libVolRen/VolumeUtilities.cpp b/libVolRen/VolumeUtilities.cpp index a8329ab7b..64bdbff21 100644 --- a/libVolRen/VolumeUtilities.cpp +++ b/libVolRen/VolumeUtilities.cpp @@ -2,7 +2,7 @@ // ////////////////////////////////////////////////////////////////////// -#include "stdafx.h" +#include "StdAfx.h" #include "VolumeUtilities.h" ////////////////////////////////////////////////////////////////////// diff --git a/libanalyse/Converter.cpp b/libanalyse/Converter.cpp index 963991fcd..9754a9eeb 100644 --- a/libanalyse/Converter.cpp +++ b/libanalyse/Converter.cpp @@ -29,6 +29,11 @@ // ///////////////////////////////////////////////////////////////// #include +#ifndef _MSC_VER +#include +static char* _strlwr(char* s) { for (char* p = s; *p; ++p) *p = (char)tolower((unsigned char)*p); return s; } +static char* _strupr(char* s) { for (char* p = s; *p; ++p) *p = (char)toupper((unsigned char)*p); return s; } +#endif #define IMPLEMENT_CONVERTERCLASS 1 #include "Converter.h" diff --git a/libanalyse/Converter.h b/libanalyse/Converter.h index 1cf946f16..867eca115 100644 --- a/libanalyse/Converter.h +++ b/libanalyse/Converter.h @@ -108,9 +108,9 @@ class Converter : public ConverterFormat ///////////////////////////////////////////////////////////////////// #ifdef IMPLEMENT_CONVERTERCLASS -#define CLONE(TYPE) virtual Converter* TYPE::Clone() const { return new TYPE(*this); } +#define CLONE(TYPE) virtual Converter* Clone() const { return new TYPE(*this); } #else -#define CLONE(TYPE) virtual Converter* TYPE::Clone() const; +#define CLONE(TYPE) virtual Converter* Clone() const; #endif ///////////////////////////////////////////////////////////////////// diff --git a/libanalyse/Default.h b/libanalyse/Default.h index 8a19b6f28..6d1e800be 100644 --- a/libanalyse/Default.h +++ b/libanalyse/Default.h @@ -50,7 +50,7 @@ extern OStream DefaultOStream; // GNU specific -#ifdef __GNUC__ +#if defined(__GNUC__) && __GNUC__ < 3 #define EXPLICIT explicit #define NOSTATICTAMPLES #else diff --git a/libanalyse/Format2.h b/libanalyse/Format2.h index 34bfe1846..16dc0c788 100644 --- a/libanalyse/Format2.h +++ b/libanalyse/Format2.h @@ -192,8 +192,8 @@ class NFormat : public BASE ///////////////////////////////////////////////////////////////////// // NFormat: Static Part public: - static Format::Index NewIndex() {return Index(currentindex++);} - static Format::SIndex NewString() {return SIndex(currentstringindex++);} + static Format::Index NewIndex() {return Format::Index(currentindex++);} + static Format::SIndex NewString() {return Format::SIndex(currentstringindex++);} private: static int currentindex; static int currentstringindex; diff --git a/libanalyse/MYMATH.H b/libanalyse/MYMATH.H index 60064fbaa..cbd043439 100644 --- a/libanalyse/MYMATH.H +++ b/libanalyse/MYMATH.H @@ -71,8 +71,8 @@ inline double sqr(double x) {return x*x;} inline long sqr(long x) {return x*x;} // testbit, setbit -inline int testbit(unsigned long l, int p) { return (l&(1<>(istream& s, String& x) { - if (!s.ipfx(0) || (!(s.flags() & ios::skipws) && !ws(s))) + if (!LA_IPFX(s) || (!(s.flags() & ios::skipws) && !ws(s))) { s.clear(ios::failbit|s.rdstate()); // Redundant if using GNU iostreams. return s; @@ -1225,7 +1231,7 @@ istream& operator>>(istream& s, String& x) } x.rep->s[i] = 0; x.rep->len = i; - int new_state = s.rdstate(); + ios::iostate new_state = s.rdstate(); if (i == 0) new_state |= ios::failbit; if (ch == EOF) new_state |= ios::eofbit; s.clear(new_state); @@ -1234,7 +1240,7 @@ istream& operator>>(istream& s, String& x) int readline(istream& s, String& x, char terminator, int discard) { - if (!s.ipfx(0)) + if (!LA_IPFX(s)) return 0; int ch; int i = 0; diff --git a/libanalyse/SymbolArray.h b/libanalyse/SymbolArray.h index d212b79c7..608d4afa6 100644 --- a/libanalyse/SymbolArray.h +++ b/libanalyse/SymbolArray.h @@ -147,7 +147,7 @@ class SymbolArray : public Array void Show(OStream& out=DefaultOStream) const; // Static Members - (should be put in Symbol 'class') - static int MaxBits() {return sizeof(symbol)*8;} + static int MaxBits() {return 32;} // bit-permutation width of the original 32-bit 'unsigned long' symbols static symbol MaxNum() {return 0xFFFFFFFF;} // Implementation diff --git a/libanalyse/la_ostream.h b/libanalyse/la_ostream.h index 8a5e87aaa..f052aa69c 100644 --- a/libanalyse/la_ostream.h +++ b/libanalyse/la_ostream.h @@ -105,6 +105,11 @@ friend inline OStream& sep(OStream& out) { return out.sep(); } }; +// standard C++ needs the manipulators at namespace scope +OStream& flush(OStream& out); +OStream& endl(OStream& out); +OStream& sep(OStream& out); + extern OStream DefaultOStream; ///////////////////////////////////////////////////////////////////// diff --git a/libanalyse/la_string.h b/libanalyse/la_string.h index 2c3c0dd74..d3dfcb74c 100644 --- a/libanalyse/la_string.h +++ b/libanalyse/la_string.h @@ -18,9 +18,12 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. #ifndef _String_h -#ifdef __GNUG__ +#if defined(__GNUG__) && __GNUC__ < 3 #pragma interface #endif +#if defined(__GNUG__) && __GNUC__ >= 3 && !defined(_G_NO_NRV) +#define _G_NO_NRV +#endif #define _String_h 1 #if !defined(_MSC_VER) || _MSC_VER <= 1200 @@ -323,9 +326,9 @@ class String const Regex& sep); friend String common_prefix(const String& x, const String& y, - int startpos = 0); + int startpos); friend String common_suffix(const String& x, const String& y, - int startpos = -1); + int startpos); friend String replicate(char c, int n); friend String replicate(const String& y, int n); friend String join(String src[], int n, const String& sep); @@ -365,8 +368,8 @@ class String friend istream& operator>>(istream& s, String& x); friend int readline(istream& s, String& x, - char terminator = '\n', - int discard_terminator = 1); + char terminator, + int discard_terminator); // status @@ -386,6 +389,12 @@ class String int OK() const; }; +// standard C++ needs these at namespace scope (default arguments, no ADL via String) +String common_prefix(const String& x, const String& y, int startpos = 0); +String common_suffix(const String& x, const String& y, int startpos = -1); +String replicate(char c, int n); +int readline(istream& s, String& x, char terminator = '\n', int discard_terminator = 1); + typedef String StrTmp; // for backward compatibility // other externs diff --git a/libanalyse/mytemplates.h b/libanalyse/mytemplates.h index 24f90edd0..3aa3203f4 100644 --- a/libanalyse/mytemplates.h +++ b/libanalyse/mytemplates.h @@ -32,7 +32,13 @@ #ifndef _MYTEMPLATES_H #define _MYTEMPLATES_H 1 +#ifdef _MSC_VER #include +#define LA_STDCALL __stdcall +#else +#include +#define LA_STDCALL +#endif /////////////////////////////////////////////////////////////////////////////////////// // Beginn Aenderung Jens Liebehenschel, 30.12.1998 @@ -70,7 +76,7 @@ template inline int __stdcall operator>=(const T& x, const T& y) #pragma warning( pop ) // templates defining operator +,-,*,/,^,% using +=,... and initializing constructor -template inline T __stdcall operator+(const T& x, A& y) +template inline T LA_STDCALL operator+(const T& x, A& y) { T tmp(x); tmp+=y; return tmp; } /////////////////////////////////////////////////////////////////////////////////////// // Ende Aenderung Jens Liebehenschel, 30.12.1998 diff --git a/libec/include/ECsecude.h b/libec/include/ECsecude.h index 384e62063..27a0a4d83 100644 --- a/libec/include/ECsecude.h +++ b/libec/include/ECsecude.h @@ -53,13 +53,13 @@ struct Secude_s extern struct Secude_s ECSecudeLib; -#define SECUDE(a) ECSecudeLib.##a -#define SECUDE_DATA_PTR(a) ECSecudeLib.##a +#define SECUDE(a) ECSecudeLib.a +#define SECUDE_DATA_PTR(a) ECSecudeLib.a #else #define SECUDE(a) a -#define SECUDE_DATA_PTR(a) &##a +#define SECUDE_DATA_PTR(a) &a #endif //LINK_SECUDE diff --git a/libec/sources/ECsecude.c b/libec/sources/ECsecude.c index 54a904363..a20aa6781 100644 --- a/libec/sources/ECsecude.c +++ b/libec/sources/ECsecude.c @@ -2,6 +2,15 @@ #ifndef LINK_SECUDE +#ifdef _WIN32 struct Secude_s ECSecudeLib; +#else +/* bound at link time to the SECUDE compatibility library (port/secude) */ +#define DoOneFn(a, b, c, d) (c##_t) c, +#define DoOneData(a, b) &b, +struct Secude_s ECSecudeLib = { DoECAll }; +#undef DoOneFn +#undef DoOneData +#endif -#endif \ No newline at end of file +#endif diff --git a/libmiracl/include/BIG.H b/libmiracl/include/BIG.H index 161a46b1f..0c77389ea 100644 --- a/libmiracl/include/BIG.H +++ b/libmiracl/include/BIG.H @@ -170,7 +170,7 @@ public: // x^m.y^k mod n friend Big pow(int,Big *,Big *,Big); // x[0]^m[0].x[1].m[1]... mod n - friend Big luc(const Big& ,const Big&, const Big&, Big *b4=NULL); + friend Big luc(const Big& ,const Big&, const Big&, Big *b4); friend Big inverse(const Big&, const Big&); friend Big rand(const Big&); // 0 < rand < parameter friend Big rand(int,int); // (digits,base) e.g. (1024,2) @@ -201,7 +201,7 @@ public: friend Big nres_pow(const Big&,const Big&); friend Big nres_pow2(const Big&,const Big&,const Big&,const Big&); friend Big nres_pown(int,Big *,Big *); - friend Big nres_luc(const Big&,const Big&,Big *b3=NULL); + friend Big nres_luc(const Big&,const Big&,Big *b3); friend Big nres_sqrt(const Big&); friend Big nres_modadd(const Big&,const Big&); friend Big nres_modsub(const Big&,const Big&); @@ -230,6 +230,14 @@ public: ~Big() { mirkill(fn); } }; +/* standard C++ needs these at namespace scope (no ADL via Big, default arguments) */ +Big luc(const Big&,const Big&,const Big&,Big *b4=NULL); +Big nres_luc(const Big&,const Big&,Big *b3=NULL); +Big from_binary(int,char *); +Big rand(int,int); +BOOL modulo(int,int,int,int,BOOL); +Big get_modulus(); + #endif diff --git a/libmiracl/include/MIRACL.H b/libmiracl/include/MIRACL.H index 27c6806eb..4304f1b6e 100644 --- a/libmiracl/include/MIRACL.H +++ b/libmiracl/include/MIRACL.H @@ -649,7 +649,7 @@ extern void numer(_MIPT_ flash,big); extern void denom(_MIPT_ flash,big); extern BOOL fit(big,big,int); extern void build(_MIPT_ flash,int (*)(_MIPT_ big,int)); -extern void round(_MIPT_ big,big,flash); +extern void mround(_MIPT_ big,big,flash); extern void flop(_MIPT_ flash,flash,int *,flash); extern void fmul(_MIPT_ flash,flash,flash); extern void fdiv(_MIPT_ flash,flash,flash); diff --git a/libmiracl/source/BIG.CPP b/libmiracl/source/BIG.CPP index f34514020..b1880ca75 100644 --- a/libmiracl/source/BIG.CPP +++ b/libmiracl/source/BIG.CPP @@ -23,7 +23,7 @@ big Big::getbig() const BOOL Big::iszero() const { if (size(fn)==0) return TRUE; return FALSE;} Big operator-(const Big& b) -{Big nb; negate(b.fn,nb.fn); return nb;} +{Big nb; ::negate(b.fn,nb.fn); return nb;} Big operator+(const Big& b,int i) {Big abi; incr(b.fn, i, abi.fn); return abi;} Big operator+(int i,const Big& b) @@ -34,7 +34,7 @@ Big operator+(const Big& b1, const Big& b2) Big operator-(const Big& b, int i) {Big mbi; decr(b.fn, i, mbi.fn); return mbi;} Big operator-(int i, const Big& b) -{Big mib;decr(b.fn, i, mib.fn);negate(mib.fn,mib.fn);return mib;} +{Big mib;decr(b.fn, i, mib.fn);::negate(mib.fn,mib.fn);return mib;} Big operator-(const Big& b1, const Big& b2) {Big mbb; subtract(b1.fn,b2.fn,mbb.fn); return mbb;} diff --git a/libmiracl/source/MRFLASH.C b/libmiracl/source/MRFLASH.C index d31d963cc..c49f723c2 100644 --- a/libmiracl/source/MRFLASH.C +++ b/libmiracl/source/MRFLASH.C @@ -75,7 +75,7 @@ void flop(_MIPD_ flash x,flash y,int *op,flash z) } } mr_mip->check=ON; - round(_MIPP_ mr_mip->w5,mr_mip->w6,z); + mround(_MIPP_ mr_mip->w5,mr_mip->w6,z); MR_OUT } @@ -272,7 +272,7 @@ void fpmul(_MIPD_ flash x,int n,int d,flash y) if (fit(mr_mip->w5,mr_mip->w6,mr_mip->nib)) fpack(_MIPP_ mr_mip->w5,mr_mip->w6,y); else - round(_MIPP_ mr_mip->w5,mr_mip->w6,y); + mround(_MIPP_ mr_mip->w5,mr_mip->w6,y); MR_OUT } @@ -301,7 +301,7 @@ void fincr(_MIPD_ flash x,int n,int d,flash y) if (d==1 && fit(mr_mip->w5,mr_mip->w6,mr_mip->nib)) fpack(_MIPP_ mr_mip->w5,mr_mip->w6,y); else - round(_MIPP_ mr_mip->w5,mr_mip->w6,y); + mround(_MIPP_ mr_mip->w5,mr_mip->w6,y); MR_OUT } diff --git a/libmiracl/source/MRFRND.C b/libmiracl/source/MRFRND.C index c6a06fe92..6f2316bb1 100644 --- a/libmiracl/source/MRFRND.C +++ b/libmiracl/source/MRFRND.C @@ -30,7 +30,7 @@ void frand(_MIPD_ flash x) mr_mip->check=OFF; bigrand(_MIPP_ mr_mip->w6,mr_mip->w5); mr_mip->check=ON; - round(_MIPP_ mr_mip->w5,mr_mip->w6,x); + mround(_MIPP_ mr_mip->w5,mr_mip->w6,x); MR_OUT } diff --git a/libmiracl/source/MRROUND.C b/libmiracl/source/MRROUND.C index cb88dcfb5..89ffffe60 100644 --- a/libmiracl/source/MRROUND.C +++ b/libmiracl/source/MRROUND.C @@ -169,7 +169,7 @@ middle: } -void round(_MIPD_ big num,big den,flash z) +void mround(_MIPD_ big num,big den,flash z) { /* reduces and rounds the fraction num/den into z */ int s; #ifndef MR_GENERIC_MT diff --git a/port/PORTING_STATUS.md b/port/PORTING_STATUS.md new file mode 100644 index 000000000..439db0443 --- /dev/null +++ b/port/PORTING_STATUS.md @@ -0,0 +1,70 @@ +# CrypTool 1 on macOS/Linux — porting status + +Work in progress on branch `xplat-port`. CrypTool builds, links and starts on macOS (arm64) and +Linux (Ubuntu 24.04, GTK 3): the tip-of-the-day dialog and the starting example in the editor +come up. Most features have not been exercised yet. + +**Automatic status:** [STATUS.md on the port-status branch](https://github.com/wroclaw-tech/cryptool1/blob/port-status/STATUS.md) +(`python3 port/tools/port_status.py` locally). It only measures compiling, linking and the unit +tests, which all pass, so it shows 100%; the table below estimates the remaining work by area. + +| Area | Weight | Done | +|---|---|---| +| Resource compiler | 10% | 100% | +| Third-party libraries | 15% | 100% | +| SECUDE replacement | 10% | 100% | +| mfcwx (MFC/Win32 on wxWidgets) | 30% | 85% | +| App sources compile and link | 10% | 100% | +| Run, feature testing, UI tuning | 20% | 15% | +| Packaging (DMG, deb/tar.gz) | 5% | 60% | + +## Approach +The original MFC sources are compiled almost unchanged against **mfcwx**, an MFC/Win32 +compatibility layer implemented on wxWidgets 3.2. Windows resources (`.rc`) are converted to +C++ tables at build time. SECUDE (proprietary, Windows-only) is replaced by an OpenSSL 3 based +implementation of the same API. + +Build and run: +``` +cmake -S . -B build -G Ninja +ninja -C build +build/port/app/CrypTool.app/Contents/MacOS/CrypTool # macOS +build/port/app/CrypTool # Linux +``` +macOS: Homebrew `wxwidgets@3.2 openssl@3 gmp ninja cmake`. Linux (Ubuntu 24.04): +`libwxgtk3.2-dev libssl-dev libgmp-dev libglu1-mesa-dev ninja-build cmake`. +Tests: configure with `-DMFCWX_TESTS=ON -DCRYPTOOL_THIRDPARTY_TESTS=ON`, then `ctest`. +Packages: `cmake --install` / `cpack` (DMG on macOS, tar.gz and deb on Linux). + +## Layout +| Path | Content | +|---|---| +| `port/rc/` | `rc2cpp.py` resource compiler and the `mfcwx_add_rc` CMake function | +| `port/thirdparty/` | libanalyse, MIRACL, NTL, libec, cracklib, apfloat→GMP, cv act→OpenSSL, AES candidates | +| `port/secude/` | SECUDE API on OpenSSL 3 (key stores, CA, certificates, PKCS#12) | +| `port/mfcwx/` | MFC/Win32 headers and implementation, plus runtime/GDI/Scintilla tests | +| `port/app/` | CrypTool target, data directory assembly, bundle/install/CPack rules, icons | +| `port/tools/` | port status, help index generator, dialog gallery, source fix scripts | + +## Key decisions +- HWND = `wxWindow*`; Windows ids are offset by `kIdOffset`, ids that would exceed wx's 0x7fff + limit get compact ids; controls have no data members (temporary `CWnd` casts work as in MFC). +- `CString` is a byte string in the active ANSI code page (1252/1250/1253 by UI language); + conversion happens at the wx boundary. The Scintilla proxy keeps the editor in UTF-8 and + translates text and positions. +- Paths inside the app keep Windows form (`\dir\file`); every file API converts them. +- The registry is an INI file (`~/Library/Preferences/CrypTool1.ini`, `~/.config/cryptool1.ini`); + `APPDATA` points to `~/Library/Application Support` or `~/.local/share`. +- HTML Help is replaced by an in-app wxHtmlHelpController built from the `.hhp/.hhc/.hhk` sources. +- The app is compiled as C++14 with hidden symbol visibility. +- `MFCWX_SNAPSHOT_DIR` makes the app save PNGs of its windows (used by the Linux CI job). + +## Remaining work +1. Exercise the menus: encryption/analysis dialogs, hex editor, plots, OpenGL views, key store, + and fix what breaks (start with the dialog gallery, `-DCRYPTOOL_DIALOG_GALLERY=ON`). +2. UI tuning: dialog sizes and fonts, toolbar icons in dark mode, F1 on submenus + (`WM_MENUSELECT`), printing (currently a stub). +3. Data: ship the PDFs referenced by the help, check the external tools (AES animation, ANIMAL, …). +4. Packaging: sign/notarize the macOS bundle, test the deb on a clean system. + +Known approximations are listed in the commit messages of the respective mfcwx parts. diff --git a/port/app/CMakeLists.txt b/port/app/CMakeLists.txt new file mode 100644 index 000000000..18b2d0020 --- /dev/null +++ b/port/app/CMakeLists.txt @@ -0,0 +1,173 @@ +include(${REPO_ROOT}/port/rc/rc2cpp.cmake) + +set(CT_SRC ${REPO_ROOT}/CrypTool) +# *.CPP: the MIRACL wrapper copies (MONTY.CPP, ...); globbing is case-sensitive on Linux. +file(GLOB CT_SOURCES CONFIGURE_DEPENDS ${CT_SRC}/*.cpp ${CT_SRC}/*.CPP ${CT_SRC}/zip/*.c) +list(REMOVE_DUPLICATES CT_SOURCES) +list(FILTER CT_SOURCES EXCLUDE REGEX "/(Ber_Ell_Kurve|DlgCrypToolPRNGSeedCollector|DlgFindText|DlgMac|DlgSelHash)\\.cpp$") +# zip/main.c is the standalone test driver of the zip code (not part of CrypTool.vcproj). +list(FILTER CT_SOURCES EXCLUDE REGEX "/zip/main\\.c$") +# OLE-based picture control on Windows, wxWidgets-based elsewhere. +if(WIN32) + list(FILTER CT_SOURCES EXCLUDE REGEX "/PictureEx(Loop)?_wx\\.cpp$") +else() + list(FILTER CT_SOURCES EXCLUDE REGEX "/PictureEx(Loop)?\\.cpp$") +endif() +file(GLOB CT_EXTRA_SOURCES CONFIGURE_DEPENDS + ${REPO_ROOT}/libVolRen/ArcBall.cpp ${REPO_ROOT}/libVolRen/CMatrix.cpp ${REPO_ROOT}/libVolRen/CPosition.cpp + ${REPO_ROOT}/libVolRen/CQuaternion.cpp ${REPO_ROOT}/libVolRen/CVector.cpp ${REPO_ROOT}/libVolRen/Volume.cpp + ${REPO_ROOT}/libVolRen/VolumeUtilities.cpp ${REPO_ROOT}/ChallengeResponse/*.cpp) + +add_executable(CrypTool ${CT_SOURCES} ${CT_EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/platform.cpp) +mfcwx_add_rc(CrypTool RC ${CT_SRC}/CrypTool.rc MODULE CrypTool HEADERS ${CT_SRC}/resource.h + REPLACE "[CRYPTOOL_VERSION_FULL]=CrypTool ${PROJECT_VERSION}" "[CRYPTOOL_VERSION]=${PROJECT_VERSION}") + +set_target_properties(CrypTool PROPERTIES CXX_STANDARD 14 CXX_EXTENSIONS ON) +# The zip code defines inflate, deflate, error, ... globally; exported, they would replace zlib's and glibc's +# functions for the shared libraries (FreeType crashes in CrypTool's inflate on Linux). +set_target_properties(CrypTool PROPERTIES C_VISIBILITY_PRESET hidden CXX_VISIBILITY_PRESET hidden) +# Quoted includes only: etc. must resolve to the libraries, as on Windows. +target_compile_options(CrypTool PRIVATE "SHELL:-iquote ${CT_SRC}" "SHELL:-iquote ${REPO_ROOT}/libVolRen" + "SHELL:-iquote ${REPO_ROOT}/ChallengeResponse") +target_include_directories(CrypTool PRIVATE ${REPO_ROOT}/scintilla/include) +target_link_libraries(CrypTool PRIVATE mfcwx cryptool_thirdparty $ OpenSSL::Crypto) +target_compile_options(CrypTool PRIVATE + -Wno-inconsistent-missing-override -Wno-overloaded-virtual -Wno-deprecated-declarations + $<$:-Wno-register -Wno-writable-strings -Wno-write-strings> + -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-dangling-else + -Wno-switch -Wno-unused-value -Wno-sign-compare -Wno-char-subscripts -Wno-missing-braces + -fno-delete-null-pointer-checks) +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(CrypTool PRIVATE -Wno-c++11-narrowing -Wno-reserved-user-defined-literal + -Wno-logical-op-parentheses -Wno-bitwise-op-parentheses -Wno-shift-op-parentheses + -Wno-tautological-constant-out-of-range-compare -Wno-unused-private-field -Wno-null-conversion + -Wno-undefined-bool-conversion -Wno-format-security) +else() + target_compile_options(CrypTool PRIVATE $<$:-Wno-narrowing -fpermissive>) +endif() + +set(CRYPTOOL_DEV_DATA_DIR ${CMAKE_BINARY_DIR}/data) +target_compile_definitions(CrypTool PRIVATE CRYPTOOL_DEV_DATA_DIR="${CRYPTOOL_DEV_DATA_DIR}") +add_custom_target(cryptool_data ALL + COMMAND ${CMAKE_COMMAND} -DREPO_ROOT=${REPO_ROOT} -DDATA_DIR=${CRYPTOOL_DEV_DATA_DIR} + -DMKPSE=$ -P ${CMAKE_CURRENT_SOURCE_DIR}/assemble_data.cmake + DEPENDS secude_compat_mkpse + COMMENT "Assembling the CrypTool data directory" + VERBATIM) +add_dependencies(CrypTool cryptool_data) + +# --------------------------------------------------------------------------------------------- +# Help: hlp_* mirrored into the data directory plus the index read by mfcwx (help.cpp) + +set(CT_HELP_LANGUAGES en de) +set(CT_HELP_GENERATED CrypTool.helpindex hid_load_readme.html) +set(CT_HELP_OUTPUTS) +foreach(lang IN LISTS CT_HELP_LANGUAGES) + set(help_src ${CT_SRC}/hlp_${lang}) + set(help_out ${CRYPTOOL_DEV_DATA_DIR}/hlp_${lang}) + set(readme ${REPO_ROOT}/setup/template-${lang}/ReadMe-${lang}.txt) + file(GLOB help_inputs CONFIGURE_DEPENDS LIST_DIRECTORIES false ${help_src}/*) + list(TRANSFORM CT_HELP_GENERATED PREPEND ${help_out}/ OUTPUT_VARIABLE outputs) + add_custom_command(OUTPUT ${outputs} + COMMAND ${Python3_EXECUTABLE} ${REPO_ROOT}/port/tools/build_help_index.py --mirror --help-dir ${help_src} + --resource-header ${CT_SRC}/resource.h --readme ${readme} --out-dir ${help_out} + DEPENDS ${REPO_ROOT}/port/tools/build_help_index.py ${CT_SRC}/resource.h ${readme} ${help_inputs} + COMMENT "Generating the help index for hlp_${lang}" + VERBATIM) + list(APPEND CT_HELP_OUTPUTS ${outputs}) +endforeach() +add_custom_target(cryptool_help ALL DEPENDS ${CT_HELP_OUTPUTS}) +add_dependencies(CrypTool cryptool_help) + +# --------------------------------------------------------------------------------------------- +# Installation and packages + +include(GNUInstallDirs) +if(APPLE) + set(MACOSX_BUNDLE_ICON ${CMAKE_CURRENT_SOURCE_DIR}/icons/CrypTool.icns) + set_source_files_properties(${MACOSX_BUNDLE_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + target_sources(CrypTool PRIVATE ${MACOSX_BUNDLE_ICON}) + set_target_properties(CrypTool PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in) + set(CRYPTOOL_DATA_DEST CrypTool.app/Contents/Resources) + install(TARGETS CrypTool BUNDLE DESTINATION .) +else() + set(CRYPTOOL_DATA_DEST ${CMAKE_INSTALL_DATADIR}/CrypTool) + install(TARGETS CrypTool RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(FILES cryptool.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + install(FILES icons/cryptool-256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME cryptool.png) + install(FILES icons/cryptool-48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME cryptool.png) +endif() + +mfcwx_install_rc_files(CrypTool DESTINATION ${CRYPTOOL_DATA_DEST}) +foreach(help hlp_en hlp_de) + install(DIRECTORY ${CT_SRC}/${help} DESTINATION ${CRYPTOOL_DATA_DEST} + PATTERN "*.vcproj" EXCLUDE PATTERN "*.vcxproj*" EXCLUDE PATTERN "*.hhp" EXCLUDE) +endforeach() +foreach(lang IN LISTS CT_HELP_LANGUAGES) + list(TRANSFORM CT_HELP_GENERATED PREPEND ${CRYPTOOL_DEV_DATA_DIR}/hlp_${lang}/ OUTPUT_VARIABLE outputs) + install(FILES ${outputs} DESTINATION ${CRYPTOOL_DATA_DEST}/hlp_${lang}) +endforeach() +file(GLOB CT_TEMPLATE_ENTRIES RELATIVE ${REPO_ROOT}/setup/template ${REPO_ROOT}/setup/template/*) +foreach(entry IN LISTS CT_TEMPLATE_ENTRIES) + string(TOLOWER "${entry}" lower) + if(lower MATCHES "\\.(dll|manifest)$" OR lower STREQUAL "pse") + continue() + endif() + if(IS_DIRECTORY ${REPO_ROOT}/setup/template/${entry}) + install(DIRECTORY ${REPO_ROOT}/setup/template/${entry} DESTINATION ${CRYPTOOL_DATA_DEST}) + else() + install(FILES ${REPO_ROOT}/setup/template/${entry} DESTINATION ${CRYPTOOL_DATA_DEST}) + endif() +endforeach() +install(DIRECTORY ${CRYPTOOL_DEV_DATA_DIR}/PSE DESTINATION ${CRYPTOOL_DATA_DEST} OPTIONAL) + +if(APPLE) + # Copies the Homebrew dylibs (wxWidgets, OpenSSL, GMP) into the bundle so it runs on other Macs. + execute_process(COMMAND brew --prefix OUTPUT_VARIABLE brew_prefix OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) + set(bundle_lib_dirs) + foreach(prefix ${brew_prefix} /opt/homebrew /usr/local) + if(EXISTS ${prefix}/lib) + list(APPEND bundle_lib_dirs ${prefix}/lib) + endif() + endforeach() + list(REMOVE_DUPLICATES bundle_lib_dirs) + install(CODE " + include(BundleUtilities) + fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/CrypTool.app\" \"\" \"${bundle_lib_dirs}\") + execute_process(COMMAND codesign --force --deep --sign - \"\${CMAKE_INSTALL_PREFIX}/CrypTool.app\" + RESULT_VARIABLE sign_result) + if(NOT sign_result EQUAL 0) + message(FATAL_ERROR \"codesign failed\") + endif() + ") +endif() + +set(CPACK_PACKAGE_NAME CrypTool) +set(CPACK_PACKAGE_VENDOR "CrypTool project") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CrypTool 1 - learn and try out cryptography and cryptanalysis") +set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) +set(CPACK_RESOURCE_FILE_LICENSE ${REPO_ROOT}/COPYING) +string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" cpack_arch) +if(cpack_arch STREQUAL "amd64") + set(cpack_arch x86_64) +elseif(cpack_arch STREQUAL "aarch64") + set(cpack_arch arm64) +endif() +if(APPLE) + set(cpack_os macos) +else() + set(cpack_os linux) +endif() +set(CPACK_PACKAGE_FILE_NAME "CrypTool-${PROJECT_VERSION}-${cpack_os}-${cpack_arch}") +if(APPLE) + set(CPACK_GENERATOR DragNDrop) + set(CPACK_DMG_VOLUME_NAME "CrypTool ${PROJECT_VERSION}") +else() + set(CPACK_GENERATOR TGZ DEB) + set(CPACK_DEBIAN_PACKAGE_MAINTAINER "CrypTool project") + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + set(CPACK_DEBIAN_PACKAGE_SECTION education) +endif() +include(CPack) diff --git a/port/app/Info.plist.in b/port/app/Info.plist.in new file mode 100644 index 000000000..e36da4ed2 --- /dev/null +++ b/port/app/Info.plist.in @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + CrypTool + CFBundleIconFile + CrypTool.icns + CFBundleIdentifier + org.cryptool.ct1 + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CrypTool + CFBundleDisplayName + CrypTool 1 + CFBundlePackageType + APPL + CFBundleShortVersionString + ${PROJECT_VERSION} + CFBundleVersion + ${PROJECT_VERSION} + LSMinimumSystemVersion + 11.0 + NSHighResolutionCapable + + NSPrincipalClass + NSApplication + CFBundleDocumentTypes + + + CFBundleTypeRole + Editor + LSItemContentTypes + + public.data + + + + + diff --git a/port/app/assemble_data.cmake b/port/app/assemble_data.cmake new file mode 100644 index 000000000..6c824fb3e --- /dev/null +++ b/port/app/assemble_data.cmake @@ -0,0 +1,30 @@ +# Builds the data directory the application reads at run time (a development stand-in for the +# installed resources): links to the bitmaps and template files plus freshly generated key stores. +# The help directories are set up by the cryptool_help target (port/tools/build_help_index.py). +# cmake -DREPO_ROOT=... -DDATA_DIR=... -DMKPSE=... -P assemble_data.cmake + +file(MAKE_DIRECTORY "${DATA_DIR}") + +function(link_into name target) + if(NOT EXISTS "${DATA_DIR}/${name}" AND EXISTS "${target}") + file(CREATE_LINK "${target}" "${DATA_DIR}/${name}" SYMBOLIC) + endif() +endfunction() + +link_into(res "${REPO_ROOT}/CrypTool/res") + +file(GLOB template_entries RELATIVE "${REPO_ROOT}/setup/template" "${REPO_ROOT}/setup/template/*") +foreach(entry IN LISTS template_entries) + string(TOLOWER "${entry}" lower) + if(lower MATCHES "\\.(dll|manifest)$" OR lower STREQUAL "pse") + continue() + endif() + link_into("${entry}" "${REPO_ROOT}/setup/template/${entry}") +endforeach() + +if(MKPSE AND NOT EXISTS "${DATA_DIR}/PSE/PSECA/capse.cse") + execute_process(COMMAND "${MKPSE}" "${DATA_DIR}" RESULT_VARIABLE result) + if(NOT result EQUAL 0) + message(WARNING "secude_compat_mkpse failed: ${result}") + endif() +endif() diff --git a/port/app/cryptool.desktop b/port/app/cryptool.desktop new file mode 100644 index 000000000..54d857734 --- /dev/null +++ b/port/app/cryptool.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=CrypTool 1 +GenericName=Cryptography learning tool +Comment=Learn and try out cryptography and cryptanalysis +Exec=CrypTool %F +Icon=cryptool +Terminal=false +Categories=Education;Security;Utility; diff --git a/port/app/icons/CrypTool.icns b/port/app/icons/CrypTool.icns new file mode 100644 index 000000000..351f358fe Binary files /dev/null and b/port/app/icons/CrypTool.icns differ diff --git a/port/app/icons/cryptool-256.png b/port/app/icons/cryptool-256.png new file mode 100644 index 000000000..e9d76f399 Binary files /dev/null and b/port/app/icons/cryptool-256.png differ diff --git a/port/app/icons/cryptool-48.png b/port/app/icons/cryptool-48.png new file mode 100644 index 000000000..b34de0edc Binary files /dev/null and b/port/app/icons/cryptool-48.png differ diff --git a/port/app/platform.cpp b/port/app/platform.cpp new file mode 100644 index 000000000..3b945674d --- /dev/null +++ b/port/app/platform.cpp @@ -0,0 +1,15 @@ +#include "mfcwx/app.h" +#include "mfcwx/rcdata.h" + +extern const mfcwx::rc::Module g_rcModule_CrypTool; + +namespace { + +struct RegisterCrypTool { + RegisterCrypTool() { + mfcwx::RegisterResourceModule(&g_rcModule_CrypTool); + mfcwx::SetDefaultDataDirectory(CRYPTOOL_DEV_DATA_DIR); + } +} registerCrypTool; + +} // namespace diff --git a/port/mfcwx/CMakeLists.txt b/port/mfcwx/CMakeLists.txt new file mode 100644 index 000000000..671ace4cb --- /dev/null +++ b/port/mfcwx/CMakeLists.txt @@ -0,0 +1,60 @@ +file(GLOB MFCWX_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +if(APPLE) + enable_language(OBJCXX) + list(APPEND MFCWX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/snapshot_mac.mm) +endif() + +add_library(mfcwx STATIC ${MFCWX_SOURCES}) +target_include_directories(mfcwx PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_compile_features(mfcwx PUBLIC cxx_std_14) +include(${wxWidgets_USE_FILE}) +target_include_directories(mfcwx SYSTEM PUBLIC ${wxWidgets_INCLUDE_DIRS}) +target_compile_definitions(mfcwx PUBLIC ${wxWidgets_DEFINITIONS} MFCWX=1) +target_compile_options(mfcwx PUBLIC ${wxWidgets_CXX_FLAGS}) +target_link_libraries(mfcwx PUBLIC ${wxWidgets_LIBRARIES} OpenGL::GL Threads::Threads ${CMAKE_DL_LIBS}) +if(APPLE) + target_link_libraries(mfcwx PUBLIC "-framework OpenGL" "-framework Cocoa") +endif() + +option(MFCWX_TESTS "Build the mfcwx runtime tests" OFF) +if(MFCWX_TESTS) + # The runtime sources are compiled directly so the tests do not depend on the GUI parts; + # tests/runtime_stubs.cpp provides the few GUI symbols they reference. + set(MFCWX_RUNTIME_SOURCES + afxcore.cpp afxfile.cpp afxmt.cpp codepage.cpp codepage_tables.cpp crt.cpp cstring.cpp file.cpp kernel.cpp + profile.cpp thread.cpp win32.cpp) + list(TRANSFORM MFCWX_RUNTIME_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/src/) + add_executable(mfcwx_runtime_tests tests/runtime_tests.cpp tests/runtime_stubs.cpp ${MFCWX_RUNTIME_SOURCES}) + target_include_directories(mfcwx_runtime_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src) + target_include_directories(mfcwx_runtime_tests SYSTEM PRIVATE ${wxWidgets_INCLUDE_DIRS}) + target_compile_features(mfcwx_runtime_tests PRIVATE cxx_std_14) + target_compile_definitions(mfcwx_runtime_tests PRIVATE ${wxWidgets_DEFINITIONS} MFCWX=1) + target_compile_options(mfcwx_runtime_tests PRIVATE ${wxWidgets_CXX_FLAGS}) + target_link_libraries(mfcwx_runtime_tests PRIVATE ${wxWidgets_LIBRARIES} Threads::Threads ${CMAKE_DL_LIBS}) + add_test(NAME mfcwx_runtime_tests COMMAND mfcwx_runtime_tests) + + # GDI tests: render through CDC into bitmaps, check pixels and write PNGs for inspection. + set(MFCWX_GDI_SOURCES gdi.cpp gdi_bits.cpp gdi_dc.cpp gdi_text.cpp codepage.cpp codepage_tables.cpp cstring.cpp) + list(TRANSFORM MFCWX_GDI_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/src/) + add_executable(mfcwx_gdi_tests tests/gdi_tests.cpp tests/gdi_test_stubs.cpp ${MFCWX_GDI_SOURCES}) + target_include_directories(mfcwx_gdi_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) + target_include_directories(mfcwx_gdi_tests SYSTEM PRIVATE ${wxWidgets_INCLUDE_DIRS}) + target_compile_features(mfcwx_gdi_tests PRIVATE cxx_std_14) + target_compile_definitions(mfcwx_gdi_tests PRIVATE ${wxWidgets_DEFINITIONS} MFCWX=1) + target_compile_options(mfcwx_gdi_tests PRIVATE ${wxWidgets_CXX_FLAGS}) + target_link_libraries(mfcwx_gdi_tests PRIVATE ${wxWidgets_LIBRARIES} Threads::Threads ${CMAKE_DL_LIBS}) + add_test(NAME mfcwx_gdi_tests COMMAND mfcwx_gdi_tests ${CMAKE_CURRENT_BINARY_DIR}/gdi_test_output) + + # Scintilla proxy; tests/scintilla_tests.cpp records the notifications it sends. + add_executable(mfcwx_scintilla_tests tests/scintilla_tests.cpp src/scintilla.cpp src/codepage.cpp + src/codepage_tables.cpp) + target_include_directories(mfcwx_scintilla_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src) + target_include_directories(mfcwx_scintilla_tests SYSTEM PRIVATE ${wxWidgets_INCLUDE_DIRS}) + target_compile_features(mfcwx_scintilla_tests PRIVATE cxx_std_14) + target_compile_definitions(mfcwx_scintilla_tests PRIVATE ${wxWidgets_DEFINITIONS} MFCWX=1) + target_compile_options(mfcwx_scintilla_tests PRIVATE ${wxWidgets_CXX_FLAGS}) + target_link_libraries(mfcwx_scintilla_tests PRIVATE ${wxWidgets_LIBRARIES} Threads::Threads) + add_test(NAME mfcwx_scintilla_tests COMMAND mfcwx_scintilla_tests) +endif() diff --git a/port/mfcwx/include/afx.h b/port/mfcwx/include/afx.h new file mode 100644 index 000000000..4efb4f2ab --- /dev/null +++ b/port/mfcwx/include/afx.h @@ -0,0 +1,602 @@ +#pragma once + +// MFC core (non-GUI) subset: CObject, CString, exceptions, files, archives, time, collections. +#define __AFX_H__ + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "mfcwx/win32.h" + +#ifdef __cplusplus + +#include "mfcwx/cstring.h" +#include "mfcwx/codepage.h" + +#ifndef _DEBUG +#define ASSERT(f) ((void)0) +#define ASSERT_VALID(p) ((void)0) +#define ASSERT_KINDOF(class_name, object) ((void)0) +#define ASSERT_POINTER(p, type) ((void)0) +#define ASSERT_NULL_OR_POINTER(p, type) ((void)0) +#else +#define ASSERT(f) ((f) ? (void)0 : AfxAssertFailedLine(__FILE__, __LINE__, #f)) +#define ASSERT_VALID(p) ((void)0) +#define ASSERT_KINDOF(class_name, object) ((void)0) +#define ASSERT_POINTER(p, type) ASSERT((p) != NULL) +#define ASSERT_NULL_OR_POINTER(p, type) ((void)0) +#endif +#define VERIFY(f) ((void)(f)) +#define ENSURE(f) ((void)(f)) +#define ENSURE_ARG(f) ((void)(f)) +#define DEBUG_ONLY(f) ((void)0) +#define TRACE(...) ((void)0) +#define TRACE0(sz) ((void)0) +#define TRACE1(sz, p1) ((void)0) +#define TRACE2(sz, p1, p2) ((void)0) +#define TRACE3(sz, p1, p2, p3) ((void)0) +#define ATLTRACE(...) ((void)0) +#define ATLASSERT(f) ((void)0) +#define DEBUG_NEW new +#define THIS_FILE __FILE__ +#define AFX_MANAGE_STATE(p) +#define AfxGetStaticModuleState() nullptr +#define afx_msg +#define AFX_MSG_CALL +#define AFX_INLINE inline + +void AfxAssertFailedLine(const char* file, int line, const char* expr); + +// MFC code calls members such as GetSafeHwnd() through null pointers; hide the origin of the +// pointer from the optimizer so the null test survives. +inline bool AfxIsNullThis(const void* p) { + __asm__("" : "+r"(p)); + return p == nullptr; +} +void AfxDebugBreak(); + +class CArchive; +class CDumpContext; +class CObject; + +struct CRuntimeClass { + const char* m_lpszClassName; + int m_nObjectSize; + UINT m_wSchema; + CObject* (*m_pfnCreateObject)(); + CRuntimeClass* (*m_pfnGetBaseClass)(); + CRuntimeClass* m_pNextClass; + + CObject* CreateObject(); + BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; + CRuntimeClass* GetBaseClass() const { return m_pfnGetBaseClass ? m_pfnGetBaseClass() : nullptr; } + static CRuntimeClass* FromName(const char* name); + static CObject* CreateObject(const char* name); +}; + +struct AFX_CLASSINIT { + explicit AFX_CLASSINIT(CRuntimeClass* pNewClass); +}; + +class CDumpContext { +public: + CDumpContext& operator<<(const char*) { return *this; } + CDumpContext& operator<<(int) { return *this; } + CDumpContext& operator<<(unsigned) { return *this; } + CDumpContext& operator<<(long) { return *this; } + CDumpContext& operator<<(double) { return *this; } + CDumpContext& operator<<(const void*) { return *this; } + int GetDepth() const { return 0; } +}; +extern CDumpContext afxDump; + +class CObject { +public: + virtual CRuntimeClass* GetRuntimeClass() const; + virtual ~CObject() = default; + BOOL IsKindOf(const CRuntimeClass* pClass) const; + BOOL IsSerializable() const; + virtual void Serialize(CArchive& ar); + virtual void AssertValid() const {} + virtual void Dump(CDumpContext&) const {} + + static CRuntimeClass classCObject; + static CRuntimeClass* GetThisClass(); + +protected: + CObject() = default; + CObject(const CObject&) = default; + CObject& operator=(const CObject&) = default; +}; + +#define _RUNTIME_CLASS(class_name) (class_name::GetThisClass()) +#define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name) + +#define DECLARE_DYNAMIC(class_name) \ +public: \ + static CRuntimeClass class##class_name; \ + static CRuntimeClass* GetThisClass(); \ + CRuntimeClass* GetRuntimeClass() const override; + +#define DECLARE_DYNCREATE(class_name) \ + DECLARE_DYNAMIC(class_name) \ + static CObject* CreateObject(); + +#define DECLARE_SERIAL(class_name) \ + DECLARE_DYNCREATE(class_name) \ + friend CArchive& operator>>(CArchive& ar, class_name*& pOb); + +#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \ + CRuntimeClass class_name::class##class_name = {#class_name, sizeof(class class_name), wSchema, pfnNew, \ + &base_class_name::GetThisClass, nullptr}; \ + static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \ + CRuntimeClass* class_name::GetThisClass() { return &class_name::class##class_name; } \ + CRuntimeClass* class_name::GetRuntimeClass() const { return &class_name::class##class_name; } + +#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ + IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, nullptr) + +#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \ + CObject* class_name::CreateObject() { return new class_name; } \ + IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, class_name::CreateObject) + +#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \ + CObject* class_name::CreateObject() { return new class_name; } \ + IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, class_name::CreateObject) \ + CArchive& operator>>(CArchive& ar, class_name*& pOb) { \ + pOb = static_cast(ar.ReadObject(RUNTIME_CLASS(class_name))); \ + return ar; \ + } + +#define VERSIONABLE_SCHEMA (0x80000000) + +// --------------------------------------------------------------------------------------------- +// Exceptions + +class CException : public CObject { + DECLARE_DYNAMIC(CException) +public: + explicit CException(BOOL bAutoDelete = TRUE) : m_bAutoDelete(bAutoDelete) {} + void Delete(); + virtual BOOL GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext = nullptr) const; + virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0); + BOOL m_bAutoDelete; +}; + +class CSimpleException : public CException { + DECLARE_DYNAMIC(CSimpleException) +public: + CSimpleException() = default; + explicit CSimpleException(BOOL bAutoDelete) : CException(bAutoDelete) {} +}; + +class CMemoryException : public CSimpleException { + DECLARE_DYNAMIC(CMemoryException) +public: + CMemoryException() = default; + BOOL GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext = nullptr) const override; +}; + +class CNotSupportedException : public CSimpleException { + DECLARE_DYNAMIC(CNotSupportedException) +}; + +class CInvalidArgException : public CSimpleException { + DECLARE_DYNAMIC(CInvalidArgException) +}; + +class CUserException : public CSimpleException { + DECLARE_DYNAMIC(CUserException) +}; + +class CResourceException : public CSimpleException { + DECLARE_DYNAMIC(CResourceException) +}; + +class CArchiveException : public CException { + DECLARE_DYNAMIC(CArchiveException) +public: + enum { none, genericException, readOnly, endOfFile, writeOnly, badIndex, badClass, badSchema, bufferFull }; + explicit CArchiveException(int cause = none, const char* lpszArchiveName = nullptr) + : m_cause(cause), m_strFileName(lpszArchiveName) {} + BOOL GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext = nullptr) const override; + int m_cause; + CString m_strFileName; +}; + +class CFileException : public CException { + DECLARE_DYNAMIC(CFileException) +public: + enum { + none, + genericException, + fileNotFound, + badPath, + tooManyOpenFiles, + accessDenied, + invalidFile, + removeCurrentDir, + directoryFull, + badSeek, + hardIO, + sharingViolation, + lockViolation, + diskFull, + endOfFile + }; + explicit CFileException(int cause = none, LONG lOsError = -1, const char* lpszArchiveName = nullptr) + : m_cause(cause), m_lOsError(lOsError), m_strFileName(lpszArchiveName) {} + BOOL GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext = nullptr) const override; + static int OsErrorToException(LONG lOsError); + static int ErrnoToException(int nErrno); + static void ThrowOsError(LONG lOsError, const char* lpszFileName = nullptr); + static void ThrowErrno(int nErrno, const char* lpszFileName = nullptr); + int m_cause; + LONG m_lOsError; + CString m_strFileName; +}; + +[[noreturn]] void AfxThrowMemoryException(); +[[noreturn]] void AfxThrowNotSupportedException(); +[[noreturn]] void AfxThrowInvalidArgException(); +[[noreturn]] void AfxThrowUserException(); +[[noreturn]] void AfxThrowResourceException(); +[[noreturn]] void AfxThrowArchiveException(int cause, const char* lpszArchiveName = nullptr); +[[noreturn]] void AfxThrowFileException(int cause, LONG lOsError = -1, const char* lpszFileName = nullptr); +void AfxAbort(); + +#define TRY try +#define CATCH(class, e) catch (class * e) +#define AND_CATCH(class, e) catch (class * e) +#define END_CATCH +#define CATCH_ALL(e) catch (CException * e) +#define AND_CATCH_ALL(e) catch (CException * e) +#define END_CATCH_ALL +#define END_TRY +#define THROW(e) throw e +#define THROW_LAST() throw + +// --------------------------------------------------------------------------------------------- +// Files + +struct CFileStatus { + time_t m_ctime; + time_t m_mtime; + time_t m_atime; + ULONGLONG m_size; + BYTE m_attribute; + char m_szFullName[_MAX_PATH]; +}; + +class CFile : public CObject { + DECLARE_DYNAMIC(CFile) +public: + enum OpenFlags { + modeRead = 0x0000, + modeWrite = 0x0001, + modeReadWrite = 0x0002, + shareCompat = 0x0000, + shareExclusive = 0x0010, + shareDenyWrite = 0x0020, + shareDenyRead = 0x0030, + shareDenyNone = 0x0040, + modeNoInherit = 0x0080, + modeCreate = 0x1000, + modeNoTruncate = 0x2000, + typeText = 0x4000, + typeBinary = 0x8000, + osNoBuffer = 0x10000, + osWriteThrough = 0x20000, + osRandomAccess = 0x40000, + osSequentialScan = 0x80000 + }; + enum Attribute { normal = 0x00, readOnly = 0x01, hidden = 0x02, system = 0x04, volume = 0x08, directory = 0x10, archive = 0x20 }; + enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 }; + static const HANDLE hFileNull; + + CFile(); + explicit CFile(HANDLE hFile); + CFile(const char* lpszFileName, UINT nOpenFlags); + ~CFile() override; + + virtual BOOL Open(const char* lpszFileName, UINT nOpenFlags, CFileException* pError = nullptr); + virtual void Close(); + virtual void Abort(); + virtual UINT Read(void* lpBuf, UINT nCount); + virtual void Write(const void* lpBuf, UINT nCount); + virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom); + void SeekToBegin() { Seek(0, begin); } + ULONGLONG SeekToEnd() { return Seek(0, end); } + virtual ULONGLONG GetLength() const; + virtual void SetLength(ULONGLONG dwNewLen); + virtual ULONGLONG GetPosition() const; + virtual void Flush(); + virtual CString GetFileName() const; + virtual CString GetFileTitle() const; + virtual CString GetFilePath() const { return m_strFileName; } + virtual void SetFilePath(const char* lpszNewName) { m_strFileName = lpszNewName; } + BOOL GetStatus(CFileStatus& rStatus) const; + static BOOL GetStatus(const char* lpszFileName, CFileStatus& rStatus); + static void SetStatus(const char* lpszFileName, const CFileStatus& status); + static void Rename(const char* lpszOldName, const char* lpszNewName); + static void Remove(const char* lpszFileName); + virtual void LockRange(ULONGLONG, ULONGLONG) {} + virtual void UnlockRange(ULONGLONG, ULONGLONG) {} + virtual CFile* Duplicate() const; + operator HANDLE() const { return m_hFile; } + + HANDLE m_hFile; + BOOL m_bCloseOnDelete; + CString m_strFileName; + +protected: + int m_fd; +}; + +class CStdioFile : public CFile { + DECLARE_DYNAMIC(CStdioFile) +public: + CStdioFile(); + explicit CStdioFile(FILE* pOpenStream); + CStdioFile(const char* lpszFileName, UINT nOpenFlags); + ~CStdioFile() override; + + BOOL Open(const char* lpszFileName, UINT nOpenFlags, CFileException* pError = nullptr) override; + void Close() override; + void Abort() override; + UINT Read(void* lpBuf, UINT nCount) override; + void Write(const void* lpBuf, UINT nCount) override; + ULONGLONG Seek(LONGLONG lOff, UINT nFrom) override; + ULONGLONG GetLength() const override; + ULONGLONG GetPosition() const override; + void Flush() override; + virtual void WriteString(const char* lpsz); + virtual char* ReadString(char* lpsz, UINT nMax); + virtual BOOL ReadString(CString& rString); + + FILE* m_pStream; + +private: + bool m_text; +}; + +class CMemFile : public CFile { + DECLARE_DYNAMIC(CMemFile) +public: + explicit CMemFile(UINT nGrowBytes = 1024); + CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes = 0); + ~CMemFile() override; + void Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes = 0); + BYTE* Detach(); + BOOL Open(const char*, UINT, CFileException* = nullptr) override { return FALSE; } + void Close() override; + void Abort() override { Close(); } + UINT Read(void* lpBuf, UINT nCount) override; + void Write(const void* lpBuf, UINT nCount) override; + ULONGLONG Seek(LONGLONG lOff, UINT nFrom) override; + ULONGLONG GetLength() const override { return m_nFileSize; } + void SetLength(ULONGLONG dwNewLen) override; + ULONGLONG GetPosition() const override { return m_nPosition; } + void Flush() override {} + +private: + void Grow(size_t size); + BYTE* m_lpBuffer; + size_t m_nBufferSize; + size_t m_nFileSize; + size_t m_nPosition; + UINT m_nGrowBytes; + bool m_bAutoDelete; +}; + +class CFileFind : public CObject { + DECLARE_DYNAMIC(CFileFind) +public: + CFileFind(); + ~CFileFind() override; + virtual BOOL FindFile(const char* pstrName = nullptr, DWORD dwUnused = 0); + virtual BOOL FindNextFile(); + void Close(); + ULONGLONG GetLength() const; + CString GetFileName() const; + CString GetFilePath() const; + CString GetFileTitle() const; + CString GetFileURL() const; + CString GetRoot() const; + BOOL IsDots() const; + BOOL IsDirectory() const; + BOOL IsReadOnly() const { return FALSE; } + BOOL IsHidden() const; + BOOL IsArchived() const { return FALSE; } + BOOL IsNormal() const { return !IsDirectory(); } + BOOL MatchesMask(DWORD dwMask) const; + +private: + struct Impl; + Impl* m_impl; +}; + +// --------------------------------------------------------------------------------------------- +// Archives + +class CDocument; + +class CArchive { +public: + enum Mode { store = 0, load = 1, bNoFlushOnDelete = 2, bNoByteSwap = 4 }; + CArchive(CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = nullptr); + ~CArchive(); + + BOOL IsLoading() const { return (m_nMode & load) != 0; } + BOOL IsStoring() const { return (m_nMode & load) == 0; } + BOOL IsByteSwapping() const { return FALSE; } + BOOL IsBufferEmpty() const; + CFile* GetFile() const { return m_pFile; } + UINT GetObjectSchema() { return m_nObjectSchema; } + void SetObjectSchema(UINT nSchema) { m_nObjectSchema = nSchema; } + void Close(); + void Abort() { m_pFile = nullptr; } + void Flush() {} + UINT Read(void* lpBuf, UINT nMax); + void Write(const void* lpBuf, UINT nMax); + BOOL ReadString(CString& rString); + char* ReadString(char* lpsz, UINT nMax); + void WriteString(const char* lpsz); + UINT ReadCount(); + void WriteCount(UINT dwCount); + CObject* ReadObject(const CRuntimeClass* pClass); + void WriteObject(const CObject* pOb); + CRuntimeClass* ReadClass(const CRuntimeClass* pClassRefRequested = nullptr, UINT* pSchema = nullptr, + DWORD* pObTag = nullptr); + void WriteClass(const CRuntimeClass* pClassRef); + void SerializeClass(const CRuntimeClass* pClassRef); + + CArchive& operator<<(BYTE by) { Write(&by, sizeof by); return *this; } + CArchive& operator<<(WORD w) { Write(&w, sizeof w); return *this; } + CArchive& operator<<(LONG l) { Write(&l, sizeof l); return *this; } + CArchive& operator<<(DWORD dw) { Write(&dw, sizeof dw); return *this; } + CArchive& operator<<(float f) { Write(&f, sizeof f); return *this; } + CArchive& operator<<(double d) { Write(&d, sizeof d); return *this; } + CArchive& operator<<(LONGLONG d) { Write(&d, sizeof d); return *this; } + CArchive& operator<<(ULONGLONG d) { Write(&d, sizeof d); return *this; } + CArchive& operator<<(short w) { return *this << static_cast(w); } + CArchive& operator<<(char ch) { return *this << static_cast(ch); } + CArchive& operator<<(bool b) { return *this << static_cast(b ? 1 : 0); } + CArchive& operator<<(long l) { return *this << static_cast(l); } + CArchive& operator<<(unsigned long l) { return *this << static_cast(l); } + CArchive& operator<<(const CString& s); + CArchive& operator<<(const CObject* pOb) { WriteObject(pOb); return *this; } + + CArchive& operator>>(BYTE& by) { Read(&by, sizeof by); return *this; } + CArchive& operator>>(WORD& w) { Read(&w, sizeof w); return *this; } + CArchive& operator>>(DWORD& dw) { Read(&dw, sizeof dw); return *this; } + CArchive& operator>>(LONG& l) { Read(&l, sizeof l); return *this; } + CArchive& operator>>(float& f) { Read(&f, sizeof f); return *this; } + CArchive& operator>>(double& d) { Read(&d, sizeof d); return *this; } + CArchive& operator>>(LONGLONG& d) { Read(&d, sizeof d); return *this; } + CArchive& operator>>(ULONGLONG& d) { Read(&d, sizeof d); return *this; } + CArchive& operator>>(short& w) { WORD v; *this >> v; w = static_cast(v); return *this; } + CArchive& operator>>(char& ch) { BYTE v; *this >> v; ch = static_cast(v); return *this; } + CArchive& operator>>(bool& b) { BYTE v; *this >> v; b = v != 0; return *this; } + CArchive& operator>>(long& l) { LONG v; *this >> v; l = v; return *this; } + CArchive& operator>>(unsigned long& l) { DWORD v; *this >> v; l = v; return *this; } + CArchive& operator>>(CString& s); + CArchive& operator>>(CObject*& pOb) { pOb = ReadObject(nullptr); return *this; } + + CDocument* m_pDocument; + CString m_strFileName; + +private: + CFile* m_pFile; + UINT m_nMode; + UINT m_nObjectSchema; + std::vector m_loadClasses; + std::vector m_loadObjects; + std::map m_storeClasses; + std::map m_storeObjects; +}; + +// --------------------------------------------------------------------------------------------- +// Time + +class CTimeSpan { +public: + CTimeSpan() : m_span(0) {} + CTimeSpan(time_t span) : m_span(span) {} + CTimeSpan(LONG lDays, int nHours, int nMins, int nSecs) + : m_span(((static_cast(lDays) * 24 + nHours) * 60 + nMins) * 60 + nSecs) {} + LONGLONG GetDays() const { return m_span / (24 * 3600); } + LONGLONG GetTotalHours() const { return m_span / 3600; } + LONG GetHours() const { return static_cast(GetTotalHours() - GetDays() * 24); } + LONGLONG GetTotalMinutes() const { return m_span / 60; } + LONG GetMinutes() const { return static_cast(GetTotalMinutes() - GetTotalHours() * 60); } + LONGLONG GetTotalSeconds() const { return m_span; } + LONG GetSeconds() const { return static_cast(GetTotalSeconds() - GetTotalMinutes() * 60); } + time_t GetTimeSpan() const { return m_span; } + CString Format(const char* pFormat) const; + CTimeSpan operator+(CTimeSpan s) const { return CTimeSpan(m_span + s.m_span); } + CTimeSpan operator-(CTimeSpan s) const { return CTimeSpan(m_span - s.m_span); } + CTimeSpan& operator+=(CTimeSpan s) { m_span += s.m_span; return *this; } + CTimeSpan& operator-=(CTimeSpan s) { m_span -= s.m_span; return *this; } + bool operator==(CTimeSpan s) const { return m_span == s.m_span; } + bool operator!=(CTimeSpan s) const { return m_span != s.m_span; } + bool operator<(CTimeSpan s) const { return m_span < s.m_span; } + bool operator>(CTimeSpan s) const { return m_span > s.m_span; } + bool operator<=(CTimeSpan s) const { return m_span <= s.m_span; } + bool operator>=(CTimeSpan s) const { return m_span >= s.m_span; } + +private: + time_t m_span; +}; + +class CTime { +public: + CTime() : m_time(0) {} + CTime(time_t t) : m_time(t) {} + CTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, int nDST = -1); + CTime(const SYSTEMTIME& st, int nDST = -1); + CTime(const FILETIME& ft, int nDST = -1); + static CTime GetCurrentTime(); + time_t GetTime() const { return m_time; } + struct tm* GetLocalTm(struct tm* ptm) const; + struct tm* GetGmtTm(struct tm* ptm) const; + BOOL GetAsSystemTime(SYSTEMTIME& st) const; + int GetYear() const; + int GetMonth() const; + int GetDay() const; + int GetHour() const; + int GetMinute() const; + int GetSecond() const; + int GetDayOfWeek() const; + CString Format(const char* pFormat) const; + CString Format(UINT nFormatID) const; + CString FormatGmt(const char* pFormat) const; + CTimeSpan operator-(CTime t) const { return CTimeSpan(m_time - t.m_time); } + CTime operator-(CTimeSpan s) const { return CTime(m_time - s.GetTimeSpan()); } + CTime operator+(CTimeSpan s) const { return CTime(m_time + s.GetTimeSpan()); } + CTime& operator+=(CTimeSpan s) { m_time += s.GetTimeSpan(); return *this; } + CTime& operator-=(CTimeSpan s) { m_time -= s.GetTimeSpan(); return *this; } + bool operator==(CTime t) const { return m_time == t.m_time; } + bool operator!=(CTime t) const { return m_time != t.m_time; } + bool operator<(CTime t) const { return m_time < t.m_time; } + bool operator>(CTime t) const { return m_time > t.m_time; } + bool operator<=(CTime t) const { return m_time <= t.m_time; } + bool operator>=(CTime t) const { return m_time >= t.m_time; } + +private: + time_t m_time; +}; + +// File APIs accept Windows-style paths; see mfcwx::NativePath. +extern "C" FILE* mfcwx_fopen(const char* name, const char* mode); +extern "C" int mfcwx_rename(const char* from, const char* to); +extern "C" int mfcwx_unlink(const char* name); +inline int mfcwx_remove(const char* name) { return mfcwx_unlink(name); } +namespace std { +using ::mfcwx_fopen; +using ::mfcwx_remove; +using ::mfcwx_rename; +template +It mfcwx_remove(It first, It last, const T& value) { return (std::remove)(first, last, value); } +} +#define fopen mfcwx_fopen +#define rename mfcwx_rename +#define remove(...) mfcwx_remove(__VA_ARGS__) + +#include "mfcwx/geometry.h" +#include "mfcwx/collections.h" +#include "mfcwx/fstreamcompat.h" + +#endif // __cplusplus diff --git a/port/mfcwx/include/afxadv.h b/port/mfcwx/include/afxadv.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxadv.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxcmn.h b/port/mfcwx/include/afxcmn.h new file mode 100644 index 000000000..7c7375fe6 --- /dev/null +++ b/port/mfcwx/include/afxcmn.h @@ -0,0 +1,319 @@ +#pragma once +#define __AFXCMN_H__ + +// MFC common controls. Like the basic controls these classes carry no data and operate on m_hWnd. + +#include "afxwin.h" + +class CImageList : public CObject { + DECLARE_DYNCREATE(CImageList) +public: + CImageList(); + ~CImageList() override; + HIMAGELIST m_hImageList; + operator HIMAGELIST() const { return AfxIsNullThis(this) ? nullptr : m_hImageList; } + BOOL Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow); + BOOL Create(UINT nBitmapID, int cx, int nGrow, COLORREF crMask); + BOOL DeleteImageList(); + int Add(CBitmap* pbmImage, CBitmap* pbmMask); + int Add(CBitmap* pbmImage, COLORREF crMask); + int Add(HICON hIcon); + int GetImageCount() const; + BOOL Draw(CDC* pDC, int nImage, POINT pt, UINT nStyle); +}; +#define ILC_MASK 0x0001 +#define ILC_COLOR 0x0000 +#define ILC_COLOR4 0x0004 +#define ILC_COLOR8 0x0008 +#define ILC_COLOR16 0x0010 +#define ILC_COLOR24 0x0018 +#define ILC_COLOR32 0x0020 +#define ILD_NORMAL 0x0000 +#define ILD_TRANSPARENT 0x0001 + +class CProgressCtrl : public CWnd { + DECLARE_DYNAMIC(CProgressCtrl) +public: + CProgressCtrl() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + void SetRange(short nLower, short nUpper); + void SetRange32(int nLower, int nUpper); + void GetRange(int& nLower, int& nUpper) const; + int GetPos() const; + int SetPos(int nPos); + int OffsetPos(int nPos); + int SetStep(int nStep); + int StepIt(); + COLORREF SetBkColor(COLORREF clrNew); + COLORREF SetBarColor(COLORREF clrBar); + BOOL SetMarquee(BOOL fMarqueeMode, int nInterval); +}; + +class CSliderCtrl : public CWnd { + DECLARE_DYNAMIC(CSliderCtrl) +public: + CSliderCtrl() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + int GetLineSize() const; + int SetLineSize(int nSize); + int GetPageSize() const; + int SetPageSize(int nSize); + int GetRangeMax() const; + int GetRangeMin() const; + void GetRange(int& nMin, int& nMax) const; + void SetRangeMin(int nMin, BOOL bRedraw = FALSE); + void SetRangeMax(int nMax, BOOL bRedraw = FALSE); + void SetRange(int nMin, int nMax, BOOL bRedraw = FALSE); + void GetSelection(int& nMin, int& nMax) const; + void SetSelection(int nMin, int nMax); + void GetChannelRect(LPRECT lprc) const; + void GetThumbRect(LPRECT lprc) const; + int GetPos() const; + void SetPos(int nPos); + UINT GetNumTics() const; + int GetTic(int nTic) const; + BOOL SetTic(int nTic); + void SetTicFreq(int nFreq); + void ClearSel(BOOL bRedraw = FALSE); + void ClearTics(BOOL bRedraw = FALSE); +}; + +struct UDACCEL { + UINT nSec; + UINT nInc; +}; + +class CSpinButtonCtrl : public CWnd { + DECLARE_DYNAMIC(CSpinButtonCtrl) +public: + CSpinButtonCtrl() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + BOOL SetAccel(int nAccel, UDACCEL* pAccel); + UINT GetAccel(int nAccel, UDACCEL* pAccel) const; + int SetBase(int nBase); + UINT GetBase() const; + CWnd* SetBuddy(CWnd* pWndBuddy); + CWnd* GetBuddy() const; + int SetPos(int nPos); + int GetPos() const; + int SetPos32(int nPos) { return SetPos(nPos); } + int GetPos32(BOOL* lpbError = nullptr) const; + void SetRange(short nLower, short nUpper); + void SetRange32(int nLower, int nUpper); + DWORD GetRange() const; + void GetRange(int& lower, int& upper) const; + void GetRange32(int& lower, int& upper) const { GetRange(lower, upper); } +}; + +class CHeaderCtrl : public CWnd { + DECLARE_DYNAMIC(CHeaderCtrl) +public: + CHeaderCtrl() = default; + int GetItemCount() const; +}; + +class CListCtrl : public CWnd { + DECLARE_DYNAMIC(CListCtrl) +public: + CListCtrl() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + COLORREF GetBkColor() const; + BOOL SetBkColor(COLORREF cr); + COLORREF GetTextColor() const; + BOOL SetTextColor(COLORREF cr); + COLORREF GetTextBkColor() const; + BOOL SetTextBkColor(COLORREF cr); + CImageList* GetImageList(int nImageList) const; + CImageList* SetImageList(CImageList* pImageList, int nImageListType); + int GetItemCount() const; + BOOL GetItem(LVITEM* pItem) const; + BOOL SetItem(const LVITEM* pItem); + BOOL SetItem(int nItem, int nSubItem, UINT nMask, const char* lpszItem, int nImage, UINT nState, UINT nStateMask, + LPARAM lParam); + UINT GetCallbackMask() const { return 0; } + BOOL SetCallbackMask(UINT) { return TRUE; } + int GetNextItem(int nItem, int nFlags) const; + POSITION GetFirstSelectedItemPosition() const; + int GetNextSelectedItem(POSITION& pos) const; + BOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const; + BOOL GetSubItemRect(int iItem, int iSubItem, int nArea, CRect& ref); + BOOL SetItemPosition(int, POINT) { return TRUE; } + BOOL GetItemPosition(int nItem, LPPOINT lpPoint) const; + int GetStringWidth(const char* lpsz) const; + CEdit* GetEditControl() const { return nullptr; } + BOOL GetColumn(int nCol, LVCOLUMN* pColumn) const; + BOOL SetColumn(int nCol, const LVCOLUMN* pColumn); + int GetColumnWidth(int nCol) const; + BOOL SetColumnWidth(int nCol, int cx); + BOOL GetViewRect(LPRECT lpRect) const; + int GetTopIndex() const; + int GetCountPerPage() const; + BOOL GetOrigin(LPPOINT lpPoint) const; + BOOL SetItemState(int nItem, LVITEM* pItem); + BOOL SetItemState(int nItem, UINT nState, UINT nMask); + UINT GetItemState(int nItem, UINT nMask) const; + CString GetItemText(int nItem, int nSubItem) const; + int GetItemText(int nItem, int nSubItem, char* lpszText, int nLen) const; + BOOL SetItemText(int nItem, int nSubItem, const char* lpszText); + void SetItemCount(int nItems); + BOOL SetItemData(int nItem, DWORD_PTR dwData); + DWORD_PTR GetItemData(int nItem) const; + UINT GetSelectedCount() const; + int GetSelectionMark() const; + int SetSelectionMark(int iIndex); + DWORD GetExtendedStyle() const; + DWORD SetExtendedStyle(DWORD dwNewStyle); + CHeaderCtrl* GetHeaderCtrl() const; + int GetHotItem() const { return -1; } + int InsertItem(const LVITEM* pItem); + int InsertItem(int nItem, const char* lpszItem); + int InsertItem(int nItem, const char* lpszItem, int nImage); + int InsertItem(UINT nMask, int nItem, const char* lpszItem, UINT nState, UINT nStateMask, int nImage, + LPARAM lParam); + BOOL DeleteItem(int nItem); + BOOL DeleteAllItems(); + int FindItem(LVFINDINFO* pFindInfo, int nStart = -1) const; + int HitTest(LVHITTESTINFO* pHitTestInfo) const; + int HitTest(CPoint pt, UINT* pFlags = nullptr) const; + int SubItemHitTest(LVHITTESTINFO* pInfo); + BOOL EnsureVisible(int nItem, BOOL bPartialOK); + BOOL Scroll(CSize size); + BOOL RedrawItems(int nFirst, int nLast); + BOOL Arrange(UINT) { return TRUE; } + CEdit* EditLabel(int) { return nullptr; } + int InsertColumn(int nCol, const LVCOLUMN* pColumn); + int InsertColumn(int nCol, const char* lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, + int nSubItem = -1); + BOOL DeleteColumn(int nCol); + BOOL Update(int nItem); + BOOL SortItems(int (*pfnCompare)(LPARAM, LPARAM, LPARAM), DWORD_PTR dwData); + BOOL GetCheck(int nItem) const; + BOOL SetCheck(int nItem, BOOL fCheck = TRUE); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); +}; + +class CTreeCtrl : public CWnd { + DECLARE_DYNAMIC(CTreeCtrl) +public: + CTreeCtrl() = default; +}; + +class CTabCtrl : public CWnd { + DECLARE_DYNAMIC(CTabCtrl) +public: + CTabCtrl() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + CImageList* GetImageList() const { return nullptr; } + CImageList* SetImageList(CImageList*) { return nullptr; } + int GetItemCount() const; + BOOL GetItem(int nItem, TCITEM* pTabCtrlItem) const; + BOOL SetItem(int nItem, TCITEM* pTabCtrlItem); + BOOL GetItemRect(int nItem, LPRECT lpRect) const; + int GetCurSel() const; + int SetCurSel(int nItem); + void SetCurFocus(int nItem); + CSize SetItemSize(CSize size); + void SetPadding(CSize) {} + int GetRowCount() const { return 1; } + int GetCurFocus() const { return GetCurSel(); } + LONG InsertItem(int nItem, TCITEM* pTabCtrlItem); + LONG InsertItem(int nItem, const char* lpszItem); + LONG InsertItem(int nItem, const char* lpszItem, int nImage); + BOOL DeleteItem(int nItem); + BOOL DeleteAllItems(); + void AdjustRect(BOOL bLarger, LPRECT lpRect); + DWORD GetExtendedStyle() { return 0; } + DWORD SetExtendedStyle(DWORD, DWORD = 0) { return 0; } + int HitTest(void*) const { return -1; } +}; + +#define LPSTR_TEXTCALLBACK ((LPSTR)-1L) + +class CToolTipCtrl : public CWnd { + DECLARE_DYNAMIC(CToolTipCtrl) +public: + CToolTipCtrl() = default; + BOOL Create(CWnd* pParentWnd, DWORD dwStyle = 0); + BOOL AddTool(CWnd* pWnd, UINT nIDText, LPCRECT lpRectTool = nullptr, UINT_PTR nIDTool = 0); + BOOL AddTool(CWnd* pWnd, const char* lpszText = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = nullptr, + UINT_PTR nIDTool = 0); + void DelTool(CWnd* pWnd, UINT_PTR nIDTool = 0); + void UpdateTipText(const char* lpszText, CWnd* pWnd, UINT_PTR nIDTool = 0); + void UpdateTipText(UINT nIDText, CWnd* pWnd, UINT_PTR nIDTool = 0); + void RelayEvent(LPMSG lpMsg); + void Activate(BOOL bActivate); + void SetDelayTime(UINT nDelay); + void SetDelayTime(DWORD dwDuration, int iTime); + int SetMaxTipWidth(int iWidth); + void SetTipBkColor(COLORREF) {} + void SetTipTextColor(COLORREF) {} + int GetToolCount() const; + void Pop() {} + void Update() {} +}; +#define TTDT_AUTOMATIC 0 +#define TTDT_RESHOW 1 +#define TTDT_AUTOPOP 2 +#define TTDT_INITIAL 3 +#define TTF_IDISHWND 0x0001 +#define TTF_CENTERTIP 0x0002 +#define TTF_SUBCLASS 0x0010 + +class CRichEditCtrl : public CWnd { + DECLARE_DYNAMIC(CRichEditCtrl) +public: + CRichEditCtrl() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + BOOL CanUndo() const; + BOOL CanRedo() const; + int GetLineCount() const; + BOOL GetModify() const; + void SetModify(BOOL bModified = TRUE); + void GetRect(LPRECT lpRect) const; + CPoint GetCharPos(long lChar) const; + void SetOptions(WORD, DWORD) {} + int GetLine(int nIndex, char* lpszBuffer) const; + int GetLine(int nIndex, char* lpszBuffer, int nMaxLength) const; + BOOL CanPaste(UINT nFormat = 0) const; + void GetSel(long& nStartChar, long& nEndChar) const; + void GetSel(CHARRANGE& cr) const; + void LimitText(long nChars = 0); + long LineFromChar(long nIndex) const; + void SetSel(long nStartChar, long nEndChar); + void SetSel(CHARRANGE& cr); + DWORD GetDefaultCharFormat(CHARFORMAT& cf) const; + DWORD GetSelectionCharFormat(CHARFORMAT& cf) const; + long GetEventMask() const { return 0; } + long GetLimitText() const; + DWORD GetParaFormat(PARAFORMAT& pf) const; + long GetSelText(char* lpBuf) const; + CString GetSelText() const; + WORD GetSelectionType() const; + COLORREF SetBackgroundColor(BOOL bSysColor, COLORREF cr); + BOOL SetDefaultCharFormat(CHARFORMAT& cf); + BOOL SetSelectionCharFormat(CHARFORMAT& cf); + BOOL SetWordCharFormat(CHARFORMAT& cf); + DWORD SetEventMask(DWORD dwEventMask) { return dwEventMask; } + BOOL SetParaFormat(PARAFORMAT& pf); + BOOL SetReadOnly(BOOL bReadOnly = TRUE); + void SetTargetDevice(HDC, long) {} + long GetTextLength() const; + long GetTextLengthEx(DWORD, UINT = 1200) const { return GetTextLength(); } + BOOL SetAutoURLDetect(BOOL = TRUE) { return TRUE; } + void EmptyUndoBuffer(); + int LineIndex(int nLine = -1) const; + int LineLength(int nLine = -1) const; + void LineScroll(int nLines, int nChars = 0); + void ReplaceSel(const char* lpszNewText, BOOL bCanUndo = FALSE); + long StreamIn(int nFormat, EDITSTREAM& es); + long StreamOut(int nFormat, EDITSTREAM& es); + long FindText(DWORD dwFlags, FINDTEXTEX* pFindText) const; + BOOL Undo(); + BOOL Redo(); + void Clear(); + void Copy(); + void Cut(); + void Paste(); + int GetFirstVisibleLine() const; + void HideSelection(BOOL, BOOL) {} +}; diff --git a/port/mfcwx/include/afxcoll.h b/port/mfcwx/include/afxcoll.h new file mode 100644 index 000000000..05e081c1b --- /dev/null +++ b/port/mfcwx/include/afxcoll.h @@ -0,0 +1,2 @@ +#pragma once +#include "afx.h" diff --git a/port/mfcwx/include/afxconv.h b/port/mfcwx/include/afxconv.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxconv.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxcview.h b/port/mfcwx/include/afxcview.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxcview.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxdb.h b/port/mfcwx/include/afxdb.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxdb.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxdhtml.h b/port/mfcwx/include/afxdhtml.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxdhtml.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxdisp.h b/port/mfcwx/include/afxdisp.h new file mode 100644 index 000000000..17582187c --- /dev/null +++ b/port/mfcwx/include/afxdisp.h @@ -0,0 +1,3 @@ +#pragma once +#define __AFXDISP_H__ +#include "afxwin.h" diff --git a/port/mfcwx/include/afxdlgs.h b/port/mfcwx/include/afxdlgs.h new file mode 100644 index 000000000..f4c909a92 --- /dev/null +++ b/port/mfcwx/include/afxdlgs.h @@ -0,0 +1,197 @@ +#pragma once +#define __AFXDLGS_H__ + +#include "afxwin.h" + +#include + +class CCommonDialog : public CDialog { + DECLARE_DYNAMIC(CCommonDialog) +public: + explicit CCommonDialog(CWnd* pParentWnd) : CDialog(static_cast(0), pParentWnd) {} +}; + +class CFileDialog : public CCommonDialog { + DECLARE_DYNAMIC(CFileDialog) +public: + explicit CFileDialog(BOOL bOpenFileDialog, const char* lpszDefExt = nullptr, const char* lpszFileName = nullptr, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, const char* lpszFilter = nullptr, + CWnd* pParentWnd = nullptr, DWORD dwSize = 0, BOOL bVistaStyle = TRUE); + INT_PTR DoModal() override; + CString GetPathName() const; + CString GetFileName() const; + CString GetFileExt() const; + CString GetFileTitle() const; + CString GetFolderPath() const; + BOOL GetReadOnlyPref() const { return FALSE; } + POSITION GetStartPosition() const; + CString GetNextPathName(POSITION& pos) const; + OPENFILENAME& GetOFN() { return m_ofn; } + + OPENFILENAME m_ofn; + BOOL m_bOpenFileDialog; + CString m_strFilter; + CString m_strDefExt; + CString m_strTitle; + CString m_strInitialDir; + char m_szFileName[4096]; + char m_szFileTitle[260]; + std::vector m_paths; +}; + +class CColorDialog : public CCommonDialog { + DECLARE_DYNAMIC(CColorDialog) +public: + explicit CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = nullptr); + INT_PTR DoModal() override; + COLORREF GetColor() const { return m_cc.rgbResult; } + void SetCurrentColor(COLORREF clr) { m_cc.rgbResult = clr; } + CHOOSECOLOR m_cc; +}; + +typedef struct tagCHOOSEFONTA { + DWORD lStructSize; + HWND hwndOwner; + HDC hDC; + LPLOGFONT lpLogFont; + INT iPointSize; + DWORD Flags; + COLORREF rgbColors; + LPARAM lCustData; + LPVOID lpfnHook; + LPCSTR lpTemplateName; + HINSTANCE hInstance; + LPSTR lpszStyle; + WORD nFontType; + INT nSizeMin; + INT nSizeMax; +} CHOOSEFONT, *LPCHOOSEFONT; +#define CF_SCREENFONTS 0x00000001 +#define CF_PRINTERFONTS 0x00000002 +#define CF_BOTH (CF_SCREENFONTS | CF_PRINTERFONTS) +#define CF_EFFECTS 0x00000100L +#define CF_INITTOLOGFONTSTRUCT 0x00000040L +#define CF_FIXEDPITCHONLY 0x00004000L +#define CF_NOVERTFONTS 0x01000000L + +class CFontDialog : public CCommonDialog { + DECLARE_DYNAMIC(CFontDialog) +public: + explicit CFontDialog(LPLOGFONT lplfInitial = nullptr, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, + CDC* pdcPrinter = nullptr, CWnd* pParentWnd = nullptr); + INT_PTR DoModal() override; + void GetCurrentFont(LPLOGFONT lplf); + CString GetFaceName() const; + int GetSize() const; + COLORREF GetColor() const { return m_cf.rgbColors; } + int GetWeight() const { return m_lf.lfWeight; } + BOOL IsItalic() const { return m_lf.lfItalic; } + BOOL IsUnderline() const { return m_lf.lfUnderline; } + BOOL IsStrikeOut() const { return m_lf.lfStrikeOut; } + BOOL IsBold() const { return m_lf.lfWeight >= FW_SEMIBOLD; } + CHOOSEFONT m_cf; + LOGFONT m_lf; +}; + +typedef struct tagPSDA { + DWORD lStructSize; + HWND hwndOwner; + HGLOBAL hDevMode, hDevNames; + DWORD Flags; + POINT ptPaperSize; + RECT rtMinMargin, rtMargin; +} PAGESETUPDLG; +#define PSD_INTHOUSANDTHSOFINCHES 0x00000004 +#define PSD_INHUNDREDTHSOFMILLIMETERS 0x00000008 +#define PSD_MARGINS 0x00000002 + +class CPageSetupDialog : public CCommonDialog { + DECLARE_DYNAMIC(CPageSetupDialog) +public: + explicit CPageSetupDialog(DWORD dwFlags = 0, CWnd* pParentWnd = nullptr); + INT_PTR DoModal() override; + CSize GetPaperSize() const; + void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const; + PAGESETUPDLG m_psd; +}; + +class CPrintDialog : public CCommonDialog { + DECLARE_DYNAMIC(CPrintDialog) +public: + explicit CPrintDialog(BOOL bPrintSetupOnly, DWORD dwFlags = 0, CWnd* pParentWnd = nullptr); + INT_PTR DoModal() override; + PRINTDLG m_pd; + HDC GetPrinterDC() const { return nullptr; } + HDC CreatePrinterDC() { return nullptr; } + CString GetDeviceName() const { return CString(); } + BOOL PrintSelection() const; + BOOL PrintRange() const; + BOOL PrintAll() const; + int GetFromPage() const; + int GetToPage() const; +}; + +#define FR_DOWN 0x00000001 +#define FR_WHOLEWORD 0x00000002 +#define FR_MATCHCASE 0x00000004 +#define FR_FINDNEXT 0x00000008 +#define FR_REPLACE 0x00000010 +#define FR_REPLACEALL 0x00000020 +#define FR_DIALOGTERM 0x00000040 +#define FINDMSGSTRING "commdlg_FindReplace" + +class CFindReplaceDialog : public CCommonDialog { + DECLARE_DYNAMIC(CFindReplaceDialog) +public: + CFindReplaceDialog(); + BOOL Create(BOOL bFindDialogOnly, const char* lpszFindWhat, const char* lpszReplaceWith = nullptr, + DWORD dwFlags = FR_DOWN, CWnd* pParentWnd = nullptr); + static CFindReplaceDialog* GetNotifier(LPARAM lParam); + CString GetReplaceString() const { return m_replace; } + CString GetFindString() const { return m_find; } + BOOL SearchDown() const { return (m_flags & FR_DOWN) != 0; } + BOOL FindNext() const { return (m_flags & FR_FINDNEXT) != 0; } + BOOL MatchCase() const { return (m_flags & FR_MATCHCASE) != 0; } + BOOL MatchWholeWord() const { return (m_flags & FR_WHOLEWORD) != 0; } + BOOL ReplaceCurrent() const { return (m_flags & FR_REPLACE) != 0; } + BOOL ReplaceAll() const { return (m_flags & FR_REPLACEALL) != 0; } + BOOL IsTerminating() const { return (m_flags & FR_DIALOGTERM) != 0; } + CString m_find; + CString m_replace; + DWORD m_flags; +}; + +class CPropertyPage : public CDialog { + DECLARE_DYNAMIC(CPropertyPage) +public: + CPropertyPage(); + explicit CPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0, DWORD dwSize = 0); + void SetModified(BOOL = TRUE) {} + virtual BOOL OnSetActive() { return TRUE; } + virtual BOOL OnKillActive() { return UpdateData(TRUE); } + virtual BOOL OnApply() { return TRUE; } + virtual void OnReset() {} + void OnOK() override {} + void OnCancel() override {} + CString m_strCaption; +}; + +class CPropertySheet : public CWnd { + DECLARE_DYNAMIC(CPropertySheet) +public: + CPropertySheet(); + explicit CPropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + explicit CPropertySheet(const char* pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + void AddPage(CPropertyPage* pPage); + void RemovePage(CPropertyPage* pPage); + int GetPageCount() const { return static_cast(m_pages.size()); } + CPropertyPage* GetPage(int nPage) const { return m_pages[static_cast(nPage)]; } + int GetActiveIndex() const { return m_active; } + BOOL SetActivePage(int nPage); + void SetTitle(const char* lpszText, UINT = 0) { m_strCaption = lpszText; } + virtual INT_PTR DoModal(); + std::vector m_pages; + CString m_strCaption; + CWnd* m_pParentWnd; + int m_active; +}; diff --git a/port/mfcwx/include/afxdtctl.h b/port/mfcwx/include/afxdtctl.h new file mode 100644 index 000000000..cf6cec0e8 --- /dev/null +++ b/port/mfcwx/include/afxdtctl.h @@ -0,0 +1,3 @@ +#pragma once +#define __AFXDTCTL_H__ +#include "afxwin.h" diff --git a/port/mfcwx/include/afxext.h b/port/mfcwx/include/afxext.h new file mode 100644 index 000000000..7d76748d6 --- /dev/null +++ b/port/mfcwx/include/afxext.h @@ -0,0 +1,41 @@ +#pragma once +#define __AFXEXT_H__ + +#include "afxwin.h" +#include "afxdlgs.h" + +class CBitmapButton : public CButton { + DECLARE_DYNAMIC(CBitmapButton) +public: + CBitmapButton() = default; + CBitmapButton(const CBitmapButton&) = delete; + BOOL LoadBitmaps(const char* lpszBitmapResource, const char* lpszBitmapResourceSel = nullptr, + const char* lpszBitmapResourceFocus = nullptr, const char* lpszBitmapResourceDisabled = nullptr); + BOOL LoadBitmaps(UINT nIDBitmapResource, UINT nIDBitmapResourceSel = 0, UINT nIDBitmapResourceFocus = 0, + UINT nIDBitmapResourceDisabled = 0); + BOOL AutoLoad(UINT nID, CWnd* pParent); + void SizeToContent(); + void DrawItem(LPDRAWITEMSTRUCT lpDIS) override; + + CBitmap m_bitmap; + CBitmap m_bitmapSel; + CBitmap m_bitmapFocus; + CBitmap m_bitmapDisabled; +}; + +class CFormView : public CScrollView { + DECLARE_DYNAMIC(CFormView) +public: + explicit CFormView(UINT nIDTemplate); + explicit CFormView(const char* lpszTemplateName); + void OnDraw(CDC*) override {} + void OnInitialUpdate() override; + UINT m_nIDTemplate; +}; + +class CSplitterWnd : public CWnd { +public: + BOOL CreateStatic(CWnd*, int, int, DWORD = WS_CHILD | WS_VISIBLE, UINT = AFX_IDW_PANE_FIRST) { return FALSE; } + BOOL CreateView(int, int, CRuntimeClass*, SIZE, CCreateContext*) { return FALSE; } + CWnd* GetPane(int, int) const { return nullptr; } +}; diff --git a/port/mfcwx/include/afxinet.h b/port/mfcwx/include/afxinet.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxinet.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxmt.h b/port/mfcwx/include/afxmt.h new file mode 100644 index 000000000..bf98e059f --- /dev/null +++ b/port/mfcwx/include/afxmt.h @@ -0,0 +1,81 @@ +#pragma once +#define __AFXMT_H__ + +#include "afxwin.h" + +class CSyncObject : public CObject { + DECLARE_DYNAMIC(CSyncObject) +public: + explicit CSyncObject(const char* pstrName = nullptr); + ~CSyncObject() override; + virtual BOOL Lock(DWORD dwTimeout = INFINITE); + virtual BOOL Unlock() = 0; + virtual BOOL Unlock(LONG, LPLONG = nullptr) { return TRUE; } + operator HANDLE() const { return m_hObject; } + HANDLE m_hObject; +}; + +class CCriticalSection : public CSyncObject { + DECLARE_DYNAMIC(CCriticalSection) +public: + CCriticalSection(); + ~CCriticalSection() override; + BOOL Lock() { return Lock(INFINITE); } + BOOL Lock(DWORD dwTimeout) override; + BOOL Unlock() override; + operator CRITICAL_SECTION*() { return &m_sect; } + CRITICAL_SECTION m_sect; +}; + +class CMutex : public CSyncObject { + DECLARE_DYNAMIC(CMutex) +public: + explicit CMutex(BOOL bInitiallyOwn = FALSE, const char* lpszName = nullptr, LPSECURITY_ATTRIBUTES lpsaAttribute = nullptr); + BOOL Unlock() override; +}; + +class CSemaphore : public CSyncObject { + DECLARE_DYNAMIC(CSemaphore) +public: + explicit CSemaphore(LONG lInitialCount = 1, LONG lMaxCount = 1, const char* pstrName = nullptr, + LPSECURITY_ATTRIBUTES lpsaAttributes = nullptr); + BOOL Unlock() override; + BOOL Unlock(LONG lCount, LPLONG lprevCount = nullptr) override; +}; + +class CEvent : public CSyncObject { + DECLARE_DYNAMIC(CEvent) +public: + explicit CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, const char* lpszName = nullptr, + LPSECURITY_ATTRIBUTES lpsaAttribute = nullptr); + BOOL SetEvent(); + BOOL PulseEvent(); + BOOL ResetEvent(); + BOOL Unlock() override { return TRUE; } +}; + +class CSingleLock { +public: + explicit CSingleLock(CSyncObject* pObject, BOOL bInitialLock = FALSE); + ~CSingleLock(); + BOOL Lock(DWORD dwTimeOut = INFINITE); + BOOL Unlock(); + BOOL Unlock(LONG lCount, LPLONG lPrevCount = nullptr); + BOOL IsLocked() { return m_bAcquired; } + +protected: + CSyncObject* m_pObject; + BOOL m_bAcquired; +}; + +class CMultiLock { +public: + CMultiLock(CSyncObject* ppObjects[], DWORD dwCount, BOOL bInitialLock = FALSE); + ~CMultiLock(); + DWORD Lock(DWORD dwTimeOut = INFINITE, BOOL bWaitForAll = TRUE, DWORD dwWakeMask = 0); + BOOL Unlock(); + +protected: + std::vector m_objects; + std::vector m_locked; +}; diff --git a/port/mfcwx/include/afxodlgs.h b/port/mfcwx/include/afxodlgs.h new file mode 100644 index 000000000..be0574af7 --- /dev/null +++ b/port/mfcwx/include/afxodlgs.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxdlgs.h" diff --git a/port/mfcwx/include/afxole.h b/port/mfcwx/include/afxole.h new file mode 100644 index 000000000..5a4ef9756 --- /dev/null +++ b/port/mfcwx/include/afxole.h @@ -0,0 +1,57 @@ +#pragma once +#define __AFXOLE_H__ + +#include "afxwin.h" + +#define DROPEFFECT_NONE 0 +#define DROPEFFECT_COPY 1 +#define DROPEFFECT_MOVE 2 +#define DROPEFFECT_LINK 4 +#define DROPEFFECT_SCROLL 0x80000000 +typedef DWORD DROPEFFECT; +typedef WORD CLIPFORMAT; + +class COleDataObject { +public: + COleDataObject() = default; + BOOL IsDataAvailable(CLIPFORMAT cfFormat, void* = nullptr) const; + HGLOBAL GetGlobalData(CLIPFORMAT cfFormat, void* = nullptr) const; + BOOL AttachClipboard(); + void Release() {} +}; + +class COleDataSource : public CCmdTarget { +public: + void CacheGlobalData(CLIPFORMAT cfFormat, HGLOBAL hGlobal, void* = nullptr); + DROPEFFECT DoDragDrop(DWORD = DROPEFFECT_COPY | DROPEFFECT_MOVE, LPCRECT = nullptr, void* = nullptr); + void SetClipboard(); + HGLOBAL m_data = nullptr; + CLIPFORMAT m_format = 0; +}; + +class COleDropTarget : public CCmdTarget { +public: + BOOL Register(CWnd*) { return TRUE; } + void Revoke() {} +}; + +class COleDateTime { +public: + COleDateTime() : m_dt(0), m_status(valid) {} + COleDateTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec); + static COleDateTime GetCurrentTime(); + int GetYear() const; + int GetMonth() const; + int GetDay() const; + int GetHour() const; + int GetMinute() const; + int GetSecond() const; + int GetDayOfWeek() const; + CString Format(const char* pFormat) const; + CString Format(DWORD dwFlags = 0, LCID lcid = 0) const; + enum DateTimeStatus { error = -1, valid = 0, invalid = 1, null = 2 }; + double m_dt; + DateTimeStatus m_status; +}; + +BOOL AFXAPI AfxOleInit(); diff --git a/port/mfcwx/include/afxpriv.h b/port/mfcwx/include/afxpriv.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxpriv.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxres.h b/port/mfcwx/include/afxres.h new file mode 100644 index 000000000..e0912e953 --- /dev/null +++ b/port/mfcwx/include/afxres.h @@ -0,0 +1,281 @@ +#pragma once + +/* Standard MFC resource IDs. Parsed by port/rc/rc2cpp.py. */ + +#include "mfcwx/winconst.h" + +#define IDC_STATIC (-1) + +#define ID_SEPARATOR 0 + +#define AFX_IDS_APP_TITLE 0xE000 +#define AFX_IDS_IDLEMESSAGE 0xE001 +#define AFX_IDS_HELPMODEMESSAGE 0xE002 +#define AFX_IDS_APP_TITLE_EMBEDDING 0xE003 +#define AFX_IDS_COMPANY_NAME 0xE004 +#define AFX_IDS_OBJ_TITLE_INPLACE 0xE005 + +#define ID_FILE_NEW 0xE100 +#define ID_FILE_OPEN 0xE101 +#define ID_FILE_CLOSE 0xE102 +#define ID_FILE_SAVE 0xE103 +#define ID_FILE_SAVE_AS 0xE104 +#define ID_FILE_PAGE_SETUP 0xE105 +#define ID_FILE_PRINT_SETUP 0xE106 +#define ID_FILE_PRINT 0xE107 +#define ID_FILE_PRINT_DIRECT 0xE108 +#define ID_FILE_PRINT_PREVIEW 0xE109 +#define ID_FILE_UPDATE 0xE10A +#define ID_FILE_SAVE_COPY_AS 0xE10B +#define ID_FILE_SEND_MAIL 0xE10C +#define ID_FILE_NEW_FRAME 0xE10D +#define ID_FILE_MRU_FIRST 0xE110 +#define ID_FILE_MRU_FILE1 0xE110 +#define ID_FILE_MRU_FILE2 0xE111 +#define ID_FILE_MRU_FILE3 0xE112 +#define ID_FILE_MRU_FILE4 0xE113 +#define ID_FILE_MRU_FILE5 0xE114 +#define ID_FILE_MRU_FILE6 0xE115 +#define ID_FILE_MRU_FILE7 0xE116 +#define ID_FILE_MRU_FILE8 0xE117 +#define ID_FILE_MRU_FILE9 0xE118 +#define ID_FILE_MRU_FILE10 0xE119 +#define ID_FILE_MRU_FILE11 0xE11A +#define ID_FILE_MRU_FILE12 0xE11B +#define ID_FILE_MRU_FILE13 0xE11C +#define ID_FILE_MRU_FILE14 0xE11D +#define ID_FILE_MRU_FILE15 0xE11E +#define ID_FILE_MRU_FILE16 0xE11F +#define ID_FILE_MRU_LAST 0xE11F + +#define ID_EDIT_CLEAR 0xE120 +#define ID_EDIT_CLEAR_ALL 0xE121 +#define ID_EDIT_COPY 0xE122 +#define ID_EDIT_CUT 0xE123 +#define ID_EDIT_FIND 0xE124 +#define ID_EDIT_PASTE 0xE125 +#define ID_EDIT_PASTE_LINK 0xE126 +#define ID_EDIT_PASTE_SPECIAL 0xE127 +#define ID_EDIT_REPEAT 0xE128 +#define ID_EDIT_REPLACE 0xE129 +#define ID_EDIT_SELECT_ALL 0xE12A +#define ID_EDIT_UNDO 0xE12B +#define ID_EDIT_REDO 0xE12C + +#define ID_WINDOW_NEW 0xE130 +#define ID_WINDOW_ARRANGE 0xE131 +#define ID_WINDOW_CASCADE 0xE132 +#define ID_WINDOW_TILE_HORZ 0xE133 +#define ID_WINDOW_TILE_VERT 0xE134 +#define ID_WINDOW_SPLIT 0xE135 +#define AFX_IDM_WINDOW_FIRST 0xE130 +#define AFX_IDM_WINDOW_LAST 0xE13F +#define AFX_IDM_FIRST_MDICHILD 0xFF00 + +#define ID_APP_ABOUT 0xE140 +#define ID_APP_EXIT 0xE141 +#define ID_HELP_INDEX 0xE142 +#define ID_HELP_FINDER 0xE143 +#define ID_HELP_USING 0xE144 +#define ID_CONTEXT_HELP 0xE145 +#define ID_HELP 0xE146 +#define ID_DEFAULT_HELP 0xE147 + +#define ID_NEXT_PANE 0xE150 +#define ID_PREV_PANE 0xE151 +#define ID_FORMAT_FONT 0xE160 + +#define ID_OLE_INSERT_NEW 0xE200 +#define ID_OLE_EDIT_LINKS 0xE201 +#define ID_OLE_EDIT_CONVERT 0xE202 +#define ID_OLE_EDIT_CHANGE_ICON 0xE203 +#define ID_OLE_EDIT_PROPERTIES 0xE204 +#define ID_OLE_VERB_FIRST 0xE210 + +#define AFX_ID_PREVIEW_CLOSE 0xE300 +#define AFX_ID_PREVIEW_NUMPAGE 0xE301 +#define AFX_ID_PREVIEW_NEXT 0xE302 +#define AFX_ID_PREVIEW_PREV 0xE303 +#define AFX_ID_PREVIEW_PRINT 0xE304 +#define AFX_ID_PREVIEW_ZOOMIN 0xE305 +#define AFX_ID_PREVIEW_ZOOMOUT 0xE306 + +#define ID_INDICATOR_EXT 0xE700 +#define ID_INDICATOR_CAPS 0xE701 +#define ID_INDICATOR_NUM 0xE702 +#define ID_INDICATOR_SCRL 0xE703 +#define ID_INDICATOR_OVR 0xE704 +#define ID_INDICATOR_REC 0xE705 +#define ID_INDICATOR_KANA 0xE706 + +#define ID_VIEW_TOOLBAR 0xE800 +#define ID_VIEW_STATUS_BAR 0xE801 +#define ID_VIEW_REBAR 0xE804 +#define ID_VIEW_AUTOARRANGE 0xE805 +#define ID_VIEW_SMALLICON 0xE810 +#define ID_VIEW_LARGEICON 0xE811 +#define ID_VIEW_LIST 0xE812 +#define ID_VIEW_DETAILS 0xE813 +#define ID_VIEW_LINEUP 0xE814 +#define ID_VIEW_BYNAME 0xE815 + +#define ID_RECORD_FIRST 0xE900 +#define ID_RECORD_LAST 0xE901 +#define ID_RECORD_NEXT 0xE902 +#define ID_RECORD_PREV 0xE903 + +#define AFX_IDW_CONTROLBAR_FIRST 0xE800 +#define AFX_IDW_CONTROLBAR_LAST 0xE8FF +#define AFX_IDW_TOOLBAR 0xE800 +#define AFX_IDW_STATUS_BAR 0xE801 +#define AFX_IDW_PREVIEW_BAR 0xE802 +#define AFX_IDW_RESIZE_BAR 0xE803 +#define AFX_IDW_REBAR 0xE804 +#define AFX_IDW_DIALOGBAR 0xE805 +#define AFX_IDW_DOCKBAR_TOP 0xE81B +#define AFX_IDW_DOCKBAR_LEFT 0xE81C +#define AFX_IDW_DOCKBAR_RIGHT 0xE81D +#define AFX_IDW_DOCKBAR_BOTTOM 0xE81E +#define AFX_IDW_DOCKBAR_FLOAT 0xE81F +#define AFX_IDW_PANE_FIRST 0xE900 +#define AFX_IDW_PANE_LAST 0xE9FF +#define AFX_IDW_HSCROLL_FIRST 0xEA00 +#define AFX_IDW_VSCROLL_FIRST 0xEA10 +#define AFX_IDW_SIZE_BOX 0xEA20 +#define AFX_IDW_PANE_SAVE 0xEA21 + +#define AFX_IDS_SCFIRST 0xEF00 +#define AFX_IDS_SCSIZE 0xEF00 +#define AFX_IDS_SCMOVE 0xEF01 +#define AFX_IDS_SCMINIMIZE 0xEF02 +#define AFX_IDS_SCMAXIMIZE 0xEF03 +#define AFX_IDS_SCNEXTWINDOW 0xEF04 +#define AFX_IDS_SCPREVWINDOW 0xEF05 +#define AFX_IDS_SCCLOSE 0xEF06 +#define AFX_IDS_SCRESTORE 0xEF12 +#define AFX_IDS_SCTASKLIST 0xEF13 +#define AFX_IDS_MDICHILD 0xEF1F +#define AFX_IDS_DESKACCESSORY 0xEFDA +#define AFX_IDS_OPENFILE 0xF000 +#define AFX_IDS_SAVEFILE 0xF001 +#define AFX_IDS_ALLFILTER 0xF002 +#define AFX_IDS_UNTITLED 0xF003 +#define AFX_IDS_SAVEFILECOPY 0xF004 +#define AFX_IDS_PREVIEW_CLOSE 0xF005 +#define AFX_IDS_UNNAMED_FILE 0xF006 +#define AFX_IDS_HIDE 0xF011 + +#define AFX_IDP_INVALID_FILENAME 0xF100 +#define AFX_IDP_FAILED_TO_OPEN_DOC 0xF101 +#define AFX_IDP_FAILED_TO_SAVE_DOC 0xF102 +#define AFX_IDP_ASK_TO_SAVE 0xF103 +#define AFX_IDP_FAILED_TO_CREATE_DOC 0xF104 +#define AFX_IDP_FILE_TOO_LARGE 0xF105 +#define AFX_IDP_FAILED_TO_START_PRINT 0xF106 +#define AFX_IDP_FAILED_TO_LAUNCH_HELP 0xF107 +#define AFX_IDP_INTERNAL_FAILURE 0xF108 +#define AFX_IDP_COMMAND_FAILURE 0xF109 +#define AFX_IDP_FAILED_MEMORY_ALLOC 0xF10A +#define AFX_IDP_UNREG_DONE 0xF10B +#define AFX_IDP_UNREG_FAILURE 0xF10C +#define AFX_IDP_DLL_LOAD_FAILED 0xF10D +#define AFX_IDP_DLL_BAD_VERSION 0xF10E +#define AFX_IDP_PARSE_INT 0xF110 +#define AFX_IDP_PARSE_REAL 0xF111 +#define AFX_IDP_PARSE_INT_RANGE 0xF112 +#define AFX_IDP_PARSE_REAL_RANGE 0xF113 +#define AFX_IDP_PARSE_STRING_SIZE 0xF114 +#define AFX_IDP_PARSE_RADIO_BUTTON 0xF115 +#define AFX_IDP_PARSE_BYTE 0xF116 +#define AFX_IDP_PARSE_UINT 0xF117 +#define AFX_IDP_PARSE_DATETIME 0xF118 +#define AFX_IDP_PARSE_CURRENCY 0xF119 +#define AFX_IDP_FAILED_INVALID_FORMAT 0xF120 +#define AFX_IDP_FAILED_INVALID_PATH 0xF121 +#define AFX_IDP_FAILED_DISK_FULL 0xF122 +#define AFX_IDP_FAILED_ACCESS_READ 0xF123 +#define AFX_IDP_FAILED_ACCESS_WRITE 0xF124 +#define AFX_IDP_FAILED_IO_ERROR_READ 0xF125 +#define AFX_IDP_FAILED_IO_ERROR_WRITE 0xF126 + +#define AFX_IDC_LISTBOX 100 +#define AFX_IDC_CHANGE 101 +#define AFX_IDD_FILEOPEN 28676 +#define AFX_IDD_FILESAVE 28677 +#define AFX_IDD_FONT 28678 +#define AFX_IDD_COLOR 28679 +#define AFX_IDD_PRINT 28680 +#define AFX_IDD_PRINTSETUP 28681 +#define AFX_IDD_FIND 28682 +#define AFX_IDD_REPLACE 28683 +#define AFX_IDD_NEWTYPEDLG 30721 +#define AFX_IDD_PRINTDLG 30722 +#define AFX_IDD_PREVIEW_TOOLBAR 30723 + +#define AFX_IDS_MEMORY_EXCEPTION 0xF007 +#define AFX_IDS_NOT_SUPPORTED_EXCEPTION 0xF008 +#define AFX_IDS_RESOURCE_EXCEPTION 0xF009 +#define AFX_IDS_USER_EXCEPTION 0xF00A +#define AFX_IDS_PRINTONPORT 0xF040 +#define AFX_IDS_ONEPAGE 0xF041 +#define AFX_IDS_TWOPAGE 0xF042 +#define AFX_IDS_PRINTPAGENUM 0xF043 +#define AFX_IDS_PREVIEWPAGEDESC 0xF044 +#define AFX_IDS_PRINTDEFAULTEXT 0xF045 +#define AFX_IDS_PRINTDEFAULT 0xF046 +#define AFX_IDS_PRINTFILTER 0xF047 +#define AFX_IDS_PRINTCAPTION 0xF048 +#define AFX_IDS_PRINTTOFILE 0xF049 +#define AFX_IDS_PASTELINKEDTYPE 0xF074 +#define AFX_IDS_UNKNOWNTYPE 0xF076 +#define AFX_IDS_NOT_DOCOBJECT 0xF184 +#define AFX_IDS_OCC_SCALEUNITS_PIXELS 0xF1C0 +#define AFX_IDP_NO_ERROR_AVAILABLE 0xF020 +#define AFX_IDP_FAILED_TO_NOTIFY 0xF185 +#define AFX_IDP_GET_NOT_SUPPORTED 0xF18C +#define AFX_IDP_SET_NOT_SUPPORTED 0xF18D +#define AFX_IDP_FAILED_MAPI_LOAD 0xF190 +#define AFX_IDP_INVALID_MAPI_DLL 0xF191 +#define AFX_IDP_FAILED_MAPI_SEND 0xF192 +#define AFX_IDP_FILE_NONE 0xF1A0 +#define AFX_IDP_FILE_GENERIC 0xF1A1 +#define AFX_IDP_FILE_NOT_FOUND 0xF1A2 +#define AFX_IDP_FILE_BAD_PATH 0xF1A3 +#define AFX_IDP_FILE_TOO_MANY_OPEN 0xF1A4 +#define AFX_IDP_FILE_ACCESS_DENIED 0xF1A5 +#define AFX_IDP_FILE_INVALID_FILE 0xF1A6 +#define AFX_IDP_FILE_REMOVE_CURRENT 0xF1A7 +#define AFX_IDP_FILE_DIR_FULL 0xF1A8 +#define AFX_IDP_FILE_BAD_SEEK 0xF1A9 +#define AFX_IDP_FILE_HARD_IO 0xF1AA +#define AFX_IDP_FILE_SHARING 0xF1AB +#define AFX_IDP_FILE_LOCKING 0xF1AC +#define AFX_IDP_FILE_DISKFULL 0xF1AD +#define AFX_IDP_FILE_EOF 0xF1AE +#define AFX_IDP_ARCH_NONE 0xF1B0 +#define AFX_IDP_ARCH_GENERIC 0xF1B1 +#define AFX_IDP_ARCH_READONLY 0xF1B2 +#define AFX_IDP_ARCH_ENDOFFILE 0xF1B3 +#define AFX_IDP_ARCH_WRITEONLY 0xF1B4 +#define AFX_IDP_ARCH_BADINDEX 0xF1B5 +#define AFX_IDP_ARCH_BADCLASS 0xF1B6 +#define AFX_IDP_ARCH_BADSCHEMA 0xF1B7 +#define AFX_IDC_PRINT_DOCNAME 201 +#define AFX_IDC_PRINT_PRINTERNAME 202 +#define AFX_IDC_PRINT_PORTNAME 203 +#define AFX_IDC_PRINT_PAGENUM 204 +#define AFX_IDC_CONTEXTHELP 30977 +#define AFX_IDC_MAGNIFY 30978 +#define AFX_IDC_SMALLARROWS 30979 +#define AFX_IDC_HSPLITBAR 30980 +#define AFX_IDC_VSPLITBAR 30981 +#define AFX_IDC_NODROPCRSR 30982 +#define AFX_IDC_TRACKNWSE 30983 +#define AFX_IDC_TRACKNESW 30984 +#define AFX_IDC_TRACKNS 30985 +#define AFX_IDC_TRACKWE 30986 +#define AFX_IDC_TRACK4WAY 30988 +#define AFX_IDC_MOVE4WAY 30989 +#define AFX_IDB_MINIFRAME_MENU 30994 +#define AFX_IDB_CHECKLISTBOX_NT 30995 +#define AFX_IDB_CHECKLISTBOX_95 30996 diff --git a/port/mfcwx/include/afxrich.h b/port/mfcwx/include/afxrich.h new file mode 100644 index 000000000..37b5330df --- /dev/null +++ b/port/mfcwx/include/afxrich.h @@ -0,0 +1,42 @@ +#pragma once +#define __AFXRICH_H__ + +#include "afxwin.h" +#include "afxcmn.h" +#include "afxole.h" + +class CRichEditCntrItem : public CObject { +public: + CRichEditCntrItem() = default; +}; + +class CRichEditDoc : public CDocument { + DECLARE_DYNAMIC(CRichEditDoc) +public: + CRichEditDoc(); + virtual CRichEditCntrItem* CreateClientItem(void* preo = nullptr) const; + class CRichEditView* GetView() const; + BOOL m_bRTF; + void Serialize(CArchive& ar) override; +}; + +class CRichEditView : public CView { + DECLARE_DYNCREATE(CRichEditView) +public: + CRichEditView(); + CRichEditCtrl& GetRichEditCtrl() const { return *reinterpret_cast(const_cast(this)); } + CRichEditDoc* GetDocument() const { return reinterpret_cast(m_pDocument); } + void OnDraw(CDC*) override {} + void OnInitialUpdate() override; + void Serialize(CArchive& ar) override; + long GetTextLength() const; + void SetCharFormat(CHARFORMAT2 cf); + CHARFORMAT2& GetCharFormatSelection(); + void WrapChanged() {} + afx_msg int OnCreate(LPCREATESTRUCT lpcs); + int m_nWordWrap; + enum WordWrapType { WrapNone = 0, WrapToWindow = 1, WrapToTargetDevice = 2 }; + +protected: + DECLARE_MESSAGE_MAP() +}; diff --git a/port/mfcwx/include/afxsock.h b/port/mfcwx/include/afxsock.h new file mode 100644 index 000000000..6e7e9031a --- /dev/null +++ b/port/mfcwx/include/afxsock.h @@ -0,0 +1,2 @@ +#pragma once +#include "afxwin.h" diff --git a/port/mfcwx/include/afxtempl.h b/port/mfcwx/include/afxtempl.h new file mode 100644 index 000000000..e60a537cd --- /dev/null +++ b/port/mfcwx/include/afxtempl.h @@ -0,0 +1,3 @@ +#pragma once +#define __AFXTEMPL_H__ +#include "afx.h" diff --git a/port/mfcwx/include/afxwin.h b/port/mfcwx/include/afxwin.h new file mode 100644 index 000000000..9a0acaaca --- /dev/null +++ b/port/mfcwx/include/afxwin.h @@ -0,0 +1,1264 @@ +#pragma once + +// MFC GUI subset on top of wxWidgets. +#define __AFXWIN_H__ + +#include "afx.h" +#include "afxres.h" +#include "mfcwx/msgmap.h" + +#include + +class wxWindow; +class wxDC; +class wxMenu; +class wxMenuBar; +class wxBitmap; +class wxFrame; + +class CCmdTarget; +class CWnd; +class CDC; +class CMenu; +class CCmdUI; +class CDocument; +class CView; +class CFrameWnd; +class CMDIFrameWnd; +class CMDIChildWnd; +class CDocTemplate; +class CWinApp; +class CWinThread; +class CDataExchange; +class CScrollBar; +class CGdiObject; +class CPen; +class CBrush; +class CFont; +class CBitmap; +class CRgn; +class CPalette; +class CImageList; +class CToolTipCtrl; +class CPrintInfo; +class CCreateContext; +class CPrintDialog; +class CStatusBar; +class CToolBar; +class CControlBar; +class CDialog; + +namespace mfcwx { +struct WindowState; +struct DCState; +struct GdiObjectImpl; +} + +// --------------------------------------------------------------------------------------------- +// Command targets + +class CCmdTarget : public CObject { + DECLARE_DYNAMIC(CCmdTarget) +public: + CCmdTarget() = default; + virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo); + void BeginWaitCursor(); + void EndWaitCursor(); + void RestoreWaitCursor(); + void EnableAutomation() {} + virtual void OnFinalRelease() { delete this; } + +protected: + static const AFX_MSGMAP* GetThisMessageMap(); + virtual const AFX_MSGMAP* GetMessageMap() const; + +public: + // Locates the handler for a message map entry search; used by the dispatcher. + const AFX_MSGMAP_ENTRY* FindMessageEntry(UINT nMessage, UINT nCode, UINT nID) const; + BOOL DispatchCommand(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo); +}; + +class CCmdUI { +public: + CCmdUI(); + virtual ~CCmdUI() = default; + virtual void Enable(BOOL bOn = TRUE); + virtual void SetCheck(int nCheck = 1); + virtual void SetRadio(BOOL bOn = TRUE); + virtual void SetText(const char* lpszText); + void ContinueRouting() { m_bContinueRouting = TRUE; } + BOOL DoUpdate(CCmdTarget* pTarget, BOOL bDisableIfNoHndler); + + UINT m_nID; + UINT m_nIndex; + CMenu* m_pMenu; + CMenu* m_pSubMenu; + CMenu* m_pParentMenu; + CWnd* m_pOther; + BOOL m_bEnableChanged; + BOOL m_bContinueRouting; + UINT m_nIndexMax; + + // results collected for the wx update event + bool m_enabled; + int m_check; + bool m_checkSet; + bool m_textSet; + CString m_text; +}; + +// --------------------------------------------------------------------------------------------- +// Windows + +class CWnd : public CCmdTarget { + DECLARE_DYNCREATE(CWnd) +public: + CWnd(); + ~CWnd() override; + + HWND m_hWnd; + HWND GetSafeHwnd() const { return AfxIsNullThis(this) ? nullptr : m_hWnd; } + operator HWND() const { return AfxIsNullThis(this) ? nullptr : m_hWnd; } + bool operator==(const CWnd& wnd) const { return m_hWnd == wnd.m_hWnd; } + bool operator!=(const CWnd& wnd) const { return m_hWnd != wnd.m_hWnd; } + + static CWnd* FromHandle(HWND hWnd); + static CWnd* FromHandlePermanent(HWND hWnd); + static void DeleteTempMap(); + BOOL Attach(HWND hWndNew); + HWND Detach(); + BOOL SubclassWindow(HWND hWnd); + BOOL SubclassDlgItem(UINT nID, CWnd* pParent); + HWND UnsubclassWindow(); + + // creation + virtual BOOL Create(const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, CCreateContext* pContext = nullptr); + virtual BOOL CreateEx(DWORD dwExStyle, const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle, + int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, + LPVOID lpParam = nullptr); + virtual BOOL CreateEx(DWORD dwExStyle, const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam = nullptr); + virtual BOOL DestroyWindow(); + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + virtual void PreSubclassWindow() {} + virtual void PostNcDestroy() {} + + // message handling + LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0); + BOOL PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0); + BOOL SendNotifyMessage(UINT message, WPARAM wParam, LPARAM lParam); + void SendMessageToDescendants(UINT message, WPARAM wParam = 0, LPARAM lParam = 0, BOOL bDeep = TRUE, + BOOL bOnlyPerm = FALSE); + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + LRESULT Default(); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); + virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); + BOOL ReflectChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); + virtual BOOL PreTranslateMessage(MSG* pMsg); + static const MSG* GetCurrentMessage(); + BOOL ExecuteDlgInit(const char* lpszResourceName); + BOOL ExecuteDlgInit(UINT nIDTemplate); + + // state + DWORD GetStyle() const; + DWORD GetExStyle() const; + BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0); + BOOL ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0); + int GetDlgCtrlID() const; + int SetDlgCtrlID(int nID); + CWnd* GetParent() const; + CWnd* SetParent(CWnd* pWndNewParent); + CWnd* GetOwner() const; + void SetOwner(CWnd* pOwnerWnd); + CWnd* GetParentOwner() const; + CFrameWnd* GetParentFrame() const; + CFrameWnd* GetTopLevelFrame() const; + CWnd* GetTopLevelParent() const; + CWnd* GetTopLevelOwner() const; + CWnd* GetTopWindow() const; + CWnd* GetWindow(UINT nCmd) const; + CWnd* GetNextWindow(UINT nFlag = GW_HWNDNEXT) const; + CWnd* GetLastActivePopup() const; + CWnd* GetDescendantWindow(int nID, BOOL bOnlyPerm = FALSE) const; + CWnd* ChildWindowFromPoint(POINT point) const; + static CWnd* WindowFromPoint(POINT point); + static CWnd* GetActiveWindow(); + CWnd* SetActiveWindow(); + static CWnd* GetForegroundWindow(); + BOOL SetForegroundWindow(); + static CWnd* GetFocus(); + CWnd* SetFocus(); + static CWnd* GetDesktopWindow(); + static CWnd* GetCapture(); + CWnd* SetCapture(); + static CWnd* FindWindow(const char* lpszClassName, const char* lpszWindowName); + BOOL IsChild(const CWnd* pWnd) const; + BOOL IsWindowEnabled() const; + BOOL EnableWindow(BOOL bEnable = TRUE); + BOOL IsWindowVisible() const; + BOOL ShowWindow(int nCmdShow); + BOOL IsIconic() const; + BOOL IsZoomed() const; + BOOL FlashWindow(BOOL) { return TRUE; } + void DragAcceptFiles(BOOL bAccept = TRUE); + BOOL IsDialogMessage(LPMSG) { return FALSE; } + + // text + void SetWindowText(const char* lpszString); + void SetWindowTextA(const char* lpszString) { SetWindowText(lpszString); } + int GetWindowText(char* lpszStringBuf, int nMaxCount) const; + void GetWindowText(CString& rString) const; + int GetWindowTextA(char* lpszStringBuf, int nMaxCount) const { return GetWindowText(lpszStringBuf, nMaxCount); } + void GetWindowTextA(CString& rString) const { GetWindowText(rString); } + int GetWindowTextLength() const; + void SetFont(CFont* pFont, BOOL bRedraw = TRUE); + CFont* GetFont() const; + + // geometry + void GetWindowRect(LPRECT lpRect) const; + void GetClientRect(LPRECT lpRect) const; + void ClientToScreen(LPPOINT lpPoint) const; + void ClientToScreen(LPRECT lpRect) const; + void ScreenToClient(LPPOINT lpPoint) const; + void ScreenToClient(LPRECT lpRect) const; + void MapWindowPoints(CWnd* pwndTo, LPPOINT lpPoint, UINT nCount) const; + void MapWindowPoints(CWnd* pwndTo, LPRECT lpRect) const; + void MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE); + void MoveWindow(LPCRECT lpRect, BOOL bRepaint = TRUE); + BOOL SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags); + BOOL GetWindowPlacement(WINDOWPLACEMENT* lpwndpl) const; + BOOL SetWindowPlacement(const WINDOWPLACEMENT* lpwndpl); + void CenterWindow(CWnd* pAlternateOwner = nullptr); + void BringWindowToTop(); + void CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType = 0); + void RepositionBars(UINT, UINT, UINT, UINT = 0, LPRECT = nullptr, LPCRECT = nullptr, BOOL = TRUE) {} + + // painting + CDC* GetDC(); + CDC* GetWindowDC(); + int ReleaseDC(CDC* pDC); + void Invalidate(BOOL bErase = TRUE); + void InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE); + void InvalidateRgn(CRgn* pRgn, BOOL bErase = TRUE); + void ValidateRect(LPCRECT) {} + void UpdateWindow(); + BOOL RedrawWindow(LPCRECT lpRectUpdate = nullptr, CRgn* prgnUpdate = nullptr, UINT flags = 0); + void SetRedraw(BOOL bRedraw = TRUE); + BOOL GetUpdateRect(LPRECT lpRect, BOOL bErase = FALSE); + CDC* BeginPaint(LPPAINTSTRUCT lpPaint); + void EndPaint(LPPAINTSTRUCT lpPaint); + void ScrollWindow(int xAmount, int yAmount, LPCRECT lpRect = nullptr, LPCRECT lpClipRect = nullptr); + void ShowCaret() {} + void HideCaret() {} + BOOL CreateCaret(CBitmap*) { return TRUE; } + void CreateSolidCaret(int, int) {} + void SetCaretPos(POINT) {} + static CPoint GetCaretPos(); + + // scrolling + int GetScrollPos(int nBar) const; + int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE); + void GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const; + void SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE); + BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE); + BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, UINT nMask = SIF_ALL); + int GetScrollLimit(int nBar); + void ShowScrollBar(UINT nBar, BOOL bShow = TRUE); + BOOL EnableScrollBar(int nSBFlags, UINT nArrowFlags = ESB_ENABLE_BOTH); + virtual CScrollBar* GetScrollBarCtrl(int nBar) const; + + // timers + UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse, void (*lpfnTimer)(HWND, UINT, UINT_PTR, DWORD)); + BOOL KillTimer(UINT_PTR nIDEvent); + + // dialog items + CWnd* GetDlgItem(int nID) const; + void GetDlgItem(int nID, HWND* phWnd) const; + UINT GetDlgItemInt(int nID, BOOL* lpTrans = nullptr, BOOL bSigned = TRUE) const; + void SetDlgItemInt(int nID, UINT nValue, BOOL bSigned = TRUE); + int GetDlgItemText(int nID, char* lpStr, int nMaxCount) const; + int GetDlgItemText(int nID, CString& rString) const; + void SetDlgItemText(int nID, const char* lpszString); + UINT IsDlgButtonChecked(int nIDButton) const; + void CheckDlgButton(int nIDButton, UINT nCheck); + void CheckRadioButton(int nIDFirstButton, int nIDLastButton, int nIDCheckButton); + int GetCheckedRadioButton(int nIDFirstButton, int nIDLastButton); + LRESULT SendDlgItemMessage(int nID, UINT message, WPARAM wParam = 0, LPARAM lParam = 0); + CWnd* GetNextDlgGroupItem(CWnd* pWndCtl, BOOL bPrevious = FALSE) const; + CWnd* GetNextDlgTabItem(CWnd* pWndCtl, BOOL bPrevious = FALSE) const; + BOOL UpdateData(BOOL bSaveAndValidate = TRUE); + virtual void DoDataExchange(CDataExchange* pDX); + + // menus + CMenu* GetMenu() const; + BOOL SetMenu(CMenu* pMenu); + void DrawMenuBar(); + CMenu* GetSystemMenu(BOOL bRevert) const; + + // help, icons, misc + virtual void WinHelp(DWORD_PTR dwData, UINT nCmd = HELP_CONTEXT); + virtual void HtmlHelp(DWORD_PTR dwData, UINT nCmd = 0x000F); + HICON SetIcon(HICON hIcon, BOOL bBigIcon); + HICON GetIcon(BOOL bBigIcon) const; + BOOL EnableToolTips(BOOL bEnable = TRUE); + void SetWindowContextHelpId(DWORD) {} + int MessageBox(const char* lpszText, const char* lpszCaption = nullptr, UINT nType = MB_OK); + int MessageBoxA(const char* lpszText, const char* lpszCaption = nullptr, UINT nType = MB_OK) { return MessageBox(lpszText, lpszCaption, nType); } + BOOL OpenClipboard(); + BOOL LockWindowUpdate(); + void UnlockWindowUpdate(); + LONG_PTR GetWindowLongPtr(int nIndex) const; + LONG_PTR SetWindowLongPtr(int nIndex, LONG_PTR dwNewLong); + + // default handlers + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnDestroy(); + afx_msg void OnNcDestroy(); + afx_msg void OnClose(); + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnMove(int x, int y); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnMButtonDown(UINT nFlags, CPoint point); + afx_msg void OnMButtonUp(UINT nFlags, CPoint point); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnContextMenu(CWnd* pWnd, CPoint pos); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); + afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); + afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); + afx_msg UINT OnGetDlgCode(); + afx_msg void OnDropFiles(HDROP hDropInfo); + afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); + afx_msg void OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd); + afx_msg void OnEnable(BOOL bEnable); + afx_msg BOOL OnNcActivate(BOOL bActive); + afx_msg void OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu); + afx_msg void OnSizing(UINT fwSide, LPRECT pRect); + + // implementation + wxWindow* GetWx() const { return reinterpret_cast(m_hWnd); } + static CWnd* FromWx(wxWindow* window); + void AttachWx(wxWindow* window); + +protected: + DECLARE_MESSAGE_MAP() +}; + +extern const CWnd wndTop; +extern const CWnd wndBottom; +extern const CWnd wndTopMost; +extern const CWnd wndNoTopMost; + +// --------------------------------------------------------------------------------------------- +// GDI + +class CGdiObject : public CObject { + DECLARE_DYNCREATE(CGdiObject) +public: + CGdiObject(); + ~CGdiObject() override; + HGDIOBJ m_hObject; + operator HGDIOBJ() const { return AfxIsNullThis(this) ? nullptr : m_hObject; } + HGDIOBJ GetSafeHandle() const { return AfxIsNullThis(this) ? nullptr : m_hObject; } + static CGdiObject* FromHandle(HGDIOBJ hObject); + BOOL Attach(HGDIOBJ hObject); + HGDIOBJ Detach(); + BOOL DeleteObject(); + int GetObject(int nCount, LPVOID lpObject) const; + BOOL CreateStockObject(int nIndex); + BOOL UnrealizeObject() { return TRUE; } +}; + +class CPen : public CGdiObject { + DECLARE_DYNAMIC(CPen) +public: + CPen() = default; + CPen(int nPenStyle, int nWidth, COLORREF crColor); + CPen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = nullptr); + BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor); + BOOL CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, + const DWORD* lpStyle = nullptr); + BOOL CreatePenIndirect(LPLOGPEN lpLogPen); + int GetLogPen(LOGPEN* pLogPen); + static CPen* FromHandle(HPEN hPen) { return static_cast(CGdiObject::FromHandle(hPen)); } + operator HPEN() const { return m_hObject; } +}; + +class CBrush : public CGdiObject { + DECLARE_DYNAMIC(CBrush) +public: + CBrush() = default; + explicit CBrush(COLORREF crColor); + CBrush(int nIndex, COLORREF crColor); + explicit CBrush(CBitmap* pBitmap); + BOOL CreateSolidBrush(COLORREF crColor); + BOOL CreateHatchBrush(int nIndex, COLORREF crColor); + BOOL CreatePatternBrush(CBitmap* pBitmap); + BOOL CreateSysColorBrush(int nIndex); + BOOL CreateBrushIndirect(const LOGBRUSH* lpLogBrush); + int GetLogBrush(LOGBRUSH* pLogBrush); + static CBrush* FromHandle(HBRUSH hBrush) { return static_cast(CGdiObject::FromHandle(hBrush)); } + operator HBRUSH() const { return m_hObject; } +}; + +class CFont : public CGdiObject { + DECLARE_DYNAMIC(CFont) +public: + CFont() = default; + BOOL CreateFontIndirect(const LOGFONT* lpLogFont); + BOOL CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, + BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, + BYTE nQuality, BYTE nPitchAndFamily, const char* lpszFacename); + BOOL CreateFontA(int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, + BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, + BYTE nQuality, BYTE nPitchAndFamily, const char* lpszFacename) { + return CreateFont(nHeight, nWidth, nEscapement, nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, + nCharSet, nOutPrecision, nClipPrecision, nQuality, nPitchAndFamily, lpszFacename); + } + BOOL CreatePointFont(int nPointSize, const char* lpszFaceName, CDC* pDC = nullptr); + BOOL CreatePointFontIndirect(const LOGFONT* lpLogFont, CDC* pDC = nullptr); + int GetLogFont(LOGFONT* pLogFont); + static CFont* FromHandle(HFONT hFont) { return static_cast(CGdiObject::FromHandle(hFont)); } + operator HFONT() const { return m_hObject; } +}; + +class CBitmap : public CGdiObject { + DECLARE_DYNAMIC(CBitmap) +public: + CBitmap() = default; + BOOL LoadBitmap(const char* lpszResourceName); + BOOL LoadBitmap(UINT nIDResource); + BOOL LoadBitmapA(const char* lpszResourceName) { return LoadBitmap(lpszResourceName); } + BOOL LoadBitmapA(UINT nIDResource) { return LoadBitmap(nIDResource); } + BOOL LoadOEMBitmap(UINT nIDBitmap); + BOOL LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, void* lpColorMap = nullptr, int nMapSize = 0); + BOOL CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits); + BOOL CreateBitmapIndirect(LPBITMAP lpBitmap); + BOOL CreateCompatibleBitmap(CDC* pDC, int nWidth, int nHeight); + BOOL CreateDiscardableBitmap(CDC* pDC, int nWidth, int nHeight); + int GetBitmap(BITMAP* pBitMap); + DWORD SetBitmapBits(DWORD dwCount, const void* lpBits); + DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const; + CSize SetBitmapDimension(int nWidth, int nHeight); + CSize GetBitmapDimension() const; + static CBitmap* FromHandle(HBITMAP hBitmap) { return static_cast(CGdiObject::FromHandle(hBitmap)); } + operator HBITMAP() const { return m_hObject; } +}; + +class CRgn : public CGdiObject { + DECLARE_DYNAMIC(CRgn) +public: + CRgn() = default; + BOOL CreateRectRgn(int x1, int y1, int x2, int y2); + BOOL CreateRectRgnIndirect(LPCRECT lpRect); + BOOL CreateEllipticRgn(int x1, int y1, int x2, int y2); + BOOL CreateEllipticRgnIndirect(LPCRECT lpRect); + BOOL CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode); + BOOL CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3); + int CombineRgn(CRgn* pRgn1, CRgn* pRgn2, int nCombineMode); + int CopyRgn(CRgn* pRgnSrc); + BOOL PtInRegion(int x, int y) const; + BOOL PtInRegion(POINT point) const { return PtInRegion(point.x, point.y); } + BOOL RectInRegion(LPCRECT lpRect) const; + int GetRgnBox(LPRECT lpRect) const; + void SetRectRgn(int x1, int y1, int x2, int y2); + int OffsetRgn(int x, int y); + static CRgn* FromHandle(HRGN hRgn) { return static_cast(CGdiObject::FromHandle(hRgn)); } + operator HRGN() const { return m_hObject; } +}; + +typedef struct tagLOGPALETTE* LPLOGPALETTE; +class CPalette : public CGdiObject { + DECLARE_DYNAMIC(CPalette) +public: + CPalette() = default; + BOOL CreatePalette(LPLOGPALETTE) { return TRUE; } + BOOL CreateHalftonePalette(CDC*) { return TRUE; } + operator HPALETTE() const { return m_hObject; } +}; + +class CDC : public CObject { + DECLARE_DYNCREATE(CDC) +public: + CDC(); + ~CDC() override; + + HDC m_hDC; + HDC m_hAttribDC; + operator HDC() const { return AfxIsNullThis(this) ? nullptr : m_hDC; } + HDC GetSafeHdc() const { return AfxIsNullThis(this) ? nullptr : m_hDC; } + static CDC* FromHandle(HDC hDC); + static void DeleteTempMap(); + BOOL Attach(HDC hDC); + HDC Detach(); + BOOL CreateCompatibleDC(CDC* pDC); + BOOL CreateDC(const char*, const char*, const char*, const void*) { return FALSE; } + BOOL CreateIC(const char*, const char*, const char*, const void*) { return FALSE; } + BOOL DeleteDC(); + CWnd* GetWindow() const; + BOOL IsPrinting() const { return m_bPrinting; } + BOOL m_bPrinting; + + int SaveDC(); + BOOL RestoreDC(int nSavedDC); + CGdiObject* SelectStockObject(int nIndex); + CPen* SelectObject(CPen* pPen); + CBrush* SelectObject(CBrush* pBrush); + CFont* SelectObject(CFont* pFont); + CBitmap* SelectObject(CBitmap* pBitmap); + int SelectObject(CRgn* pRgn); + CGdiObject* SelectObject(CGdiObject* pObject); + HGDIOBJ SelectObject(HGDIOBJ hObject); + CPalette* SelectPalette(CPalette* pPalette, BOOL bForceBackground); + UINT RealizePalette() { return 0; } + CPen* GetCurrentPen() const; + CBrush* GetCurrentBrush() const; + CFont* GetCurrentFont() const; + CBitmap* GetCurrentBitmap() const; + int GetDeviceCaps(int nIndex) const; + + COLORREF GetBkColor() const; + COLORREF SetBkColor(COLORREF crColor); + int GetBkMode() const; + int SetBkMode(int nBkMode); + COLORREF GetTextColor() const; + COLORREF SetTextColor(COLORREF crColor); + int GetROP2() const; + int SetROP2(int nDrawMode); + int SetStretchBltMode(int nStretchMode); + int GetStretchBltMode() const; + UINT SetTextAlign(UINT nFlags); + UINT GetTextAlign() const; + int SetTextCharacterExtra(int) { return 0; } + int SetMapMode(int nMapMode); + int GetMapMode() const; + CPoint SetViewportOrg(int x, int y); + CPoint SetViewportOrg(POINT point) { return SetViewportOrg(point.x, point.y); } + CPoint GetViewportOrg() const; + CPoint OffsetViewportOrg(int nWidth, int nHeight); + CSize SetViewportExt(int cx, int cy); + CSize SetViewportExt(SIZE size) { return SetViewportExt(size.cx, size.cy); } + CSize GetViewportExt() const; + CPoint SetWindowOrg(int x, int y); + CPoint SetWindowOrg(POINT point) { return SetWindowOrg(point.x, point.y); } + CPoint GetWindowOrg() const; + CPoint OffsetWindowOrg(int nWidth, int nHeight); + CSize SetWindowExt(int cx, int cy); + CSize SetWindowExt(SIZE size) { return SetWindowExt(size.cx, size.cy); } + CSize GetWindowExt() const; + void DPtoLP(LPPOINT lpPoints, int nCount = 1) const; + void DPtoLP(LPRECT lpRect) const; + void DPtoLP(LPSIZE lpSize) const; + void LPtoDP(LPPOINT lpPoints, int nCount = 1) const; + void LPtoDP(LPRECT lpRect) const; + void LPtoDP(LPSIZE lpSize) const; + + int GetClipBox(LPRECT lpRect) const; + int SelectClipRgn(CRgn* pRgn); + int IntersectClipRect(int x1, int y1, int x2, int y2); + int IntersectClipRect(LPCRECT lpRect); + int ExcludeClipRect(int, int, int, int) { return SIMPLEREGION; } + int ExcludeClipRect(LPCRECT) { return SIMPLEREGION; } + BOOL PtVisible(int, int) const { return TRUE; } + BOOL RectVisible(LPCRECT) const { return TRUE; } + + CPoint GetCurrentPosition() const; + CPoint MoveTo(int x, int y); + CPoint MoveTo(POINT point) { return MoveTo(point.x, point.y); } + BOOL LineTo(int x, int y); + BOOL LineTo(POINT point) { return LineTo(point.x, point.y); } + BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); + BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd); + BOOL Polyline(const POINT* lpPoints, int nCount); + BOOL PolyBezier(const POINT* lpPoints, int nCount); + BOOL PolylineTo(const POINT* lpPoints, int nCount); + void FillRect(LPCRECT lpRect, CBrush* pBrush); + void FrameRect(LPCRECT lpRect, CBrush* pBrush); + void InvertRect(LPCRECT lpRect); + BOOL DrawIcon(int x, int y, HICON hIcon); + BOOL DrawIcon(POINT point, HICON hIcon) { return DrawIcon(point.x, point.y, hIcon); } + BOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags); + BOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState); + void DrawFocusRect(LPCRECT lpRect); + BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); + BOOL Ellipse(int x1, int y1, int x2, int y2); + BOOL Ellipse(LPCRECT lpRect) { return Ellipse(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } + BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); + BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd); + BOOL Polygon(const POINT* lpPoints, int nCount); + BOOL PolyPolygon(const POINT* lpPoints, const INT* lpPolyCounts, int nCount); + BOOL Rectangle(int x1, int y1, int x2, int y2); + BOOL Rectangle(LPCRECT lpRect) { return Rectangle(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } + BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3); + BOOL RoundRect(LPCRECT lpRect, POINT point); + void FillSolidRect(LPCRECT lpRect, COLORREF clr); + void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr); + void Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight); + void Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight); + BOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop); + BOOL BitBlt(int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop); + BOOL StretchBlt(int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, + int nSrcHeight, DWORD dwRop); + BOOL TransparentBlt(int xDest, int yDest, int nDestWidth, int nDestHeight, CDC* pSrcDC, int xSrc, int ySrc, + int nSrcWidth, int nSrcHeight, UINT clrTransparent); + COLORREF GetPixel(int x, int y) const; + COLORREF GetPixel(POINT point) const { return GetPixel(point.x, point.y); } + COLORREF SetPixel(int x, int y, COLORREF crColor); + COLORREF SetPixel(POINT point, COLORREF crColor) { return SetPixel(point.x, point.y, crColor); } + BOOL SetPixelV(int x, int y, COLORREF crColor) { SetPixel(x, y, crColor); return TRUE; } + BOOL FloodFill(int x, int y, COLORREF crColor); + BOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType); + BOOL FillRgn(CRgn* pRgn, CBrush* pBrush); + BOOL FrameRgn(CRgn* pRgn, CBrush* pBrush, int nWidth, int nHeight); + BOOL PaintRgn(CRgn* pRgn); + + BOOL TextOut(int x, int y, const char* lpszString, int nCount); + BOOL TextOut(int x, int y, const CString& str); + BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, const char* lpszString, UINT nCount, + LPINT lpDxWidths); + BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, const CString& str, LPINT lpDxWidths); + CSize TabbedTextOut(int x, int y, const char* lpszString, int nCount, int nTabPositions, LPINT lpnTabStopPositions, + int nTabOrigin); + int DrawText(const char* lpszString, int nCount, LPRECT lpRect, UINT nFormat); + int DrawText(const CString& str, LPRECT lpRect, UINT nFormat); + CSize GetTextExtent(const char* lpszString, int nCount) const; + CSize GetTextExtent(const CString& str) const; + CSize GetOutputTextExtent(const char* lpszString, int nCount) const { return GetTextExtent(lpszString, nCount); } + CSize GetOutputTextExtent(const CString& str) const { return GetTextExtent(str); } + CSize GetTabbedTextExtent(const char* lpszString, int nCount, int nTabPositions, LPINT lpnTabStopPositions) const; + BOOL GetTextExtentExPoint(const char* lpszString, int nCount, int nMaxExtent, LPINT lpnFit, LPINT alpDx, + LPSIZE lpSize) const; + BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const; + BOOL GetOutputTextMetrics(LPTEXTMETRIC lpMetrics) const { return GetTextMetrics(lpMetrics); } + int GetTextFace(int nCount, char* lpszFacename) const; + int GetTextFace(CString& rString) const; + BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const; + int SetTextJustification(int, int) { return 1; } + + int StartDoc(const char*) { return 0; } + int EndDoc() { return 0; } + int StartPage() { return 0; } + int EndPage() { return 0; } + int AbortDoc() { return 0; } + + // implementation: m_hDC points to an mfcwx::DCState owned by this CDC (or by the creator of a + // temporary wrapper); GetWx() returns the wx device context it draws on. + wxDC* GetWx() const; +}; + +class CPaintDC : public CDC { + DECLARE_DYNAMIC(CPaintDC) +public: + explicit CPaintDC(CWnd* pWnd); + ~CPaintDC() override; + PAINTSTRUCT m_ps; + +protected: + HWND m_hWnd; +}; + +class CClientDC : public CDC { + DECLARE_DYNAMIC(CClientDC) +public: + explicit CClientDC(CWnd* pWnd); + ~CClientDC() override; + +protected: + HWND m_hWnd; +}; + +class CWindowDC : public CDC { + DECLARE_DYNAMIC(CWindowDC) +public: + explicit CWindowDC(CWnd* pWnd); + ~CWindowDC() override; + +protected: + HWND m_hWnd; +}; + +// --------------------------------------------------------------------------------------------- +// Menus + +class CMenu : public CObject { + DECLARE_DYNCREATE(CMenu) +public: + CMenu(); + ~CMenu() override; + HMENU m_hMenu; + operator HMENU() const { return AfxIsNullThis(this) ? nullptr : m_hMenu; } + HMENU GetSafeHmenu() const { return AfxIsNullThis(this) ? nullptr : m_hMenu; } + static CMenu* FromHandle(HMENU hMenu); + BOOL Attach(HMENU hMenu); + HMENU Detach(); + BOOL CreateMenu(); + BOOL CreatePopupMenu(); + BOOL LoadMenu(const char* lpszResourceName); + BOOL LoadMenu(UINT nIDResource); + BOOL DestroyMenu(); + BOOL DeleteMenu(UINT nPosition, UINT nFlags); + BOOL RemoveMenu(UINT nPosition, UINT nFlags); + BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, const char* lpszNewItem = nullptr); + BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, const char* lpszNewItem = nullptr); + BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, const char* lpszNewItem = nullptr); + UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck); + BOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags); + UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable); + UINT GetMenuItemCount() const; + UINT GetMenuItemID(int nPos) const; + UINT GetMenuState(UINT nID, UINT nFlags) const; + int GetMenuString(UINT nIDItem, char* lpString, int nMaxCount, UINT nFlags) const; + int GetMenuString(UINT nIDItem, CString& rString, UINT nFlags) const; + CMenu* GetSubMenu(int nPos) const; + BOOL SetDefaultItem(UINT, BOOL = FALSE) { return TRUE; } + BOOL TrackPopupMenu(UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = nullptr); + BOOL SetMenuItemBitmaps(UINT, UINT, const CBitmap*, const CBitmap*) { return TRUE; } + + // implementation + wxMenu* GetWxMenu() const; + wxMenuBar* GetWxMenuBar() const; +}; + +// --------------------------------------------------------------------------------------------- +// Controls (no data members: methods operate on m_hWnd so temporary CWnd wrappers can be cast) + +class CStatic : public CWnd { + DECLARE_DYNAMIC(CStatic) +public: + CStatic() = default; + BOOL Create(const char* lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff); + HICON SetIcon(HICON hIcon); + HICON GetIcon() const; + HBITMAP SetBitmap(HBITMAP hBitmap); + HBITMAP GetBitmap() const; + HCURSOR SetCursor(HCURSOR hCursor); + HCURSOR GetCursor(); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) override; +}; + +class CButton : public CWnd { + DECLARE_DYNAMIC(CButton) +public: + CButton() = default; + BOOL Create(const char* lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + UINT GetState() const; + void SetState(BOOL bHighlight); + int GetCheck() const; + void SetCheck(int nCheck); + UINT GetButtonStyle() const; + void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE); + HICON SetIcon(HICON hIcon); + HICON GetIcon() const; + HBITMAP SetBitmap(HBITMAP hBitmap); + HBITMAP GetBitmap() const; + HCURSOR SetCursor(HCURSOR hCursor); + HCURSOR GetCursor(); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) override; +}; + +class CEdit : public CWnd { + DECLARE_DYNAMIC(CEdit) +public: + CEdit() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + BOOL CanUndo() const; + int GetLineCount() const; + BOOL GetModify() const; + void SetModify(BOOL bModified = TRUE); + void GetRect(LPRECT lpRect) const; + DWORD GetSel() const; + void GetSel(int& nStartChar, int& nEndChar) const; + int GetLine(int nIndex, char* lpszBuffer) const; + int GetLine(int nIndex, char* lpszBuffer, int nMaxLength) const; + void EmptyUndoBuffer(); + BOOL FmtLines(BOOL) { return TRUE; } + void LimitText(int nChars = 0); + int LineFromChar(int nIndex = -1) const; + int LineIndex(int nLine = -1) const; + int LineLength(int nLine = -1) const; + void LineScroll(int nLines, int nChars = 0); + void ReplaceSel(const char* lpszNewText, BOOL bCanUndo = FALSE); + void SetPasswordChar(char ch); + void SetRect(LPCRECT) {} + void SetRectNP(LPCRECT) {} + void SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE); + void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE); + BOOL SetTabStops(int nTabStops, LPINT rgTabStops); + void SetTabStops() {} + BOOL SetTabStops(const int&) { return TRUE; } + BOOL Undo(); + void Clear(); + void Copy(); + void Cut(); + void Paste(); + BOOL SetReadOnly(BOOL bReadOnly = TRUE); + int GetFirstVisibleLine() const; + char GetPasswordChar() const; + void SetMargins(UINT, UINT) {} + DWORD GetMargins() const { return 0; } + void SetLimitText(UINT nMax); + UINT GetLimitText() const; + CPoint PosFromChar(UINT nChar) const; + int CharFromPos(CPoint pt) const; +}; + +class CListBox : public CWnd { + DECLARE_DYNAMIC(CListBox) +public: + CListBox() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + int GetCount() const; + int GetHorizontalExtent() const { return 0; } + void SetHorizontalExtent(int) {} + int GetTopIndex() const; + int SetTopIndex(int nIndex); + DWORD_PTR GetItemData(int nIndex) const; + int SetItemData(int nIndex, DWORD_PTR dwItemData); + void* GetItemDataPtr(int nIndex) const { return reinterpret_cast(GetItemData(nIndex)); } + int SetItemDataPtr(int nIndex, void* pData) { return SetItemData(nIndex, reinterpret_cast(pData)); } + int GetItemRect(int nIndex, LPRECT lpRect) const; + int GetSel(int nIndex) const; + int GetText(int nIndex, char* lpszBuffer) const; + void GetText(int nIndex, CString& rString) const; + int GetTextLen(int nIndex) const; + void SetColumnWidth(int) {} + BOOL SetTabStops(int, LPINT) { return TRUE; } + void SetTabStops() {} + BOOL SetTabStops(const int&) { return TRUE; } + int SetItemHeight(int, UINT) { return 0; } + int GetItemHeight(int) const { return 16; } + int FindStringExact(int nIndexStart, const char* lpszFind) const; + int GetCaretIndex() const; + int SetCaretIndex(int nIndex, BOOL bScroll = TRUE); + int GetCurSel() const; + int SetCurSel(int nSelect); + int SetSel(int nIndex, BOOL bSelect = TRUE); + int GetSelCount() const; + int GetSelItems(int nMaxItems, LPINT rgIndex) const; + int SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem); + int AddString(const char* lpszItem); + int DeleteString(UINT nIndex); + int InsertString(int nIndex, const char* lpszItem); + void ResetContent(); + int Dir(UINT, const char*) { return LB_ERR; } + int FindString(int nStartAfter, const char* lpszItem) const; + int SelectString(int nStartAfter, const char* lpszItem); + int GetAnchorIndex() const { return GetCaretIndex(); } + void SetAnchorIndex(int) {} + UINT ItemFromPoint(CPoint pt, BOOL& bOutside) const; +}; + +#define CLBN_CHKCHANGE 40 + +class CCheckListBox : public CListBox { + DECLARE_DYNAMIC(CCheckListBox) +public: + CCheckListBox() = default; + void SetCheckStyle(UINT) {} + UINT GetCheckStyle() { return BS_AUTOCHECKBOX; } + void SetCheck(int nIndex, int nCheck); + int GetCheck(int nIndex); + void Enable(int nIndex, BOOL bEnabled = TRUE); + BOOL IsEnabled(int nIndex); +}; + +class CComboBox : public CWnd { + DECLARE_DYNAMIC(CComboBox) +public: + CComboBox() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + int GetCount() const; + int GetCurSel() const; + int SetCurSel(int nSelect); + DWORD GetEditSel() const; + BOOL LimitText(int nMaxChars); + BOOL SetEditSel(int nStartChar, int nEndChar); + DWORD_PTR GetItemData(int nIndex) const; + int SetItemData(int nIndex, DWORD_PTR dwItemData); + void* GetItemDataPtr(int nIndex) const { return reinterpret_cast(GetItemData(nIndex)); } + int SetItemDataPtr(int nIndex, void* pData) { return SetItemData(nIndex, reinterpret_cast(pData)); } + int GetLBText(int nIndex, char* lpszText) const; + void GetLBText(int nIndex, CString& rString) const; + int GetLBTextLen(int nIndex) const; + int SetItemHeight(int, UINT) { return 0; } + int GetItemHeight(int) const { return 16; } + int FindStringExact(int nIndexStart, const char* lpszFind) const; + int SetExtendedUI(BOOL = TRUE) { return CB_OKAY; } + BOOL GetExtendedUI() const { return FALSE; } + void GetDroppedControlRect(LPRECT lprect) const; + BOOL GetDroppedState() const { return FALSE; } + int GetDroppedWidth() const { return 0; } + int SetDroppedWidth(UINT) { return 0; } + int GetTopIndex() const { return 0; } + int SetTopIndex(int) { return 0; } + void ShowDropDown(BOOL bShowIt = TRUE); + int AddString(const char* lpszString); + int DeleteString(UINT nIndex); + int InsertString(int nIndex, const char* lpszString); + void ResetContent(); + int Dir(UINT, const char*) { return CB_ERR; } + int FindString(int nStartAfter, const char* lpszString) const; + int SelectString(int nStartAfter, const char* lpszString); + void Clear(); + void Copy(); + void Cut(); + void Paste(); +}; + +class CScrollBar : public CWnd { + DECLARE_DYNAMIC(CScrollBar) +public: + CScrollBar() = default; + BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + int GetScrollPos() const; + int SetScrollPos(int nPos, BOOL bRedraw = TRUE); + void GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const; + void SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE); + void ShowScrollBar(BOOL bShow = TRUE); + BOOL EnableScrollBar(UINT nArrowFlags = ESB_ENABLE_BOTH); + BOOL SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE); + BOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo, UINT nMask = SIF_ALL); + int GetScrollLimit(); +}; + +// --------------------------------------------------------------------------------------------- +// Dialogs and data exchange + +class CDataExchange { +public: + CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate); + BOOL m_bSaveAndValidate; + CWnd* m_pDlgWnd; + HWND m_hWndLastControl; + BOOL m_bEditLastControl; + HWND PrepareCtrl(int nIDC); + HWND PrepareEditCtrl(int nIDC); + void Fail(); +}; + +class CDialog : public CWnd { + DECLARE_DYNAMIC(CDialog) +public: + CDialog(); + explicit CDialog(const char* lpszTemplateName, CWnd* pParentWnd = nullptr); + explicit CDialog(UINT nIDTemplate, CWnd* pParentWnd = nullptr); + ~CDialog() override; + + virtual BOOL Create(const char* lpszTemplateName, CWnd* pParentWnd = nullptr); + virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = nullptr); + BOOL CreateIndirect(const void* lpDialogTemplate, CWnd* pParentWnd = nullptr, void* lpDialogInit = nullptr); + BOOL InitModalIndirect(const void* lpDialogTemplate, CWnd* pParentWnd = nullptr, void* lpDialogInit = nullptr); + virtual INT_PTR DoModal(); + void EndDialog(int nResult); + void MapDialogRect(LPRECT lpRect) const; + void SetHelpID(UINT nIDR) { m_nIDHelp = nIDR; } + void SetDefID(UINT nID); + DWORD GetDefID() const; + void NextDlgCtrl() const; + void PrevDlgCtrl() const; + void GotoDlgCtrl(CWnd* pWndCtrl); + BOOL CheckAutoCenter() { return TRUE; } + virtual BOOL OnInitDialog(); + virtual void OnSetFont(CFont*) {} + BOOL ContinueModal() { return m_bModalRunning; } + BOOL DestroyWindow() override; + + UINT m_nIDHelp; + const char* m_lpszTemplateName; + UINT m_nIDTemplate; + CWnd* m_pParentWnd; + BOOL m_bModalRunning; + int m_nModalResult; + +protected: + virtual void OnOK(); + virtual void OnCancel(); + afx_msg void OnHelp(); + afx_msg LRESULT HandleInitDialog(WPARAM, LPARAM); + BOOL CreateFromTemplate(BOOL bModal); + friend struct mfcwx::WindowState; + + DECLARE_MESSAGE_MAP() +}; + +void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, BYTE& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, short& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, int& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, UINT& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, long& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, unsigned long& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, LONG& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, DWORD& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, LONGLONG& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, ULONGLONG& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, char* value, int nMaxLen); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, float& value); +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, double& value); +void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, int& value); +void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, bool& value); +void AFXAPI DDX_Radio(CDataExchange* pDX, int nIDC, int& value); +void AFXAPI DDX_LBString(CDataExchange* pDX, int nIDC, CString& value); +void AFXAPI DDX_CBString(CDataExchange* pDX, int nIDC, CString& value); +void AFXAPI DDX_LBIndex(CDataExchange* pDX, int nIDC, int& index); +void AFXAPI DDX_CBIndex(CDataExchange* pDX, int nIDC, int& index); +void AFXAPI DDX_LBStringExact(CDataExchange* pDX, int nIDC, CString& value); +void AFXAPI DDX_CBStringExact(CDataExchange* pDX, int nIDC, CString& value); +void AFXAPI DDX_Scroll(CDataExchange* pDX, int nIDC, int& value); +void AFXAPI DDX_Slider(CDataExchange* pDX, int nIDC, int& value); + +void AFXAPI DDV_MaxChars(CDataExchange* pDX, const CString& value, int nChars); +void AFXAPI DDV_MinMaxByte(CDataExchange* pDX, BYTE value, BYTE minVal, BYTE maxVal); +void AFXAPI DDV_MinMaxShort(CDataExchange* pDX, short value, short minVal, short maxVal); +void AFXAPI DDV_MinMaxInt(CDataExchange* pDX, int value, int minVal, int maxVal); +void AFXAPI DDV_MinMaxLong(CDataExchange* pDX, long value, long minVal, long maxVal); +void AFXAPI DDV_MinMaxUInt(CDataExchange* pDX, UINT value, UINT minVal, UINT maxVal); +void AFXAPI DDV_MinMaxDWord(CDataExchange* pDX, DWORD value, DWORD minVal, DWORD maxVal); +void AFXAPI DDV_MinMaxLongLong(CDataExchange* pDX, LONGLONG value, LONGLONG minVal, LONGLONG maxVal); +void AFXAPI DDV_MinMaxULongLong(CDataExchange* pDX, ULONGLONG value, ULONGLONG minVal, ULONGLONG maxVal); +void AFXAPI DDV_MinMaxFloat(CDataExchange* pDX, float const& value, float minVal, float maxVal); +void AFXAPI DDV_MinMaxDouble(CDataExchange* pDX, double const& value, double minVal, double maxVal); +void AFXAPI DDV_MinMaxSlider(CDataExchange* pDX, DWORD value, DWORD minVal, DWORD maxVal); + +// --------------------------------------------------------------------------------------------- +// Threads and application + +typedef UINT (*AFX_THREADPROC)(LPVOID); + +class CWinThread : public CCmdTarget { + DECLARE_DYNAMIC(CWinThread) +public: + CWinThread(); + CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam); + ~CWinThread() override; + BOOL CreateThread(DWORD dwCreateFlags = 0, UINT nStackSize = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = nullptr); + int GetThreadPriority(); + BOOL SetThreadPriority(int nPriority); + DWORD SuspendThread(); + DWORD ResumeThread(); + BOOL PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam); + virtual BOOL InitInstance(); + virtual int ExitInstance(); + virtual int Run(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL PumpMessage(); + virtual BOOL OnIdle(LONG lCount); + virtual BOOL IsIdleMessage(MSG*) { return TRUE; } + virtual CWnd* GetMainWnd(); + virtual BOOL ProcessMessageFilter(int code, LPMSG lpMsg); + operator HANDLE() const { return m_hThread; } + + CWnd* m_pMainWnd; + CWnd* m_pActiveWnd; + BOOL m_bAutoDelete; + HANDLE m_hThread; + DWORD m_nThreadID; + AFX_THREADPROC m_pfnThreadProc; + LPVOID m_pThreadParams; + MSG m_msgCur; +}; + +CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, + UINT nStackSize = 0, DWORD dwCreateFlags = 0, + LPSECURITY_ATTRIBUTES lpSecurityAttrs = nullptr); +CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, + UINT nStackSize = 0, DWORD dwCreateFlags = 0, + LPSECURITY_ATTRIBUTES lpSecurityAttrs = nullptr); +void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete = TRUE); +CWinThread* AFXAPI AfxGetThread(); + +class CRecentFileList { +public: + CRecentFileList(UINT nStart, const char* lpszSection, const char* lpszEntryFormat, int nSize, + int nMaxDispLen = 30); + virtual ~CRecentFileList() = default; + int GetSize() const { return m_nSize; } + CString& operator[](int nIndex) { return m_arrNames[nIndex]; } + virtual void Remove(int nIndex); + virtual void Add(const char* lpszPathName); + virtual BOOL GetDisplayName(CString& strName, int nIndex, const char* lpszCurDir, int nCurDir, + BOOL bAtLeastName = TRUE) const; + virtual void UpdateMenu(CCmdUI* pCmdUI); + virtual void ReadList(); + virtual void WriteList(); + + int m_nSize; + std::vector m_arrNames; + CString m_strSectionName; + CString m_strEntryFormat; + UINT m_nStart; + int m_nMaxDisplayLength; +}; + +class CWinApp : public CWinThread { + DECLARE_DYNAMIC(CWinApp) +public: + explicit CWinApp(const char* lpszAppName = nullptr); + ~CWinApp() override; + + HINSTANCE m_hInstance; + HINSTANCE m_hPrevInstance; + char* m_lpCmdLine; + int m_nCmdShow; + const char* m_pszAppName; + const char* m_pszRegistryKey; + const char* m_pszExeName; + const char* m_pszHelpFilePath; + const char* m_pszProfileName; + CRecentFileList* m_pRecentFileList; + BOOL m_bHelpMode; + WORD m_nWaitCursorCount; + HCURSOR m_hcurWaitCursorRestore; + int m_eHelpType; + + BOOL InitInstance() override; + int ExitInstance() override; + int Run() override; + BOOL OnIdle(LONG lCount) override; + virtual BOOL InitApplication(); + virtual CDocument* OpenDocumentFile(const char* lpszFileName); + virtual void AddToRecentFileList(const char* lpszPathName); + virtual BOOL SaveAllModified(); + virtual void CloseAllDocuments(BOOL bEndSession); + virtual int DoMessageBox(const char* lpszPrompt, UINT nType, UINT nIDPrompt); + virtual void DoWaitCursor(int nCode); + virtual void WinHelp(DWORD_PTR dwData, UINT nCmd = HELP_CONTEXT); + virtual void WinHelpInternal(DWORD_PTR dwData, UINT nCmd = HELP_CONTEXT); + virtual void HtmlHelp(DWORD_PTR dwData, UINT nCmd = 0x000F); + virtual BOOL ProcessShellCommand(class CCommandLineInfo& rCmdInfo); + virtual void ParseCommandLine(class CCommandLineInfo& rCmdInfo); + virtual BOOL DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, + CDocTemplate* pTemplate); + virtual BOOL OnDDECommand(LPTSTR lpszCommand); + + void AddDocTemplate(CDocTemplate* pTemplate); + POSITION GetFirstDocTemplatePosition() const; + CDocTemplate* GetNextDocTemplate(POSITION& pos) const; + HCURSOR LoadCursor(const char* lpszResourceName) const; + HCURSOR LoadCursor(UINT nIDResource) const; + HCURSOR LoadStandardCursor(const char* lpszCursorName) const; + HCURSOR LoadOEMCursor(UINT nIDCursor) const; + HICON LoadIcon(const char* lpszResourceName) const; + HICON LoadIcon(UINT nIDResource) const; + HICON LoadStandardIcon(const char* lpszIconName) const; + HICON LoadOEMIcon(UINT nIDIcon) const; + UINT GetProfileInt(const char* lpszSection, const char* lpszEntry, int nDefault); + BOOL WriteProfileInt(const char* lpszSection, const char* lpszEntry, int nValue); + CString GetProfileString(const char* lpszSection, const char* lpszEntry, const char* lpszDefault = nullptr); + BOOL WriteProfileString(const char* lpszSection, const char* lpszEntry, const char* lpszValue); + BOOL GetProfileBinary(const char* lpszSection, const char* lpszEntry, LPBYTE* ppData, UINT* pBytes); + BOOL WriteProfileBinary(const char* lpszSection, const char* lpszEntry, LPBYTE pData, UINT nBytes); + void SetRegistryKey(const char* lpszRegistryKey); + void SetRegistryKey(UINT nIDRegistryKey); + void LoadStdProfileSettings(UINT nMaxMRU = 4); + void EnableShellOpen() {} + void RegisterShellFileTypes(BOOL = FALSE) {} + void UnregisterShellFileTypes() {} + void Enable3dControls() {} + void Enable3dControlsStatic() {} + void SetDialogBkColor(COLORREF = 0, COLORREF = 0) {} + void EnableHtmlHelp() {} + void HideApplication(); + BOOL GetPrinterDeviceDefaults(void*) { return FALSE; } + void SelectPrinter(HANDLE, HANDLE, BOOL = TRUE) {} + CWnd* GetMainWnd() override { return m_pMainWnd; } + + afx_msg void OnFileNew(); + afx_msg void OnFileOpen(); + afx_msg void OnFilePrintSetup(); + afx_msg void OnAppExit(); + afx_msg void OnHelp(); + afx_msg void OnHelpFinder(); + afx_msg void OnHelpIndex(); + afx_msg void OnContextHelp(); + afx_msg void OnHelpUsing(); + afx_msg BOOL OnOpenRecentFile(UINT nID); + afx_msg void OnUpdateRecentFileMenu(CCmdUI* pCmdUI); + + std::vector m_templates; + +protected: + DECLARE_MESSAGE_MAP() +}; + +class CCommandLineInfo : public CObject { +public: + CCommandLineInfo(); + virtual void ParseParam(const char* pszParam, BOOL bFlag, BOOL bLast); + BOOL m_bShowSplash; + BOOL m_bRunEmbedded; + BOOL m_bRunAutomated; + enum { FileNew, FileOpen, FilePrint, FilePrintTo, FileDDE, AppRegister, AppUnregister, FileNothing = -1 } m_nShellCommand; + CString m_strFileName; + CString m_strPrinterName; + CString m_strDriverName; + CString m_strPortName; +}; + +CWinApp* AFXAPI AfxGetApp(); +CWnd* AFXAPI AfxGetMainWnd(); +HINSTANCE AFXAPI AfxGetInstanceHandle(); +HINSTANCE AFXAPI AfxGetResourceHandle(); +void AFXAPI AfxSetResourceHandle(HINSTANCE hInstResource); +HINSTANCE AFXAPI AfxFindResourceHandle(const char* lpszName, const char* lpszType); +const char* AFXAPI AfxGetAppName(); +int AFXAPI AfxMessageBox(const char* lpszText, UINT nType = MB_OK, UINT nIDHelp = 0); +int AFXAPI AfxMessageBox(UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT)-1); +void AFXAPI AfxFormatString1(CString& rString, UINT nIDS, const char* lpsz1); +void AFXAPI AfxFormatString2(CString& rString, UINT nIDS, const char* lpsz1, const char* lpsz2); +BOOL AFXAPI AfxExtractSubString(CString& rString, const char* lpszFullString, int iSubString, char chSep = '\n'); +const char* AFXAPI AfxRegisterWndClass(UINT nClassStyle, HCURSOR hCursor = nullptr, HBRUSH hbrBackground = nullptr, + HICON hIcon = nullptr); +BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass); +BOOL AFXAPI AfxInitRichEdit(); +BOOL AFXAPI AfxInitRichEdit2(); +BOOL AFXAPI AfxOleInit(); +void AFXAPI AfxEnableControlContainer(); +BOOL AFXAPI AfxSocketInit(); +void AFXAPI AfxInitCommonControls(); +BOOL AFXAPI AfxCheckMemory(); +void AFXAPI AfxGetModuleShortFileName(HINSTANCE hInst, CString& strShortName); +LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam); + +#include "mfcwx/winapi_gui.h" +#include "mfcwx/regkey.h" +#include "mfcwx/extras.h" + +template +inline typename std::common_type::type min(A a, B b) { return b < a ? b : a; } +template +inline typename std::common_type::type max(A a, B b) { return a < b ? b : a; } +#include "mfcwx/docview.h" diff --git a/port/mfcwx/include/atlbase.h b/port/mfcwx/include/atlbase.h new file mode 100644 index 000000000..05e081c1b --- /dev/null +++ b/port/mfcwx/include/atlbase.h @@ -0,0 +1,2 @@ +#pragma once +#include "afx.h" diff --git a/port/mfcwx/include/basetsd.h b/port/mfcwx/include/basetsd.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/basetsd.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/commctrl.h b/port/mfcwx/include/commctrl.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/commctrl.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/commdlg.h b/port/mfcwx/include/commdlg.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/commdlg.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/conio.h b/port/mfcwx/include/conio.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/conio.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/crtdbg.h b/port/mfcwx/include/crtdbg.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/crtdbg.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/direct.h b/port/mfcwx/include/direct.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/direct.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/dos.h b/port/mfcwx/include/dos.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/dos.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/gl/gl.h b/port/mfcwx/include/gl/gl.h new file mode 100644 index 000000000..f60013dd4 --- /dev/null +++ b/port/mfcwx/include/gl/gl.h @@ -0,0 +1,9 @@ +#pragma once +#ifdef __APPLE__ +#ifndef GL_SILENCE_DEPRECATION +#define GL_SILENCE_DEPRECATION +#endif +#include +#else +#include +#endif diff --git a/port/mfcwx/include/gl/glu.h b/port/mfcwx/include/gl/glu.h new file mode 100644 index 000000000..5fc1f9c1c --- /dev/null +++ b/port/mfcwx/include/gl/glu.h @@ -0,0 +1,9 @@ +#pragma once +#ifdef __APPLE__ +#ifndef GL_SILENCE_DEPRECATION +#define GL_SILENCE_DEPRECATION +#endif +#include +#else +#include +#endif diff --git a/port/mfcwx/include/htmlhelp.h b/port/mfcwx/include/htmlhelp.h new file mode 100644 index 000000000..f1d9eee22 --- /dev/null +++ b/port/mfcwx/include/htmlhelp.h @@ -0,0 +1,90 @@ +#pragma once +#include "mfcwx/win32.h" + +#ifndef HH_SET_WIN_TYPE +#define HH_SET_WIN_TYPE 0x0004 +#define HH_GET_WIN_TYPE 0x0005 +#define HH_GET_WIN_HANDLE 0x0006 +#define HH_SYNC 0x0009 +#define HH_GET_LAST_ERROR 0x0014 +#endif + +#define HH_MAX_TABS 19 + +#define HHWIN_PROP_TAB_AUTOHIDESHOW (1 << 0) +#define HHWIN_PROP_ONTOP (1 << 1) +#define HHWIN_PROP_NOTITLEBAR (1 << 2) +#define HHWIN_PROP_NODEF_STYLES (1 << 3) +#define HHWIN_PROP_NODEF_EXSTYLES (1 << 4) +#define HHWIN_PROP_TRI_PANE (1 << 5) +#define HHWIN_PROP_NOTB_TEXT (1 << 6) +#define HHWIN_PROP_POST_QUIT (1 << 7) +#define HHWIN_PROP_AUTO_SYNC (1 << 8) +#define HHWIN_PROP_TRACKING (1 << 9) +#define HHWIN_PROP_TAB_SEARCH (1 << 10) +#define HHWIN_PROP_NO_TOOLBAR (1 << 15) + +#define HHWIN_PARAM_PROPERTIES (1 << 1) +#define HHWIN_PARAM_STYLES (1 << 2) +#define HHWIN_PARAM_EXSTYLES (1 << 3) +#define HHWIN_PARAM_RECT (1 << 4) +#define HHWIN_PARAM_NAV_WIDTH (1 << 5) +#define HHWIN_PARAM_SHOWSTATE (1 << 6) + +typedef DWORD HH_INFOTYPE, *PHH_INFOTYPE; + +typedef struct tagHH_AKLINK { + int cbStruct; + BOOL fReserved; + const char* pszKeywords; + const char* pszUrl; + const char* pszMsgText; + const char* pszMsgTitle; + const char* pszWindow; + BOOL fIndexOnFail; +} HH_AKLINK, *PHH_AKLINK; + +typedef struct tagHH_WINTYPE { + int cbStruct; + BOOL fUniCodeStrings; + const char* pszType; + DWORD fsValidMembers; + DWORD fsWinProperties; + const char* pszCaption; + DWORD dwStyles; + DWORD dwExStyles; + RECT rcWindowPos; + int nShowState; + HWND hwndHelp; + HWND hwndCaller; + HH_INFOTYPE* paInfoTypes; + HWND hwndToolBar; + HWND hwndNavigation; + HWND hwndHTML; + int iNavWidth; + RECT rcHTML; + const char* pszToc; + const char* pszIndex; + const char* pszFile; + const char* pszHome; + DWORD fsToolBarFlags; + BOOL fNotExpanded; + int curNavType; + int tabpos; + int idNotify; + BYTE tabOrder[HH_MAX_TABS + 1]; + int cHistory; + const char* pszJump1; + const char* pszJump2; + const char* pszUrlJump1; + const char* pszUrlJump2; + RECT rcMinSize; + int cbInfoTypes; + const char* pszCustomTabs; +} HH_WINTYPE, *PHH_WINTYPE; + +#ifdef __cplusplus +// Reads /hlp_de or hlp_en (UI language) with the index from build_help_index.py. +HWND HtmlHelp(HWND hwndCaller, const char* pszFile, UINT uCommand, DWORD_PTR dwData); +HWND HtmlHelpA(HWND hwndCaller, const char* pszFile, UINT uCommand, DWORD_PTR dwData); +#endif diff --git a/port/mfcwx/include/io.h b/port/mfcwx/include/io.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/io.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/mbstring.h b/port/mfcwx/include/mbstring.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/mbstring.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/mfcwx/app.h b/port/mfcwx/include/mfcwx/app.h new file mode 100644 index 000000000..6f671ea4b --- /dev/null +++ b/port/mfcwx/include/mfcwx/app.h @@ -0,0 +1,23 @@ +#pragma once + +// Hooks for the platform glue of an application built on mfcwx. + +#include +#include + +namespace mfcwx { + +namespace rc { +struct Module; +} + +void RegisterResourceModule(const rc::Module* module); +void SetResourceLanguage(const char* code); +const char* GetResourceLanguage(); +std::vector AvailableResourceLanguages(); +std::string GetDataDirectory(); +void SetDataDirectory(const std::string& dir); +// Used when neither MFCWX_DATA_DIR nor an installed resource directory is found (development builds). +void SetDefaultDataDirectory(const std::string& dir); + +} // namespace mfcwx diff --git a/port/mfcwx/include/mfcwx/codepage.h b/port/mfcwx/include/mfcwx/codepage.h new file mode 100644 index 000000000..8ac2799c9 --- /dev/null +++ b/port/mfcwx/include/mfcwx/codepage.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +// The ANSI code page plays the role of the Windows system code page: CString, char* APIs and +// documents hold bytes in this encoding; mfcwx converts at every boundary to the toolkit. +namespace mfcwx { + +void SetAnsiCodePage(int cp); +int GetAnsiCodePage(); + +wchar_t AnsiToUnicode(unsigned char ch); +// Returns false if ch has no representation; out is set to '?'. +bool UnicodeToAnsi(wchar_t ch, char& out); + +std::string AnsiToUtf8(const char* s, int length = -1); +std::string Utf8ToAnsi(const char* utf8); + +// A path as used by the Windows code (ANSI bytes, '\\' or '/' separators) to a native UTF-8 path. +std::string NativePath(const char* path); +// A native UTF-8 path to the form the Windows code expects. +std::string AppPath(const char* nativePath); + +} // namespace mfcwx diff --git a/port/mfcwx/include/mfcwx/collections.h b/port/mfcwx/include/mfcwx/collections.h new file mode 100644 index 000000000..2cf2ba9db --- /dev/null +++ b/port/mfcwx/include/mfcwx/collections.h @@ -0,0 +1,451 @@ +#pragma once + +// MFC collection classes (afxtempl.h / afxcoll.h). + +#include +#include +#include + +struct __POSITION {}; +typedef __POSITION* POSITION; +#define BEFORE_START_POSITION ((POSITION)(intptr_t)-1) + +template +inline void CopyElements(TYPE* pDest, const TYPE* pSrc, INT_PTR nCount) { + for (INT_PTR i = 0; i < nCount; ++i) + pDest[i] = pSrc[i]; +} + +template +class CArray : public CObject { +public: + CArray() = default; + CArray(const CArray& other) : CObject(), m_data(other.m_data) {} + CArray& operator=(const CArray& other) { m_data = other.m_data; return *this; } + + INT_PTR GetSize() const { return static_cast(m_data.size()); } + INT_PTR GetCount() const { return GetSize(); } + BOOL IsEmpty() const { return m_data.empty(); } + INT_PTR GetUpperBound() const { return GetSize() - 1; } + void SetSize(INT_PTR nNewSize, INT_PTR nGrowBy = -1) { + if (nGrowBy > 0) + m_data.reserve(static_cast(nNewSize + nGrowBy)); + m_data.resize(static_cast(nNewSize < 0 ? 0 : nNewSize)); + } + void FreeExtra() { m_data.shrink_to_fit(); } + void RemoveAll() { m_data.clear(); } + const TYPE& GetAt(INT_PTR nIndex) const { return m_data[static_cast(nIndex)]; } + TYPE& GetAt(INT_PTR nIndex) { return m_data[static_cast(nIndex)]; } + void SetAt(INT_PTR nIndex, ARG_TYPE newElement) { m_data[static_cast(nIndex)] = newElement; } + const TYPE& ElementAt(INT_PTR nIndex) const { return m_data[static_cast(nIndex)]; } + TYPE& ElementAt(INT_PTR nIndex) { return m_data[static_cast(nIndex)]; } + const TYPE* GetData() const { return m_data.empty() ? nullptr : m_data.data(); } + TYPE* GetData() { return m_data.empty() ? nullptr : m_data.data(); } + void SetAtGrow(INT_PTR nIndex, ARG_TYPE newElement) { + if (nIndex >= GetSize()) + m_data.resize(static_cast(nIndex + 1)); + m_data[static_cast(nIndex)] = newElement; + } + INT_PTR Add(ARG_TYPE newElement) { + m_data.push_back(newElement); + return GetSize() - 1; + } + INT_PTR Append(const CArray& src) { + INT_PTR old = GetSize(); + m_data.insert(m_data.end(), src.m_data.begin(), src.m_data.end()); + return old; + } + void Copy(const CArray& src) { m_data = src.m_data; } + const TYPE& operator[](INT_PTR nIndex) const { return m_data[static_cast(nIndex)]; } + TYPE& operator[](INT_PTR nIndex) { return m_data[static_cast(nIndex)]; } + void InsertAt(INT_PTR nIndex, ARG_TYPE newElement, INT_PTR nCount = 1) { + if (nIndex > GetSize()) + m_data.resize(static_cast(nIndex)); + m_data.insert(m_data.begin() + nIndex, static_cast(nCount), newElement); + } + void InsertAt(INT_PTR nStartIndex, CArray* pNewArray) { + if (nStartIndex > GetSize()) + m_data.resize(static_cast(nStartIndex)); + m_data.insert(m_data.begin() + nStartIndex, pNewArray->m_data.begin(), pNewArray->m_data.end()); + } + void RemoveAt(INT_PTR nIndex, INT_PTR nCount = 1) { + m_data.erase(m_data.begin() + nIndex, m_data.begin() + nIndex + nCount); + } + void Serialize(CArchive& ar) override; + +protected: + std::vector m_data; +}; + +template +class CTypedPtrArray : public BASE_CLASS { +public: + TYPE GetAt(INT_PTR nIndex) const { return static_cast(BASE_CLASS::GetAt(nIndex)); } + TYPE& ElementAt(INT_PTR nIndex) { return reinterpret_cast(BASE_CLASS::ElementAt(nIndex)); } + void SetAt(INT_PTR nIndex, TYPE ptr) { BASE_CLASS::SetAt(nIndex, ptr); } + void SetAtGrow(INT_PTR nIndex, TYPE newElement) { BASE_CLASS::SetAtGrow(nIndex, newElement); } + INT_PTR Add(TYPE newElement) { return BASE_CLASS::Add(newElement); } + void InsertAt(INT_PTR nIndex, TYPE newElement, INT_PTR nCount = 1) { BASE_CLASS::InsertAt(nIndex, newElement, nCount); } + TYPE operator[](INT_PTR nIndex) const { return GetAt(nIndex); } + TYPE& operator[](INT_PTR nIndex) { return ElementAt(nIndex); } +}; + +template +class CList : public CObject { + struct CNode { + CNode* pNext; + CNode* pPrev; + TYPE data; + }; + +public: + explicit CList(INT_PTR = 10) {} + CList(const CList&) = delete; + CList& operator=(const CList&) = delete; + ~CList() override { RemoveAll(); } + + INT_PTR GetCount() const { return m_nCount; } + INT_PTR GetSize() const { return m_nCount; } + BOOL IsEmpty() const { return m_nCount == 0; } + TYPE& GetHead() { return m_pHead->data; } + const TYPE& GetHead() const { return m_pHead->data; } + TYPE& GetTail() { return m_pTail->data; } + const TYPE& GetTail() const { return m_pTail->data; } + TYPE RemoveHead() { + CNode* node = m_pHead; + TYPE value = node->data; + Unlink(node); + return value; + } + TYPE RemoveTail() { + CNode* node = m_pTail; + TYPE value = node->data; + Unlink(node); + return value; + } + POSITION AddHead(ARG_TYPE newElement) { return InsertBefore(reinterpret_cast(m_pHead), newElement); } + POSITION AddTail(ARG_TYPE newElement) { return InsertAfter(reinterpret_cast(m_pTail), newElement); } + void AddHead(CList* pNewList) { + for (CNode* n = pNewList->m_pTail; n; n = n->pPrev) + AddHead(n->data); + } + void AddTail(CList* pNewList) { + for (CNode* n = pNewList->m_pHead; n; n = n->pNext) + AddTail(n->data); + } + void RemoveAll() { + while (m_pHead) + Unlink(m_pHead); + } + POSITION GetHeadPosition() const { return reinterpret_cast(m_pHead); } + POSITION GetTailPosition() const { return reinterpret_cast(m_pTail); } + TYPE& GetNext(POSITION& rPosition) { + CNode* node = reinterpret_cast(rPosition); + rPosition = reinterpret_cast(node->pNext); + return node->data; + } + const TYPE& GetNext(POSITION& rPosition) const { + CNode* node = reinterpret_cast(rPosition); + rPosition = reinterpret_cast(node->pNext); + return node->data; + } + TYPE& GetPrev(POSITION& rPosition) { + CNode* node = reinterpret_cast(rPosition); + rPosition = reinterpret_cast(node->pPrev); + return node->data; + } + const TYPE& GetPrev(POSITION& rPosition) const { + CNode* node = reinterpret_cast(rPosition); + rPosition = reinterpret_cast(node->pPrev); + return node->data; + } + TYPE& GetAt(POSITION position) { return reinterpret_cast(position)->data; } + const TYPE& GetAt(POSITION position) const { return reinterpret_cast(position)->data; } + void SetAt(POSITION pos, ARG_TYPE newElement) { reinterpret_cast(pos)->data = newElement; } + void RemoveAt(POSITION position) { Unlink(reinterpret_cast(position)); } + POSITION InsertBefore(POSITION position, ARG_TYPE newElement) { + CNode* at = reinterpret_cast(position); + CNode* node = new CNode{at, at ? at->pPrev : m_pTail, newElement}; + if (!at) { + node->pNext = m_pHead; + node->pPrev = nullptr; + } + Link(node); + return reinterpret_cast(node); + } + POSITION InsertAfter(POSITION position, ARG_TYPE newElement) { + CNode* at = reinterpret_cast(position); + CNode* node = new CNode{at ? at->pNext : m_pHead, at, newElement}; + if (!at) { + node->pNext = nullptr; + node->pPrev = m_pTail; + } + Link(node); + return reinterpret_cast(node); + } + POSITION Find(ARG_TYPE searchValue, POSITION startAfter = nullptr) const { + CNode* n = startAfter ? reinterpret_cast(startAfter)->pNext : m_pHead; + for (; n; n = n->pNext) + if (n->data == searchValue) + return reinterpret_cast(n); + return nullptr; + } + POSITION FindIndex(INT_PTR nIndex) const { + if (nIndex < 0 || nIndex >= m_nCount) + return nullptr; + CNode* n = m_pHead; + while (nIndex-- > 0) + n = n->pNext; + return reinterpret_cast(n); + } + void Serialize(CArchive& ar) override; + +private: + void Link(CNode* node) { + if (node->pPrev) + node->pPrev->pNext = node; + else + m_pHead = node; + if (node->pNext) + node->pNext->pPrev = node; + else + m_pTail = node; + ++m_nCount; + } + void Unlink(CNode* node) { + if (node->pPrev) + node->pPrev->pNext = node->pNext; + else + m_pHead = node->pNext; + if (node->pNext) + node->pNext->pPrev = node->pPrev; + else + m_pTail = node->pPrev; + --m_nCount; + delete node; + } + + CNode* m_pHead = nullptr; + CNode* m_pTail = nullptr; + INT_PTR m_nCount = 0; +}; + +template +class CTypedPtrList : public BASE_CLASS { +public: + explicit CTypedPtrList(INT_PTR nBlockSize = 10) : BASE_CLASS(nBlockSize) {} + TYPE& GetHead() { return reinterpret_cast(BASE_CLASS::GetHead()); } + TYPE GetHead() const { return static_cast(BASE_CLASS::GetHead()); } + TYPE& GetTail() { return reinterpret_cast(BASE_CLASS::GetTail()); } + TYPE GetTail() const { return static_cast(BASE_CLASS::GetTail()); } + TYPE RemoveHead() { return static_cast(BASE_CLASS::RemoveHead()); } + TYPE RemoveTail() { return static_cast(BASE_CLASS::RemoveTail()); } + TYPE& GetNext(POSITION& rPosition) { return reinterpret_cast(BASE_CLASS::GetNext(rPosition)); } + TYPE GetNext(POSITION& rPosition) const { return static_cast(BASE_CLASS::GetNext(rPosition)); } + TYPE& GetPrev(POSITION& rPosition) { return reinterpret_cast(BASE_CLASS::GetPrev(rPosition)); } + TYPE GetPrev(POSITION& rPosition) const { return static_cast(BASE_CLASS::GetPrev(rPosition)); } + TYPE& GetAt(POSITION position) { return reinterpret_cast(BASE_CLASS::GetAt(position)); } + TYPE GetAt(POSITION position) const { return static_cast(BASE_CLASS::GetAt(position)); } + void SetAt(POSITION pos, TYPE newElement) { BASE_CLASS::SetAt(pos, newElement); } + POSITION AddHead(TYPE newElement) { return BASE_CLASS::AddHead(newElement); } + POSITION AddTail(TYPE newElement) { return BASE_CLASS::AddTail(newElement); } +}; + +template +struct CMapKeyLess { + bool operator()(const KEY& a, const KEY& b) const { return a < b; } +}; + +template +class CMap : public CObject { + struct CAssoc { + CAssoc* pNext; + CAssoc* pPrev; + KEY key; + VALUE value; + }; + +public: + explicit CMap(INT_PTR = 10) {} + CMap(const CMap&) = delete; + CMap& operator=(const CMap&) = delete; + ~CMap() override { RemoveAll(); } + + INT_PTR GetCount() const { return static_cast(m_index.size()); } + INT_PTR GetSize() const { return GetCount(); } + BOOL IsEmpty() const { return m_index.empty(); } + BOOL Lookup(ARG_KEY key, VALUE& rValue) const { + auto it = m_index.find(KEY(key)); + if (it == m_index.end()) + return FALSE; + rValue = it->second->value; + return TRUE; + } + VALUE& operator[](ARG_KEY key) { + KEY k(key); + auto it = m_index.find(k); + if (it != m_index.end()) + return it->second->value; + CAssoc* a = new CAssoc{nullptr, m_pTail, k, VALUE()}; + if (m_pTail) + m_pTail->pNext = a; + else + m_pHead = a; + m_pTail = a; + m_index.emplace(k, a); + return a->value; + } + void SetAt(ARG_KEY key, ARG_VALUE newValue) { (*this)[key] = newValue; } + BOOL RemoveKey(ARG_KEY key) { + auto it = m_index.find(KEY(key)); + if (it == m_index.end()) + return FALSE; + CAssoc* a = it->second; + m_index.erase(it); + if (a->pPrev) + a->pPrev->pNext = a->pNext; + else + m_pHead = a->pNext; + if (a->pNext) + a->pNext->pPrev = a->pPrev; + else + m_pTail = a->pPrev; + delete a; + return TRUE; + } + void RemoveAll() { + while (m_pHead) { + CAssoc* next = m_pHead->pNext; + delete m_pHead; + m_pHead = next; + } + m_pTail = nullptr; + m_index.clear(); + } + POSITION GetStartPosition() const { return reinterpret_cast(m_pHead); } + void GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue) const { + CAssoc* a = reinterpret_cast(rNextPosition); + rKey = a->key; + rValue = a->value; + rNextPosition = reinterpret_cast(a->pNext); + } + void InitHashTable(UINT, BOOL = TRUE) {} + UINT GetHashTableSize() const { return 17; } + +private: + CAssoc* m_pHead = nullptr; + CAssoc* m_pTail = nullptr; + std::map> m_index; +}; + +template +class CTypedPtrMap : public BASE_CLASS { +public: + BOOL Lookup(typename BASE_CLASS::BASE_ARG_KEY key, VALUE& rValue) const { + typename BASE_CLASS::BASE_VALUE v; + BOOL found = BASE_CLASS::Lookup(key, v); + rValue = static_cast(v); + return found; + } + VALUE& operator[](typename BASE_CLASS::BASE_ARG_KEY key) { return reinterpret_cast(BASE_CLASS::operator[](key)); } + void SetAt(KEY key, VALUE newValue) { BASE_CLASS::SetAt(key, newValue); } + BOOL RemoveKey(KEY key) { return BASE_CLASS::RemoveKey(key); } + void GetNextAssoc(POSITION& rPosition, KEY& rKey, VALUE& rValue) const { + typename BASE_CLASS::BASE_KEY k; + typename BASE_CLASS::BASE_VALUE v; + BASE_CLASS::GetNextAssoc(rPosition, k, v); + rKey = static_cast(k); + rValue = static_cast(v); + } +}; + +#define MFCWX_DECLARE_ARRAY(name, TYPE, ARG) \ + class name : public CArray { \ + DECLARE_SERIAL(name) \ + public: \ + name() = default; \ + name(const name& o) : CArray(o) {} \ + name& operator=(const name& o) { CArray::operator=(o); return *this; } \ + }; + +MFCWX_DECLARE_ARRAY(CStringArray, CString, const char*) +MFCWX_DECLARE_ARRAY(CPtrArray, void*, void*) +MFCWX_DECLARE_ARRAY(CObArray, CObject*, CObject*) +MFCWX_DECLARE_ARRAY(CDWordArray, DWORD, DWORD) +MFCWX_DECLARE_ARRAY(CUIntArray, UINT, UINT) +MFCWX_DECLARE_ARRAY(CWordArray, WORD, WORD) +MFCWX_DECLARE_ARRAY(CByteArray, BYTE, BYTE) + +#define MFCWX_DECLARE_LIST(name, TYPE, ARG) \ + class name : public CList { \ + DECLARE_SERIAL(name) \ + public: \ + explicit name(INT_PTR nBlockSize = 10) : CList(nBlockSize) {} \ + }; + +MFCWX_DECLARE_LIST(CStringList, CString, const char*) +MFCWX_DECLARE_LIST(CPtrList, void*, void*) +MFCWX_DECLARE_LIST(CObList, CObject*, CObject*) + +#define MFCWX_DECLARE_MAP(name, K, AK, V, AV) \ + class name : public CMap { \ + DECLARE_SERIAL(name) \ + public: \ + typedef K BASE_KEY; \ + typedef AK BASE_ARG_KEY; \ + typedef V BASE_VALUE; \ + typedef AV BASE_ARG_VALUE; \ + explicit name(INT_PTR nBlockSize = 10) : CMap(nBlockSize) {} \ + }; + +MFCWX_DECLARE_MAP(CMapStringToString, CString, const char*, CString, const char*) +MFCWX_DECLARE_MAP(CMapStringToPtr, CString, const char*, void*, void*) +MFCWX_DECLARE_MAP(CMapStringToOb, CString, const char*, CObject*, CObject*) +MFCWX_DECLARE_MAP(CMapPtrToPtr, void*, void*, void*, void*) +MFCWX_DECLARE_MAP(CMapPtrToWord, void*, void*, WORD, WORD) +MFCWX_DECLARE_MAP(CMapWordToPtr, WORD, WORD, void*, void*) +MFCWX_DECLARE_MAP(CMapWordToOb, WORD, WORD, CObject*, CObject*) + +template +void SerializeElements(CArchive& ar, TYPE* pElements, INT_PTR nCount) { + if (ar.IsStoring()) + ar.Write(pElements, static_cast(nCount * sizeof(TYPE))); + else + ar.Read(pElements, static_cast(nCount * sizeof(TYPE))); +} + +inline void SerializeElements(CArchive& ar, CString* pElements, INT_PTR nCount) { + for (INT_PTR i = 0; i < nCount; ++i) { + if (ar.IsStoring()) + ar << pElements[i]; + else + ar >> pElements[i]; + } +} + +template +void CArray::Serialize(CArchive& ar) { + if (ar.IsStoring()) { + ar.WriteCount(static_cast(GetSize())); + } else { + SetSize(ar.ReadCount()); + } + if (!m_data.empty()) + SerializeElements(ar, m_data.data(), GetSize()); +} + +template +void CList::Serialize(CArchive& ar) { + if (ar.IsStoring()) { + ar.WriteCount(static_cast(m_nCount)); + for (CNode* n = m_pHead; n; n = n->pNext) + SerializeElements(ar, &n->data, 1); + } else { + UINT count = ar.ReadCount(); + while (count--) { + TYPE value{}; + SerializeElements(ar, &value, 1); + AddTail(value); + } + } +} diff --git a/port/mfcwx/include/mfcwx/crtcompat.h b/port/mfcwx/include/mfcwx/crtcompat.h new file mode 100644 index 000000000..17fe75b03 --- /dev/null +++ b/port/mfcwx/include/mfcwx/crtcompat.h @@ -0,0 +1,394 @@ +#pragma once + +/* Microsoft C runtime extensions on top of the POSIX C library. C compatible. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _MFCWX_CRTCOMPAT +#define _MFCWX_CRTCOMPAT + +#define _CRT_SECURE_NO_WARNINGS +#define _MAX_PATH 260 +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 256 +#define _MAX_EXT 256 +#define _TRUNCATE ((size_t)-1) +#define STRUNCATE 80 + +#define _O_RDONLY O_RDONLY +#define _O_WRONLY O_WRONLY +#define _O_RDWR O_RDWR +#define _O_APPEND O_APPEND +#define _O_CREAT O_CREAT +#define _O_TRUNC O_TRUNC +#define _O_EXCL O_EXCL +#define _O_BINARY 0 +#define _O_TEXT 0 +#define O_BINARY 0 +#define O_TEXT 0 +#define _S_IREAD S_IRUSR +#define _S_IWRITE S_IWUSR +#define _S_IFDIR S_IFDIR +#define _S_IFREG S_IFREG +#define _S_IFMT S_IFMT +#define _SH_DENYNO 0x40 +#define _SH_DENYRW 0x10 +#define _SH_DENYWR 0x20 +#define _SH_DENYRD 0x30 + +#define _stat stat +#define _stati64 stat +#define _fstat fstat +#define _fstati64 fstat +#define _off_t off_t +#define _fsize_t unsigned long +#define _timeb timeb +#define _ftime(t) ftime(t) +#define _fseeki64 fseeko +#define _ftelli64 ftello +#define _memicmp mfcwx_memicmp +#define memicmp mfcwx_memicmp +#define __time64_t time_t +#define _time64 time +#define _localtime64 localtime +#define _gmtime64 gmtime +#define _mktime64 mktime +#define _ctime64 ctime +#define _difftime64 difftime + +#define _open mfcwx_open +#define _tell(fd) lseek((fd), 0, SEEK_CUR) +#define _telli64(fd) lseek((fd), 0, SEEK_CUR) +#define _lseeki64 _lseek +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#define _strcmpi strcasecmp +#define stricmp strcasecmp +#define strnicmp strncasecmp +#define strcmpi strcasecmp +#define _mbscmp(a, b) strcmp((const char*)(a), (const char*)(b)) +#define _mbsicmp(a, b) strcasecmp((const char*)(a), (const char*)(b)) +#define _mbslen(a) strlen((const char*)(a)) +#define _mbschr(a, c) ((unsigned char*)strchr((const char*)(a), (c))) +#define _mbsrchr(a, c) ((unsigned char*)strrchr((const char*)(a), (c))) +#define _mbsstr(a, b) ((unsigned char*)strstr((const char*)(a), (const char*)(b))) +#define _mbsinc(p) ((p) + 1) +#define _mbsdec(s, p) ((p) - 1) +#define _ismbblead(c) 0 +#define _snprintf snprintf +#define _vsnprintf vsnprintf +#define _vscprintf(fmt, args) vsnprintf(NULL, 0, (fmt), (args)) +#define _scprintf(...) snprintf(NULL, 0, __VA_ARGS__) +#define _snscanf sscanf +#define _strtoi64 strtoll +#define _strtoui64 strtoull +#define _atoi64 atoll +#define _wtoi(s) ((int)wcstol((s), NULL, 10)) +#define _isnan isnan +#define _finite isfinite +#define _hypot hypot +#define _copysign copysign +#define _chgsign(x) (-(x)) +#define _logb logb +#define _nextafter nextafter +#define _j0 j0 +#define _j1 j1 +#define _y0 y0 +#define _y1 y1 +#define _fpclass(x) fpclassify(x) +#define _CrtSetDbgFlag(x) 0 +#define _CrtDumpMemoryLeaks() 0 +#define _CrtCheckMemory() 1 +#define _CrtSetBreakAlloc(x) 0 +#define _CrtSetReportMode(a, b) 0 +#define _CRTDBG_ALLOC_MEM_DF 0x01 +#define _CRTDBG_LEAK_CHECK_DF 0x20 +#define _CRTDBG_REPORT_FLAG (-1) +#define _CRT_WARN 0 +#define _CRT_ERROR 1 +#define _CRT_ASSERT 2 +#define _CRTDBG_MODE_DEBUG 0x2 +#define _ASSERTE(expr) ((void)0) +#define _ASSERT(expr) ((void)0) +#define _RPT0(rptno, msg) ((void)0) +#define _RPT1(rptno, msg, a1) ((void)0) +#define _RPT2(rptno, msg, a1, a2) ((void)0) +#define _RPT3(rptno, msg, a1, a2, a3) ((void)0) +#define _RPTF0(rptno, msg) ((void)0) +#define _RPTF1(rptno, msg, a1) ((void)0) +#define _alloca alloca +#define _msize(p) mfcwx_msize(p) +#define _heapchk() (-2) +#define _HEAPOK (-2) +#define __min(a, b) (((a) < (b)) ? (a) : (b)) +#define __max(a, b) (((a) > (b)) ? (a) : (b)) +#define _rotl(v, s) mfcwx_rotl((v), (s)) +#define _rotr(v, s) mfcwx_rotr((v), (s)) +#define _lrotl(v, s) mfcwx_rotl((v), (s)) +#define _lrotr(v, s) mfcwx_rotr((v), (s)) +#define _byteswap_ulong(x) __builtin_bswap32(x) +#define _byteswap_ushort(x) __builtin_bswap16(x) +#define _byteswap_uint64(x) __builtin_bswap64(x) +#define _getch getchar +#define _getche getchar +#define getch getchar +#define _putch putchar +#define _kbhit() 0 +#define kbhit() 0 +#define _flushall() fflush(NULL) +#define _fcloseall() 0 +#define _fsopen(name, mode, sh) mfcwx_fopen((name), (mode)) +#define _wfopen(name, mode) NULL +#define _set_errno(e) (errno = (e), 0) +#define _get_errno(p) (*(p) = errno, 0) +#define _beginthread mfcwx_beginthread +#define _beginthreadex mfcwx_beginthreadex +#define _endthread() mfcwx_endthread(0) +#define _endthreadex(c) mfcwx_endthread(c) +#define _sleep(ms) mfcwx_sleep_ms(ms) +#define _clearfp() 0 +#define _controlfp(a, b) 0 +#define _control87(a, b) 0 +#define _MCW_EM 0x0008001f +#define _EM_INVALID 0x00000010 +#define _EM_ZERODIVIDE 0x00000008 +#define _EM_OVERFLOW 0x00000004 +#define _EM_UNDERFLOW 0x00000002 +#define _EM_INEXACT 0x00000001 +#define _EM_DENORMAL 0x00080000 +#define _PC_24 0x00020000 +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 + +#define _tcslen strlen +#define _tcscpy strcpy +#define _tcsncpy strncpy +#define _tcscat strcat +#define _tcsncat strncat +#define _tcscmp strcmp +#define _tcsncmp strncmp +#define _tcsicmp strcasecmp +#define _tcsnicmp strncasecmp +#define _tcschr strchr +#define _tcsrchr strrchr +#define _tcsstr strstr +#define _tcsspn strspn +#define _tcscspn strcspn +#define _tcspbrk strpbrk +#define _tcstok strtok +#define _tcsdup strdup +#define _tcsupr _strupr +#define _tcslwr _strlwr +#define _tcsrev _strrev +#define _tcstol strtol +#define _tcstoul strtoul +#define _tcstod strtod +#define _tcsftime strftime +#define _tcsinc(p) ((p) + 1) +#define _tcsdec(s, p) ((p) - 1) +#define _tcsnextc(p) ((unsigned int)(unsigned char)*(p)) +#define _tclen(p) 1 +#define _tccpy(d, s) (*(d) = *(s)) +#define _ttoi atoi +#define _ttol atol +#define _ttof atof +#define _tstoi atoi +#define _tstof atof +#define _ttoi64 atoll +#define _itot _itoa +#define _ltot _ltoa +#define _ultot _ultoa +#define _stprintf sprintf +#define _sntprintf snprintf +#define _vstprintf vsprintf +#define _vsntprintf vsnprintf +#define _tprintf printf +#define _ftprintf fprintf +#define _stscanf sscanf +#define _tfopen mfcwx_fopen +#define _tremove mfcwx_unlink +#define _trename mfcwx_rename +#define _tunlink mfcwx_unlink +#define _taccess mfcwx_access +#define _tmkdir _mkdir +#define _tgetcwd _getcwd +#define _tchdir mfcwx_chdir +#define _tsplitpath _splitpath +#define _tmakepath _makepath +#define _tfullpath _fullpath +#define _tsetlocale setlocale +#define _tgetenv getenv +#define _tsystem system +#define _istalpha isalpha +#define _istdigit isdigit +#define _istxdigit isxdigit +#define _istspace isspace +#define _istalnum isalnum +#define _istupper isupper +#define _istlower islower +#define _istprint isprint +#define _istpunct ispunct +#define _istcntrl iscntrl +#define _istgraph isgraph +#define _totupper toupper +#define _totlower tolower +#define _tcsclen strlen +#define _tcsnccpy strncpy +#define _tcsncpy_s(d, n, s, c) strncpy_s((d), (n), (s), (c)) +#define _tcscpy_s strcpy_s +#define _tcscat_s strcat_s +#define _stprintf_s sprintf_s +#define _tmain main +#define _tWinMain WinMain + +extern int __argc; +extern char** __argv; +int mfcwx_open(const char* name, int flags, ...); +int mfcwx_memicmp(const void* a, const void* b, size_t n); +int mfcwx_unlink(const char* name); +int mfcwx_rmdir(const char* name); +int mfcwx_chdir(const char* name); +int mfcwx_access(const char* name, int mode); +int mfcwx_chmod(const char* name, int mode); +int mfcwx_rename(const char* from, const char* to); +FILE* mfcwx_fopen(const char* name, const char* mode); +size_t mfcwx_msize(void* p); +unsigned int mfcwx_rotl(unsigned int v, int s); +unsigned int mfcwx_rotr(unsigned int v, int s); +void mfcwx_sleep_ms(unsigned long ms); +uintptr_t mfcwx_beginthread(void (*fn)(void*), unsigned stack, void* arg); +uintptr_t mfcwx_beginthreadex(void* security, unsigned stack, unsigned (*fn)(void*), void* arg, unsigned flags, + unsigned* threadId); +void mfcwx_endthread(unsigned code); +void mfcwx_normalize_path(char* path); +/* getcwd returning the application path form ("\\dir\\sub"); see mfcwx::AppPath. */ +char* mfcwx_getcwd(char* buf, int size); + +int _mkdir(const char* path); + +static inline int _close(int fd) { return close(fd); } +static inline int _read(int fd, void* buf, unsigned int n) { return (int)read(fd, buf, n); } +static inline int _write(int fd, const void* buf, unsigned int n) { return (int)write(fd, buf, n); } +static inline long _lseek(int fd, long off, int whence) { return (long)lseek(fd, off, whence); } +static inline int _dup(int fd) { return dup(fd); } +static inline int _dup2(int a, int b) { return dup2(a, b); } +static inline int _fileno(FILE* f) { return fileno(f); } +static inline FILE* _fdopen(int fd, const char* mode) { return fdopen(fd, mode); } +static inline int _unlink(const char* name) { return mfcwx_unlink(name); } +static inline int _rmdir(const char* name) { return mfcwx_rmdir(name); } +static inline int _chdir(const char* name) { return mfcwx_chdir(name); } +static inline char* _getcwd(char* buf, int size) { return mfcwx_getcwd(buf, size); } +static inline int _access(const char* name, int mode) { return mfcwx_access(name, mode); } +static inline int _chmod(const char* name, int mode) { return mfcwx_chmod(name, mode); } +static inline int _getpid(void) { return (int)getpid(); } +static inline int _isatty(int fd) { return isatty(fd); } +static inline int _umask(int mask) { return (int)umask((mode_t)mask); } +static inline char* _strdup(const char* s) { return strdup(s); } + +char* _strupr(char* s); +char* _strlwr(char* s); +char* _strrev(char* s); +char* strupr(char* s); +char* strlwr(char* s); +char* strrev(char* s); +char* _strset(char* s, int c); +char* _strnset(char* s, int c, size_t n); +char* _itoa(int value, char* buf, int radix); +char* _ltoa(long value, char* buf, int radix); +char* _ultoa(unsigned long value, char* buf, int radix); +char* _i64toa(long long value, char* buf, int radix); +char* _ui64toa(unsigned long long value, char* buf, int radix); +char* itoa(int value, char* buf, int radix); +char* ltoa(long value, char* buf, int radix); +char* ultoa(unsigned long value, char* buf, int radix); +char* _gcvt(double value, int digits, char* buf); +char* gcvt(double value, int digits, char* buf); +char* _ecvt(double value, int digits, int* dec, int* sign); +char* _fcvt(double value, int digits, int* dec, int* sign); +long _filelength(int fd); +long filelength(int fd); +long long _filelengthi64(int fd); +int _chsize(int fd, long size); +int _eof(int fd); +int _setmode(int fd, int mode); +void _splitpath(const char* path, char* drive, char* dir, char* fname, char* ext); +void _makepath(char* path, const char* drive, const char* dir, const char* fname, const char* ext); +char* _fullpath(char* abs, const char* rel, size_t size); +int _getdrive(void); +int _chdrive(int drive); +char* _mktemp(char* templ); +char* _tempnam(const char* dir, const char* prefix); +int _vsnprintf_s(char* buf, size_t size, size_t count, const char* fmt, va_list args); +int sprintf_s(char* buf, size_t size, const char* fmt, ...); +int _snprintf_s(char* buf, size_t size, size_t count, const char* fmt, ...); +int vsprintf_s(char* buf, size_t size, const char* fmt, va_list args); +int strcpy_s(char* dst, size_t size, const char* src); +int strncpy_s(char* dst, size_t size, const char* src, size_t count); +int strcat_s(char* dst, size_t size, const char* src); +int strncat_s(char* dst, size_t size, const char* src, size_t count); +char* strtok_s(char* s, const char* delim, char** ctx); +int _strupr_s(char* s, size_t size); +int _strlwr_s(char* s, size_t size); +int _itoa_s(int value, char* buf, size_t size, int radix); +int _ltoa_s(long value, char* buf, size_t size, int radix); +int _i64toa_s(long long value, char* buf, size_t size, int radix); +int fopen_s(FILE** f, const char* name, const char* mode); +int memcpy_s(void* dst, size_t dstSize, const void* src, size_t count); +int memmove_s(void* dst, size_t dstSize, const void* src, size_t count); +int localtime_s(struct tm* out, const time_t* t); +int gmtime_s(struct tm* out, const time_t* t); +int ctime_s(char* buf, size_t size, const time_t* t); +int asctime_s(char* buf, size_t size, const struct tm* t); +int _dupenv_s(char** buf, size_t* len, const char* name); +char* _strdate(char* buf); +char* _strtime(char* buf); +void _tzset(void); + +struct _finddata_t { + unsigned attrib; + time_t time_create; + time_t time_access; + time_t time_write; + unsigned long size; + char name[260]; +}; +#define _finddatai64_t _finddata_t +#define _finddata32_t _finddata_t +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 +intptr_t _findfirst(const char* pattern, struct _finddata_t* data); +int _findnext(intptr_t handle, struct _finddata_t* data); +int _findclose(intptr_t handle); +#define _findfirsti64 _findfirst +#define _findnexti64 _findnext + +#endif /* _MFCWX_CRTCOMPAT */ + +#ifdef __cplusplus +} +#endif diff --git a/port/mfcwx/include/mfcwx/cstring.h b/port/mfcwx/include/mfcwx/cstring.h new file mode 100644 index 000000000..6f418ccb4 --- /dev/null +++ b/port/mfcwx/include/mfcwx/cstring.h @@ -0,0 +1,164 @@ +#pragma once + +#include "mfcwx/win32.h" + +#include + +// MBCS CString: a byte string in the application's ANSI code page (see mfcwx/codepage.h). +class CString { +public: + CString() noexcept; + CString(const CString& s); + CString(CString&& s) noexcept; + CString(const char* s); + CString(const unsigned char* s); + CString(const char* s, int length); + CString(char ch, int repeat = 1); + CString(const wchar_t* s); + ~CString(); + + CString& operator=(const CString& s); + CString& operator=(CString&& s) noexcept; + CString& operator=(const char* s); + CString& operator=(const unsigned char* s); + CString& operator=(const wchar_t* s); + CString& operator=(char ch); + + int GetLength() const { return m_len; } + int GetAllocLength() const { return m_cap; } + bool IsEmpty() const { return m_len == 0; } + void Empty(); + char GetAt(int i) const { return m_p[i]; } + void SetAt(int i, char ch) { m_p[i] = ch; } + char operator[](int i) const { return m_p[i]; } + operator const char*() const { return m_p; } + const char* GetString() const { return m_p; } + + char* GetBuffer(); + char* GetBuffer(int minLength); + char* GetBufferSetLength(int length); + void ReleaseBuffer(int newLength = -1); + void ReleaseBufferSetLength(int newLength) { ReleaseBuffer(newLength); } + char* LockBuffer() { return GetBuffer(); } + void UnlockBuffer() {} + void FreeExtra() {} + void Preallocate(int length) { Reserve(length); } + void Truncate(int length); + void SetString(const char* s); + void SetString(const char* s, int length); + + CString& operator+=(const CString& s); + CString& operator+=(const char* s); + CString& operator+=(const unsigned char* s) { return *this += reinterpret_cast(s); } + CString& operator+=(char ch); + CString& operator+=(unsigned char ch) { return *this += static_cast(ch); } + CString& operator+=(const wchar_t* s); + void Append(const char* s); + void Append(const char* s, int length); + void Append(const CString& s) { *this += s; } + void AppendChar(char ch) { *this += ch; } + + int Compare(const char* s) const; + int CompareNoCase(const char* s) const; + int Collate(const char* s) const { return Compare(s); } + int CollateNoCase(const char* s) const { return CompareNoCase(s); } + + CString Mid(int first) const; + CString Mid(int first, int count) const; + CString Left(int count) const; + CString Right(int count) const; + CString SpanIncluding(const char* charSet) const; + CString SpanExcluding(const char* charSet) const; + CString Tokenize(const char* tokens, int& start) const; + + CString& MakeUpper(); + CString& MakeLower(); + CString& MakeReverse(); + int Replace(char oldCh, char newCh); + int Replace(const char* oldStr, const char* newStr); + int Remove(char ch); + int Insert(int index, char ch); + int Insert(int index, const char* s); + int Delete(int index, int count = 1); + + CString& TrimLeft(); + CString& TrimLeft(char target); + CString& TrimLeft(const char* targets); + CString& TrimRight(); + CString& TrimRight(char target); + CString& TrimRight(const char* targets); + CString& Trim() { TrimRight(); return TrimLeft(); } + CString& Trim(char target) { TrimRight(target); return TrimLeft(target); } + CString& Trim(const char* targets) { TrimRight(targets); return TrimLeft(targets); } + + int Find(char ch, int start = 0) const; + int Find(const char* sub, int start = 0) const; + int ReverseFind(char ch) const; + int FindOneOf(const char* charSet) const; + + void Format(const char* fmt, ...) __attribute__((format(printf, 2, 3))); + void Format(UINT formatId, ...); + void FormatV(const char* fmt, va_list args); + void AppendFormat(const char* fmt, ...) __attribute__((format(printf, 2, 3))); + void AppendFormat(UINT formatId, ...); + void AppendFormatV(const char* fmt, va_list args); + void FormatMessage(const char* fmt, ...); + void FormatMessage(UINT formatId, ...); + + BOOL LoadString(UINT id); + BOOL LoadStringA(UINT id) { return LoadString(id); } + BSTR AllocSysString() const; + BSTR SetSysString(BSTR* bstr) const; + void AnsiToOem() {} + void OemToAnsi() {} + + static int StringLength(const char* s) { return s ? static_cast(strlen(s)) : 0; } + + friend void swap(CString& a, CString& b) noexcept { + std::swap(a.m_p, b.m_p); + std::swap(a.m_len, b.m_len); + std::swap(a.m_cap, b.m_cap); + } + +private: + void Reserve(int capacity); + void Assign(const char* s, int length); + + char* m_p; + int m_len; + int m_cap; +}; + +CString operator+(const CString& a, const CString& b); +CString operator+(const CString& a, const char* b); +CString operator+(const char* a, const CString& b); +CString operator+(const CString& a, char b); +CString operator+(char a, const CString& b); +CString operator+(const CString& a, const wchar_t* b); + +inline bool operator==(const CString& a, const CString& b) { return a.Compare(b) == 0; } +inline bool operator==(const CString& a, const char* b) { return a.Compare(b) == 0; } +inline bool operator==(const char* a, const CString& b) { return b.Compare(a) == 0; } +inline bool operator==(const CString& a, char b) { return a.GetLength() == 1 && a[0] == b; } +inline bool operator!=(const CString& a, const CString& b) { return a.Compare(b) != 0; } +inline bool operator!=(const CString& a, const char* b) { return a.Compare(b) != 0; } +inline bool operator!=(const char* a, const CString& b) { return b.Compare(a) != 0; } +inline bool operator!=(const CString& a, char b) { return !(a == b); } +inline bool operator<(const CString& a, const CString& b) { return a.Compare(b) < 0; } +inline bool operator<(const CString& a, const char* b) { return a.Compare(b) < 0; } +inline bool operator<(const char* a, const CString& b) { return b.Compare(a) > 0; } +inline bool operator>(const CString& a, const CString& b) { return a.Compare(b) > 0; } +inline bool operator>(const CString& a, const char* b) { return a.Compare(b) > 0; } +inline bool operator>(const char* a, const CString& b) { return b.Compare(a) < 0; } +inline bool operator<=(const CString& a, const CString& b) { return a.Compare(b) <= 0; } +inline bool operator<=(const CString& a, const char* b) { return a.Compare(b) <= 0; } +inline bool operator<=(const char* a, const CString& b) { return b.Compare(a) >= 0; } +inline bool operator>=(const CString& a, const CString& b) { return a.Compare(b) >= 0; } +inline bool operator>=(const CString& a, const char* b) { return a.Compare(b) >= 0; } +inline bool operator>=(const char* a, const CString& b) { return b.Compare(a) <= 0; } + +typedef CString CStringA; +typedef CString CStringT; + +// Translates Microsoft-specific printf conversions (%I64d, %I32u, ...) to their C99 forms. +const char* AfxTranslateFormat(const char* fmt, char* buffer, size_t size); diff --git a/port/mfcwx/include/mfcwx/docview.h b/port/mfcwx/include/mfcwx/docview.h new file mode 100644 index 000000000..57df9a525 --- /dev/null +++ b/port/mfcwx/include/mfcwx/docview.h @@ -0,0 +1,467 @@ +#pragma once + +// Document/view architecture, frames and control bars. + +class CCreateContext { +public: + CCreateContext() = default; + CRuntimeClass* m_pNewViewClass = nullptr; + CDocument* m_pCurrentDoc = nullptr; + CDocTemplate* m_pNewDocTemplate = nullptr; + CView* m_pLastView = nullptr; + CFrameWnd* m_pCurrentFrame = nullptr; +}; + +class CPrintDialog; + +class CPrintInfo { +public: + CPrintInfo(); + ~CPrintInfo(); + void SetMinPage(UINT nMinPage) { m_nMinPage = nMinPage; } + void SetMaxPage(UINT nMaxPage) { m_nMaxPage = nMaxPage; } + UINT GetMinPage() const { return m_nMinPage; } + UINT GetMaxPage() const { return m_nMaxPage; } + UINT GetFromPage() const { return m_nMinPage; } + UINT GetToPage() const { return m_nMaxPage; } + UINT GetOffsetPage() const { return 0; } + CPrintDialog* m_pPD; + BOOL m_bDirect; + BOOL m_bPreview; + BOOL m_bContinuePrinting; + UINT m_nCurPage; + UINT m_nNumPreviewPages; + CString m_strPageDesc; + LPVOID m_lpUserData; + CRect m_rectDraw; + UINT m_nMinPage; + UINT m_nMaxPage; +}; + +class CDocument : public CCmdTarget { + DECLARE_DYNAMIC(CDocument) +public: + CDocument(); + ~CDocument() override; + + const CString& GetTitle() const { return m_strTitle; } + virtual void SetTitle(const char* lpszTitle); + const CString& GetPathName() const { return m_strPathName; } + virtual void SetPathName(const char* lpszPathName, BOOL bAddToMRU = TRUE); + CDocTemplate* GetDocTemplate() const { return m_pDocTemplate; } + virtual BOOL IsModified() { return m_bModified; } + virtual void SetModifiedFlag(BOOL bModified = TRUE) { m_bModified = bModified; } + virtual POSITION GetFirstViewPosition() const; + virtual CView* GetNextView(POSITION& rPosition) const; + void UpdateAllViews(CView* pSender, LPARAM lHint = 0, CObject* pHint = nullptr); + void AddView(CView* pView); + void RemoveView(CView* pView); + virtual void DeleteContents() {} + virtual BOOL OnNewDocument(); + virtual BOOL OnOpenDocument(const char* lpszPathName); + virtual BOOL OnSaveDocument(const char* lpszPathName); + virtual void OnCloseDocument(); + virtual void ReportSaveLoadException(const char* lpszPathName, CException* e, BOOL bSaving, UINT nIDPDefault); + virtual CFile* GetFile(const char* lpszFileName, UINT nOpenFlags, CFileException* pError); + virtual void ReleaseFile(CFile* pFile, BOOL bAbort); + virtual BOOL CanCloseFrame(CFrameWnd* pFrame); + virtual BOOL SaveModified(); + virtual void PreCloseFrame(CFrameWnd* pFrame) {} + virtual BOOL DoSave(const char* lpszPathName, BOOL bReplace = TRUE); + virtual BOOL DoFileSave(); + virtual void OnChangedViewList(); + virtual void SetModifiedFlagNoUpdate(BOOL b) { m_bModified = b; } + virtual void OnIdle() {} + void SendInitialUpdate(); + BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) override; + + afx_msg void OnFileClose(); + afx_msg void OnFileSave(); + afx_msg void OnFileSaveAs(); + + CString m_strTitle; + CString m_strPathName; + CDocTemplate* m_pDocTemplate; + std::vector m_viewList; + BOOL m_bModified; + BOOL m_bAutoDelete; + BOOL m_bEmbedded; + +protected: + DECLARE_MESSAGE_MAP() +}; + +class CView : public CWnd { + DECLARE_DYNAMIC(CView) +public: + CView(); + ~CView() override; + + CDocument* GetDocument() const { return m_pDocument; } + BOOL PreCreateWindow(CREATESTRUCT& cs) override; + BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) override; + virtual void OnInitialUpdate(); + virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); + virtual void OnDraw(CDC* pDC) = 0; + virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = nullptr); + virtual void OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView); + virtual void OnActivateFrame(UINT, CFrameWnd*) {} + virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); + virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); + virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo); + virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); + virtual void OnEndPrintPreview(CDC*, CPrintInfo*, POINT, void*) {} + virtual BOOL IsSelected(const CObject*) const { return FALSE; } + virtual BOOL OnScrollBy(CSize, BOOL = TRUE) { return FALSE; } + virtual BOOL OnScroll(UINT, UINT, BOOL = TRUE) { return FALSE; } + BOOL DoPreparePrinting(CPrintInfo* pInfo); + void PostNcDestroy() override; + + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnDestroy(); + afx_msg void OnPaint(); + afx_msg void OnFilePrint(); + afx_msg void OnFilePrintPreview(); + + CDocument* m_pDocument; + +protected: + DECLARE_MESSAGE_MAP() +}; + +class CScrollView : public CView { + DECLARE_DYNAMIC(CScrollView) +public: + CScrollView(); + static const SIZE sizeDefault; + void SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, + const SIZE& sizeLine = sizeDefault); + void SetScaleToFitSize(SIZE sizeTotal); + CPoint GetScrollPosition() const; + CPoint GetDeviceScrollPosition() const; + CSize GetTotalSize() const { return m_totalLog; } + void ScrollToPosition(POINT pt); + void FillOutsideRect(CDC* pDC, CBrush* pBrush); + void ResizeParentToFit(BOOL bShrinkOnly = TRUE); + void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = nullptr) override; + + int m_nMapMode; + CSize m_totalLog; + CSize m_totalDev; + CSize m_pageDev; + CSize m_lineDev; +}; + +class CFrameWnd : public CWnd { + DECLARE_DYNCREATE(CFrameWnd) +public: + static const CRect rectDefault; + CFrameWnd(); + ~CFrameWnd() override; + + virtual BOOL Create(const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle = WS_OVERLAPPEDWINDOW, + const RECT& rect = rectDefault, CWnd* pParentWnd = nullptr, const char* lpszMenuName = nullptr, + DWORD dwExStyle = 0, CCreateContext* pContext = nullptr); + virtual BOOL LoadFrame(UINT nIDResource, DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | 0x00008000L, + CWnd* pParentWnd = nullptr, CCreateContext* pContext = nullptr); + BOOL PreCreateWindow(CREATESTRUCT& cs) override; + BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) override; + BOOL OnCommand(WPARAM wParam, LPARAM lParam) override; + BOOL PreTranslateMessage(MSG* pMsg) override; + void PostNcDestroy() override; + + virtual CFrameWnd* GetActiveFrame(); + CView* GetActiveView() const; + void SetActiveView(CView* pViewNew, BOOL bNotify = TRUE); + virtual CDocument* GetActiveDocument(); + virtual void InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible); + virtual void ActivateFrame(int nCmdShow = -1); + virtual void OnUpdateFrameTitle(BOOL bAddToTitle); + virtual void OnUpdateFrameMenu(HMENU hMenuAlt); + virtual void RecalcLayout(BOOL bNotify = TRUE); + virtual void GetMessageString(UINT nID, CString& rMessage) const; + virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext); + virtual void SetMessageText(const char* lpszText); + void SetMessageText(UINT nID); + CWnd* CreateView(CCreateContext* pContext, UINT nID = AFX_IDW_PANE_FIRST); + void SetTitle(const char* lpszTitle) { m_strTitle = lpszTitle; } + CString GetTitle() const { return m_strTitle; } + void EnableDocking(DWORD dwDockStyle); + void DockControlBar(CControlBar* pBar, UINT nDockBarID = 0, LPCRECT lpRect = nullptr); + void FloatControlBar(CControlBar*, CPoint, DWORD = CBRS_ALIGN_TOP) {} + void ShowControlBar(CControlBar* pBar, BOOL bShow, BOOL bDelay); + CControlBar* GetControlBar(UINT nID); + BOOL IsTracking() const { return FALSE; } + void BeginModalState() {} + void EndModalState() {} + BOOL InModalState() const { return FALSE; } + void SetDockState(const void*) {} + void LoadBarState(const char*) {} + void SaveBarState(const char*) const {} + void OnSetPreviewMode(BOOL, void*) {} + void UpdateFrameTitleForDocument(const char* lpszDocName); + void NotifyFloatingWindows(DWORD) {} + BOOL IsFrameWnd() const { return TRUE; } + HMENU GetDefaultMenu() { return m_hMenuDefault; } + + afx_msg int OnCreate(LPCREATESTRUCT lpcs); + afx_msg void OnClose(); + afx_msg void OnDestroy(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnUpdateControlBarMenu(CCmdUI* pCmdUI); + afx_msg void OnUpdateKeyIndicator(CCmdUI* pCmdUI); + afx_msg BOOL OnBarCheck(UINT nID); + afx_msg void OnHelp(); + afx_msg void OnContextHelp(); + + CString m_strTitle; + UINT m_nIDHelp; + HMENU m_hMenuDefault; + HACCEL m_hAccelTable; + BOOL m_bAutoMenuEnable; + UINT m_nIdleFlags; + CView* m_pViewActive; + std::vector m_listControlBars; + CStatusBar* m_pStatusBar; + +protected: + DECLARE_MESSAGE_MAP() +}; + +class CMDIChildWnd; + +class CMDIFrameWnd : public CFrameWnd { + DECLARE_DYNAMIC(CMDIFrameWnd) +public: + CMDIFrameWnd(); + BOOL LoadFrame(UINT nIDResource, DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | 0x00008000L, + CWnd* pParentWnd = nullptr, CCreateContext* pContext = nullptr) override; + BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) override; + CFrameWnd* GetActiveFrame() override; + void OnUpdateFrameTitle(BOOL bAddToTitle) override; + void OnUpdateFrameMenu(HMENU hMenuAlt) override; + BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) override; + void RecalcLayout(BOOL bNotify = TRUE) override; + + void MDIActivate(CWnd* pWndActivate); + CMDIChildWnd* MDIGetActive(BOOL* pbMaximized = nullptr) const; + void MDIIconArrange() {} + void MDIMaximize(CWnd* pWnd); + void MDINext(); + void MDIPrev(); + void MDIRestore(CWnd* pWnd); + CMenu* MDISetMenu(CMenu* pFrameMenu, CMenu* pWindowMenu); + void MDITile(); + void MDICascade(); + void MDITile(int) { MDITile(); } + void MDICascade(int) { MDICascade(); } + CMDIChildWnd* CreateNewChild(CRuntimeClass* pClass, UINT nResource, HMENU hMenu = nullptr, HACCEL hAccel = nullptr); + HWND m_hWndMDIClient; + + afx_msg void OnWindowNew(); + afx_msg void OnWindowCascade(); + afx_msg void OnWindowTile(); + afx_msg void OnUpdateMDIWindowCmd(CCmdUI* pCmdUI); + + // implementation: all MDI children in creation order; notifies children and menus of tab switches + std::vector m_children; + void OnChildActivated(); + +protected: + DECLARE_MESSAGE_MAP() +}; + +class CMDIChildWnd : public CFrameWnd { + DECLARE_DYNCREATE(CMDIChildWnd) +public: + CMDIChildWnd(); + ~CMDIChildWnd() override; + virtual BOOL Create(const char* lpszClassName, const char* lpszWindowName, + DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, const RECT& rect = rectDefault, + CMDIFrameWnd* pParentWnd = nullptr, CCreateContext* pContext = nullptr); + BOOL LoadFrame(UINT nIDResource, DWORD dwDefaultStyle = WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW | 0x00008000L, + CWnd* pParentWnd = nullptr, CCreateContext* pContext = nullptr) override; + BOOL DestroyWindow() override; + BOOL PreCreateWindow(CREATESTRUCT& cs) override; + void ActivateFrame(int nCmdShow = -1) override; + void OnUpdateFrameMenu(BOOL bActive, CWnd* pActivateWnd, HMENU hMenuAlt); + void OnUpdateFrameTitle(BOOL bAddToTitle) override; + CMDIFrameWnd* GetMDIFrame() const; + void MDIDestroy(); + void MDIActivate(); + void MDIMaximize(); + void MDIRestore(); + void SetHandles(HMENU hMenu, HACCEL hAccel) { m_hMenuShared = hMenu; m_hAccelTable = hAccel; } + BOOL PreTranslateMessage(MSG* pMsg) override; + + HMENU m_hMenuShared; + CMDIFrameWnd* m_pMDIFrame; + bool m_bActive; + +protected: + DECLARE_MESSAGE_MAP() +}; + +class CDocTemplate : public CCmdTarget { + DECLARE_DYNAMIC(CDocTemplate) +public: + enum DocStringIndex { windowTitle, docName, fileNewName, filterName, filterExt, regFileTypeId, regFileTypeName }; + enum Confidence { noAttempt, maybeAttemptForeign, maybeAttemptNative, yesAttemptForeign, yesAttemptNative, yesAlreadyOpen }; + + CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass); + ~CDocTemplate() override; + + virtual void LoadTemplate(); + virtual POSITION GetFirstDocPosition() const = 0; + virtual CDocument* GetNextDoc(POSITION& rPos) const = 0; + virtual void AddDocument(CDocument* pDoc); + virtual void RemoveDocument(CDocument* pDoc); + virtual BOOL GetDocString(CString& rString, enum DocStringIndex index) const; + virtual CDocument* CreateNewDocument(); + virtual CFrameWnd* CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther); + virtual void InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc, BOOL bMakeVisible = TRUE); + virtual BOOL SaveAllModified(); + virtual void CloseAllDocuments(BOOL bEndSession); + virtual CDocument* OpenDocumentFile(const char* lpszPathName, BOOL bMakeVisible = TRUE) = 0; + virtual void SetDefaultTitle(CDocument* pDocument) = 0; + virtual Confidence MatchDocType(const char* lpszPathName, CDocument*& rpDocMatch); + void SetContainerInfo(UINT) {} + void SetServerInfo(UINT, UINT = 0, CRuntimeClass* = nullptr) {} + + UINT m_nIDResource; + CRuntimeClass* m_pDocClass; + CRuntimeClass* m_pFrameClass; + CRuntimeClass* m_pViewClass; + CString m_strDocStrings; + BOOL m_bAutoDelete; +}; + +class CMultiDocTemplate : public CDocTemplate { + DECLARE_DYNAMIC(CMultiDocTemplate) +public: + CMultiDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, + CRuntimeClass* pViewClass); + ~CMultiDocTemplate() override; + void LoadTemplate() override; + POSITION GetFirstDocPosition() const override; + CDocument* GetNextDoc(POSITION& rPos) const override; + void AddDocument(CDocument* pDoc) override; + void RemoveDocument(CDocument* pDoc) override; + CDocument* OpenDocumentFile(const char* lpszPathName, BOOL bMakeVisible = TRUE) override; + void SetDefaultTitle(CDocument* pDocument) override; + + HMENU m_hMenuShared; + HACCEL m_hAccelTable; + std::vector m_docList; + UINT m_nUntitledCount; +}; + +class CSingleDocTemplate : public CDocTemplate { + DECLARE_DYNAMIC(CSingleDocTemplate) +public: + CSingleDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, + CRuntimeClass* pViewClass); + POSITION GetFirstDocPosition() const override; + CDocument* GetNextDoc(POSITION& rPos) const override; + void AddDocument(CDocument* pDoc) override; + void RemoveDocument(CDocument* pDoc) override; + CDocument* OpenDocumentFile(const char* lpszPathName, BOOL bMakeVisible = TRUE) override; + void SetDefaultTitle(CDocument* pDocument) override; + CDocument* m_pOnlyDoc; +}; + +// --------------------------------------------------------------------------------------------- +// Control bars + +class CControlBar : public CWnd { + DECLARE_DYNAMIC(CControlBar) +public: + CControlBar(); + DWORD GetBarStyle() { return m_dwStyle; } + void SetBarStyle(DWORD dwStyle) { m_dwStyle = dwStyle; } + void EnableDocking(DWORD dwDockStyle) { m_dwDockStyle = dwDockStyle; } + BOOL IsFloating() const { return FALSE; } + CFrameWnd* GetDockingFrame() const { return GetParentFrame(); } + virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz); + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + DWORD m_dwStyle; + DWORD m_dwDockStyle; +}; + +#define TBBS_BUTTON 0x0000 +#define TBBS_SEPARATOR 0x0001 +#define TBBS_CHECKBOX 0x0002 +#define TBBS_GROUP 0x0004 +#define TBBS_CHECKGROUP (TBBS_GROUP | TBBS_CHECKBOX) +#define TBBS_CHECKED 0x0400 +#define TBBS_PRESSED 0x0200 +#define TBBS_DISABLED 0x0100 +#define TBBS_INDETERMINATE 0x0800 +#define TBBS_HIDDEN 0x1000 + +class CToolBar : public CControlBar { + DECLARE_DYNAMIC(CToolBar) +public: + CToolBar(); + BOOL Create(CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR); + BOOL CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle = TBSTYLE_FLAT, + DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect rcBorders = CRect(0, 0, 0, 0), + UINT nID = AFX_IDW_TOOLBAR); + BOOL LoadToolBar(const char* lpszResourceName); + BOOL LoadToolBar(UINT nIDResource); + BOOL LoadBitmap(const char* lpszResourceName); + BOOL LoadBitmap(UINT nIDResource); + BOOL SetButtons(const UINT* lpIDArray, int nIDCount); + void SetSizes(SIZE sizeButton, SIZE sizeImage); + int CommandToIndex(UINT nIDFind) const; + UINT GetItemID(int nIndex) const; + void GetItemRect(int nIndex, LPRECT lpRect) const; + UINT GetButtonStyle(int nIndex) const; + void SetButtonStyle(int nIndex, UINT nStyle); + int GetCount() const; + void SetButtonText(int, const char*) {} + void SetHeight(int) {} + + std::vector m_buttonIDs; + UINT m_nResourceID; +}; + +#define SBPS_NORMAL 0x0000 +#define SBPS_NOBORDERS 0x0100 +#define SBPS_POPOUT 0x0200 +#define SBPS_OWNERDRAW 0x1000 +#define SBPS_DISABLED 0x04000000 +#define SBPS_STRETCH 0x08000000 + +class CStatusBar : public CControlBar { + DECLARE_DYNAMIC(CStatusBar) +public: + CStatusBar(); + BOOL Create(CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR); + BOOL CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle = 0, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, + UINT nID = AFX_IDW_STATUS_BAR); + BOOL SetIndicators(const UINT* lpIDArray, int nIDCount); + int CommandToIndex(UINT nIDFind) const; + UINT GetItemID(int nIndex) const; + void GetItemRect(int nIndex, LPRECT lpRect) const; + CString GetPaneText(int nIndex) const; + void GetPaneText(int nIndex, CString& rString) const; + BOOL SetPaneText(int nIndex, const char* lpszNewText, BOOL bUpdate = TRUE); + void GetPaneInfo(int nIndex, UINT& nID, UINT& nStyle, int& cxWidth) const; + void SetPaneInfo(int nIndex, UINT nID, UINT nStyle, int cxWidth); + UINT GetPaneStyle(int nIndex) const; + void SetPaneStyle(int nIndex, UINT nStyle); + CString GetText() const { return GetPaneText(0); } + void SetText(const char* lpsz) { SetPaneText(0, lpsz); } + void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) override; + + std::vector m_indicators; + std::vector m_paneStyles; + std::vector m_paneTexts; +}; + +class CDialogBar : public CControlBar { +public: + BOOL Create(CWnd*, UINT, UINT, UINT) { return FALSE; } +}; diff --git a/port/mfcwx/include/mfcwx/extras.h b/port/mfcwx/include/mfcwx/extras.h new file mode 100644 index 000000000..0bc660c4d --- /dev/null +++ b/port/mfcwx/include/mfcwx/extras.h @@ -0,0 +1,162 @@ +#pragma once + +// Assorted Win32/MFC declarations used by the application that do not fit elsewhere. + +#define CS_VREDRAW 0x0001 +#define CS_HREDRAW 0x0002 +#define CS_DBLCLKS 0x0008 +#define CS_OWNDC 0x0020 +#define CS_CLASSDC 0x0040 +#define CS_PARENTDC 0x0080 +#define CS_NOCLOSE 0x0200 +#define CS_SAVEBITS 0x0800 +#define CS_BYTEALIGNCLIENT 0x1000 +#define CS_GLOBALCLASS 0x4000 +#define GCL_HCURSOR (-12) +#define GCL_HICON (-14) +#define GCL_HBRBACKGROUND (-10) +#define GCLP_HCURSOR (-12) +#define GCLP_HICON (-14) +#define SM_CXDRAG 68 +#define SM_CYDRAG 69 +#define TCS_EX_FLATSEPARATORS 0x00000001 +#define TCS_EX_REGISTERDROP 0x00000002 +#define LOCALE_IMEASURE 0x0000000D +#define LOCALE_SDECIMAL 0x0000000E +#define LOCALE_STHOUSAND 0x0000000F +#define LOCALE_SLANGUAGE 0x00000002 +#define LOCALE_SENGLANGUAGE 0x00001001 +#define LOCALE_SABBREVLANGNAME 0x00000003 +#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004 +#define UNUSED(x) (void)(x) +#define UNUSED_ALWAYS(x) (void)(x) + +LONG GetClassLong(HWND hWnd, int nIndex); +LONG SetClassLong(HWND hWnd, int nIndex, LONG dwNewLong); +ULONG_PTR SetClassLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong); +BOOL GetClassInfo(HINSTANCE hInstance, const char* lpClassName, WNDCLASS* lpWndClass); +ATOM RegisterClass(const WNDCLASS* lpWndClass); +BOOL UnregisterClass(const char* lpClassName, HINSTANCE hInstance); +HWND CreateWindowEx(DWORD dwExStyle, const char* lpClassName, const char* lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); +HWND CreateWindow(const char* lpClassName, const char* lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, + int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); +HWND GetNextWindow(HWND hWnd, UINT wCmd); +BOOL DestroyCaret(); +BOOL CreateCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight); +BOOL ShowCaret(HWND hWnd); +BOOL HideCaret(HWND hWnd); +BOOL SetCaretPos(int X, int Y); +int GetLocaleInfo(LCID Locale, DWORD LCType, char* lpLCData, int cchData); +int GetLocaleInfoA(LCID Locale, DWORD LCType, char* lpLCData, int cchData); +BOOL GetOpenFileName(OPENFILENAME* lpofn); +BOOL GetSaveFileName(OPENFILENAME* lpofn); +BOOL GetOpenFileNameA(OPENFILENAME* lpofn); +BOOL GetSaveFileNameA(OPENFILENAME* lpofn); +BOOL ChooseColor(CHOOSECOLOR* lpcc); +BOOL MessageBeep(UINT uType); +BOOL FlashWindow(HWND hWnd, BOOL bInvert); + +#define PD_ALLPAGES 0x00000000 +#define PD_SELECTION 0x00000001 +#define PD_PAGENUMS 0x00000002 +#define PD_NOSELECTION 0x00000004 +#define PD_NOPAGENUMS 0x00000008 +#define PD_COLLATE 0x00000010 +#define PD_PRINTTOFILE 0x00000020 +#define PD_PRINTSETUP 0x00000040 +#define PD_RETURNDC 0x00000100 +#define PD_USEDEVMODECOPIES 0x00040000 +#define PD_DISABLEPRINTTOFILE 0x00080000 +#define PD_HIDEPRINTTOFILE 0x00100000 +typedef struct tagPDA { + DWORD lStructSize; + HWND hwndOwner; + HGLOBAL hDevMode, hDevNames; + HDC hDC; + DWORD Flags; + WORD nFromPage, nToPage, nMinPage, nMaxPage, nCopies; + HINSTANCE hInstance; + LPARAM lCustData; +} PRINTDLG, *LPPRINTDLG; +typedef struct _devicemodeA { char dmDeviceName[32]; WORD dmSpecVersion, dmDriverVersion, dmSize, dmDriverExtra; DWORD dmFields; short dmOrientation, dmPaperSize, dmPaperLength, dmPaperWidth; } DEVMODE, *LPDEVMODE; +typedef struct tagDEVNAMES { WORD wDriverOffset, wDeviceOffset, wOutputOffset, wDefault; } DEVNAMES, *LPDEVNAMES; +#define DMORIENT_PORTRAIT 1 +#define DMORIENT_LANDSCAPE 2 + +typedef struct tagPALETTEENTRY { BYTE peRed, peGreen, peBlue, peFlags; } PALETTEENTRY, *LPPALETTEENTRY; +typedef struct tagLOGPALETTE { WORD palVersion, palNumEntries; PALETTEENTRY palPalEntry[1]; } LOGPALETTE; +#define PC_RESERVED 0x01 +#define PC_EXPLICIT 0x02 +#define PC_NOCOLLAPSE 0x04 + +#define ListView_GetSubItemRect(hwnd, iItem, iSubItem, code, prc) \ + (BOOL)::SendMessage((hwnd), LVM_GETSUBITEMRECT, (WPARAM)(int)(iItem), \ + ((prc) ? ((((LPRECT)(prc))->top = (iSubItem)), (((LPRECT)(prc))->left = (code)), (LPARAM)(prc)) : (LPARAM)(LPRECT)NULL)) +#define ListView_GetTopIndex(hwnd) (int)::SendMessage((hwnd), LVM_GETTOPINDEX, 0, 0) +#define ListView_GetItemText(hwndLV, i, iSubItem_, pszText_, cchTextMax_) \ + { LVITEM _lvi; _lvi.iSubItem = (iSubItem_); _lvi.cchTextMax = (cchTextMax_); _lvi.pszText = (pszText_); \ + ::SendMessage((hwndLV), LVM_GETITEMTEXT, (WPARAM)(i), (LPARAM)&_lvi); } +#define ListView_SetExtendedListViewStyle(hwnd, style) ::SendMessage((hwnd), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (style)) +#define ListView_GetItemCount(hwnd) (int)::SendMessage((hwnd), LVM_GETITEMCOUNT, 0, 0) + +class CWaitCursor { +public: + CWaitCursor(); + ~CWaitCursor(); + void Restore() {} +}; + +// WGL: OpenGL rendering into a window. mfcwx backs the window's client area with a wxGLCanvas. +typedef struct tagPIXELFORMATDESCRIPTOR { + WORD nSize, nVersion; + DWORD dwFlags; + BYTE iPixelType, cColorBits, cRedBits, cRedShift, cGreenBits, cGreenShift, cBlueBits, cBlueShift, cAlphaBits, + cAlphaShift, cAccumBits, cAccumRedBits, cAccumGreenBits, cAccumBlueBits, cAccumAlphaBits, cDepthBits, + cStencilBits, cAuxBuffers, iLayerType, bReserved; + DWORD dwLayerMask, dwVisibleMask, dwDamageMask; +} PIXELFORMATDESCRIPTOR, *PPIXELFORMATDESCRIPTOR, *LPPIXELFORMATDESCRIPTOR; +#define PFD_TYPE_RGBA 0 +#define PFD_TYPE_COLORINDEX 1 +#define PFD_MAIN_PLANE 0 +#define PFD_DOUBLEBUFFER 0x00000001 +#define PFD_STEREO 0x00000002 +#define PFD_DRAW_TO_WINDOW 0x00000004 +#define PFD_DRAW_TO_BITMAP 0x00000008 +#define PFD_SUPPORT_GDI 0x00000010 +#define PFD_SUPPORT_OPENGL 0x00000020 +#define PFD_GENERIC_FORMAT 0x00000040 +#define PFD_NEED_PALETTE 0x00000080 +#define PFD_NEED_SYSTEM_PALETTE 0x00000100 +#define PFD_SWAP_EXCHANGE 0x00000200 +#define PFD_GENERIC_ACCELERATED 0x00001000 +int ChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd); +BOOL SetPixelFormat(HDC hdc, int format, const PIXELFORMATDESCRIPTOR* ppfd); +int GetPixelFormat(HDC hdc); +int DescribePixelFormat(HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd); +BOOL SwapBuffers(HDC hdc); +HGLRC wglCreateContext(HDC hdc); +BOOL wglDeleteContext(HGLRC hglrc); +BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc); +HGLRC wglGetCurrentContext(); +HDC wglGetCurrentDC(); +void* wglGetProcAddress(const char* name); + +// --------------------------------------------------------------------------------------------- +// Declarations required by the application sources (CrypTool, ChallengeResponse, libVolRen). + +#define _AFX_NO_DAO_SUPPORT // as in 64-bit MFC: no DAO database classes (afxdao.h) +#define WM_ICONERASEBKGND 0x0027 +#define MSGF_DIALOGBOX 0 +#define MSGF_MESSAGEBOX 1 +#define MSGF_MENU 2 +#define MSGF_SCROLLBAR 5 +#define MSGF_NEXTWINDOW 6 +typedef struct tagLOGPALETTE* PLOGPALETTE; +struct IUnknown; +typedef IUnknown* LPUNKNOWN; +DWORD SearchPath(const char* lpPath, const char* lpFileName, const char* lpExtension, DWORD nBufferLength, + char* lpBuffer, char** lpFilePart); +DWORD SearchPathA(const char* lpPath, const char* lpFileName, const char* lpExtension, DWORD nBufferLength, + char* lpBuffer, char** lpFilePart); +int GetMenuStringW(HMENU hMenu, UINT uIDItem, LPWSTR lpString, int cchMax, UINT flags); diff --git a/port/mfcwx/include/mfcwx/fstreamcompat.h b/port/mfcwx/include/mfcwx/fstreamcompat.h new file mode 100644 index 000000000..95b99181d --- /dev/null +++ b/port/mfcwx/include/mfcwx/fstreamcompat.h @@ -0,0 +1,62 @@ +#pragma once + +// File streams that accept Windows-style paths ("dir\\file.txt") and are constructible +// from const char* by copy-initialization, as the pre-standard allowed. + +#include +#include + +#include "mfcwx/codepage.h" + +namespace std { + +class mfcwx_ifstream : public basic_ifstream { +public: + mfcwx_ifstream() = default; + mfcwx_ifstream(const char* path, ios_base::openmode mode = ios_base::in) + : basic_ifstream(::mfcwx::NativePath(path), mode) {} + mfcwx_ifstream(const string& path, ios_base::openmode mode = ios_base::in) + : mfcwx_ifstream(path.c_str(), mode) {} + void open(const char* path, ios_base::openmode mode = ios_base::in) { + basic_ifstream::open(::mfcwx::NativePath(path), mode); + } + void open(const string& path, ios_base::openmode mode = ios_base::in) { open(path.c_str(), mode); } +}; + +class mfcwx_ofstream : public basic_ofstream { +public: + mfcwx_ofstream() = default; + mfcwx_ofstream(const char* path, ios_base::openmode mode = ios_base::out) + : basic_ofstream(::mfcwx::NativePath(path), mode) {} + mfcwx_ofstream(const string& path, ios_base::openmode mode = ios_base::out) + : mfcwx_ofstream(path.c_str(), mode) {} + void open(const char* path, ios_base::openmode mode = ios_base::out) { + basic_ofstream::open(::mfcwx::NativePath(path), mode); + } + void open(const string& path, ios_base::openmode mode = ios_base::out) { open(path.c_str(), mode); } +}; + +class mfcwx_fstream : public basic_fstream { +public: + mfcwx_fstream() = default; + mfcwx_fstream(const char* path, ios_base::openmode mode = ios_base::in | ios_base::out) + : basic_fstream(::mfcwx::NativePath(path), mode) {} + mfcwx_fstream(const string& path, ios_base::openmode mode = ios_base::in | ios_base::out) + : mfcwx_fstream(path.c_str(), mode) {} + void open(const char* path, ios_base::openmode mode = ios_base::in | ios_base::out) { + basic_fstream::open(::mfcwx::NativePath(path), mode); + } + void open(const string& path, ios_base::openmode mode = ios_base::in | ios_base::out) { + open(path.c_str(), mode); + } +}; + +} // namespace std + +using std::mfcwx_fstream; +using std::mfcwx_ifstream; +using std::mfcwx_ofstream; + +#define ifstream mfcwx_ifstream +#define ofstream mfcwx_ofstream +#define fstream mfcwx_fstream diff --git a/port/mfcwx/include/mfcwx/geometry.h b/port/mfcwx/include/mfcwx/geometry.h new file mode 100644 index 000000000..a82b4b858 --- /dev/null +++ b/port/mfcwx/include/mfcwx/geometry.h @@ -0,0 +1,133 @@ +#pragma once + +#include "mfcwx/wintypes.h" + +class CPoint; +class CRect; + +class CSize : public tagSIZE { +public: + CSize() { cx = cy = 0; } + CSize(int initCX, int initCY) { cx = initCX; cy = initCY; } + CSize(SIZE initSize) { cx = initSize.cx; cy = initSize.cy; } + CSize(POINT initPt) { cx = initPt.x; cy = initPt.y; } + CSize(DWORD dwSize) { cx = static_cast(dwSize & 0xffff); cy = static_cast(dwSize >> 16); } + bool operator==(SIZE s) const { return cx == s.cx && cy == s.cy; } + bool operator!=(SIZE s) const { return !(*this == s); } + void operator+=(SIZE s) { cx += s.cx; cy += s.cy; } + void operator-=(SIZE s) { cx -= s.cx; cy -= s.cy; } + void SetSize(int CX, int CY) { cx = CX; cy = CY; } + CSize operator+(SIZE s) const { return CSize(cx + s.cx, cy + s.cy); } + CSize operator-(SIZE s) const { return CSize(cx - s.cx, cy - s.cy); } + CSize operator-() const { return CSize(-cx, -cy); } + CPoint operator+(POINT p) const; + CPoint operator-(POINT p) const; +}; + +class CPoint : public tagPOINT { +public: + CPoint() { x = y = 0; } + CPoint(int initX, int initY) { x = initX; y = initY; } + CPoint(POINT initPt) { x = initPt.x; y = initPt.y; } + CPoint(SIZE initSize) { x = initSize.cx; y = initSize.cy; } + CPoint(LPARAM dwPoint) { x = static_cast(dwPoint & 0xffff); y = static_cast((dwPoint >> 16) & 0xffff); } + void Offset(int xOffset, int yOffset) { x += xOffset; y += yOffset; } + void Offset(POINT point) { x += point.x; y += point.y; } + void Offset(SIZE size) { x += size.cx; y += size.cy; } + void SetPoint(int X, int Y) { x = X; y = Y; } + bool operator==(POINT p) const { return x == p.x && y == p.y; } + bool operator!=(POINT p) const { return !(*this == p); } + void operator+=(SIZE s) { x += s.cx; y += s.cy; } + void operator-=(SIZE s) { x -= s.cx; y -= s.cy; } + void operator+=(POINT p) { x += p.x; y += p.y; } + void operator-=(POINT p) { x -= p.x; y -= p.y; } + CPoint operator+(SIZE s) const { return CPoint(x + s.cx, y + s.cy); } + CPoint operator-(SIZE s) const { return CPoint(x - s.cx, y - s.cy); } + CPoint operator-() const { return CPoint(-x, -y); } + CPoint operator+(POINT p) const { return CPoint(x + p.x, y + p.y); } + CSize operator-(POINT p) const { return CSize(x - p.x, y - p.y); } +}; + +inline CPoint CSize::operator+(POINT p) const { return CPoint(cx + p.x, cy + p.y); } +inline CPoint CSize::operator-(POINT p) const { return CPoint(cx - p.x, cy - p.y); } + +class CRect : public tagRECT { +public: + CRect() { left = top = right = bottom = 0; } + CRect(int l, int t, int r, int b) { left = l; top = t; right = r; bottom = b; } + CRect(const RECT& srcRect) { left = srcRect.left; top = srcRect.top; right = srcRect.right; bottom = srcRect.bottom; } + CRect(LPCRECT lpSrcRect) { *this = *lpSrcRect; } + CRect(POINT point, SIZE size) { left = point.x; top = point.y; right = left + size.cx; bottom = top + size.cy; } + CRect(POINT topLeft, POINT bottomRight) { left = topLeft.x; top = topLeft.y; right = bottomRight.x; bottom = bottomRight.y; } + CRect& operator=(const RECT& r) { left = r.left; top = r.top; right = r.right; bottom = r.bottom; return *this; } + + int Width() const { return right - left; } + int Height() const { return bottom - top; } + CSize Size() const { return CSize(Width(), Height()); } + CPoint& TopLeft() { return *reinterpret_cast(this); } + CPoint& BottomRight() { return *(reinterpret_cast(this) + 1); } + const CPoint& TopLeft() const { return *reinterpret_cast(this); } + const CPoint& BottomRight() const { return *(reinterpret_cast(this) + 1); } + CPoint CenterPoint() const { return CPoint((left + right) / 2, (top + bottom) / 2); } + operator LPRECT() { return this; } + operator LPCRECT() const { return this; } + BOOL IsRectEmpty() const { return left >= right || top >= bottom; } + BOOL IsRectNull() const { return left == 0 && right == 0 && top == 0 && bottom == 0; } + BOOL PtInRect(POINT point) const { return point.x >= left && point.x < right && point.y >= top && point.y < bottom; } + void SetRect(int x1, int y1, int x2, int y2) { left = x1; top = y1; right = x2; bottom = y2; } + void SetRect(POINT topLeft, POINT bottomRight) { SetRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); } + void SetRectEmpty() { left = top = right = bottom = 0; } + void CopyRect(LPCRECT lpSrcRect) { *this = *lpSrcRect; } + BOOL EqualRect(LPCRECT r) const { return left == r->left && top == r->top && right == r->right && bottom == r->bottom; } + void InflateRect(int x, int y) { left -= x; top -= y; right += x; bottom += y; } + void InflateRect(SIZE size) { InflateRect(size.cx, size.cy); } + void InflateRect(LPCRECT r) { left -= r->left; top -= r->top; right += r->right; bottom += r->bottom; } + void InflateRect(int l, int t, int r, int b) { left -= l; top -= t; right += r; bottom += b; } + void DeflateRect(int x, int y) { InflateRect(-x, -y); } + void DeflateRect(SIZE size) { InflateRect(-size.cx, -size.cy); } + void DeflateRect(LPCRECT r) { left += r->left; top += r->top; right -= r->right; bottom -= r->bottom; } + void DeflateRect(int l, int t, int r, int b) { left += l; top += t; right -= r; bottom -= b; } + void OffsetRect(int x, int y) { left += x; right += x; top += y; bottom += y; } + void OffsetRect(POINT point) { OffsetRect(point.x, point.y); } + void OffsetRect(SIZE size) { OffsetRect(size.cx, size.cy); } + void MoveToY(int y) { bottom = Height() + y; top = y; } + void MoveToX(int x) { right = Width() + x; left = x; } + void MoveToXY(int x, int y) { MoveToX(x); MoveToY(y); } + void MoveToXY(POINT p) { MoveToXY(p.x, p.y); } + void NormalizeRect() { + if (left > right) { LONG t = left; left = right; right = t; } + if (top > bottom) { LONG t = top; top = bottom; bottom = t; } + } + BOOL IntersectRect(LPCRECT r1, LPCRECT r2) { + left = r1->left > r2->left ? r1->left : r2->left; + top = r1->top > r2->top ? r1->top : r2->top; + right = r1->right < r2->right ? r1->right : r2->right; + bottom = r1->bottom < r2->bottom ? r1->bottom : r2->bottom; + if (IsRectEmpty()) { SetRectEmpty(); return FALSE; } + return TRUE; + } + BOOL UnionRect(LPCRECT r1, LPCRECT r2) { + CRect a(r1), b(r2); + if (a.IsRectEmpty()) { *this = b; return !IsRectEmpty(); } + if (b.IsRectEmpty()) { *this = a; return TRUE; } + left = a.left < b.left ? a.left : b.left; + top = a.top < b.top ? a.top : b.top; + right = a.right > b.right ? a.right : b.right; + bottom = a.bottom > b.bottom ? a.bottom : b.bottom; + return TRUE; + } + bool operator==(const RECT& r) const { return EqualRect(&r); } + bool operator!=(const RECT& r) const { return !EqualRect(&r); } + void operator+=(POINT p) { OffsetRect(p); } + void operator+=(SIZE s) { OffsetRect(s); } + void operator-=(POINT p) { OffsetRect(-p.x, -p.y); } + void operator-=(SIZE s) { OffsetRect(-s.cx, -s.cy); } + void operator&=(const RECT& r) { IntersectRect(this, &r); } + void operator|=(const RECT& r) { UnionRect(this, &r); } + CRect operator+(POINT p) const { CRect r(*this); r.OffsetRect(p); return r; } + CRect operator-(POINT p) const { CRect r(*this); r.OffsetRect(-p.x, -p.y); return r; } + CRect operator+(SIZE s) const { CRect r(*this); r.OffsetRect(s); return r; } + CRect operator-(SIZE s) const { CRect r(*this); r.OffsetRect(-s.cx, -s.cy); return r; } + CRect operator&(const RECT& r2) const { CRect r; r.IntersectRect(this, &r2); return r; } + CRect operator|(const RECT& r2) const { CRect r; r.UnionRect(this, &r2); return r; } +}; diff --git a/port/mfcwx/include/mfcwx/msgmap.h b/port/mfcwx/include/mfcwx/msgmap.h new file mode 100644 index 000000000..ef7dc58f8 --- /dev/null +++ b/port/mfcwx/include/mfcwx/msgmap.h @@ -0,0 +1,292 @@ +#pragma once + +#include + +// MFC message map machinery. Handlers are stored as CCmdTarget member pointers together with a +// signature code; CCmdTarget/CWnd dispatch converts them back to the exact handler type. + +class CCmdTarget; +class CWnd; +class CDC; +class CCmdUI; +class CScrollBar; +class CMenu; + +typedef void (CCmdTarget::*AFX_PMSG)(void); +typedef void (CWnd::*AFX_PMSGW)(void); + +enum AfxSig { + AfxSig_end = 0, + AfxSigCmd_v, // void () + AfxSigCmd_b, // BOOL () + AfxSigCmd_RANGE, // void (UINT) + AfxSigCmd_EX, // BOOL (UINT) + AfxSigCmdUI, // void (CCmdUI*) + AfxSigCmdUI_RANGE, // void (CCmdUI*, UINT) + AfxSigNotify_v, // void (NMHDR*, LRESULT*) + AfxSigNotify_b, // BOOL (NMHDR*, LRESULT*) + AfxSigNotify_RANGE, // void (UINT, NMHDR*, LRESULT*) + AfxSigNotify_EX, // BOOL (UINT, NMHDR*, LRESULT*) + AfxSig_vv, // void () + AfxSig_bv, // BOOL () + AfxSig_lwl, // LRESULT (WPARAM, LPARAM) + AfxSig_is, // int (LPCREATESTRUCT) + AfxSig_bD, // BOOL (CDC*) + AfxSig_vwii, // void (UINT, int, int) WM_SIZE + AfxSig_vwwx, // void (UINT, UINT, UINT) WM_KEYDOWN/WM_CHAR... + AfxSig_vwp, // void (UINT, CPoint) mouse + AfxSig_bwsp, // BOOL (UINT, short, CPoint) WM_MOUSEWHEEL + AfxSig_vwwW, // void (UINT, UINT, CScrollBar*) WM_HSCROLL/VSCROLL + AfxSig_hDWw, // HBRUSH (CDC*, CWnd*, UINT) WM_CTLCOLOR + AfxSig_hDw, // HBRUSH (CDC*, UINT) WM_CTLCOLOR reflect + AfxSig_vOWNER, // void (int, LPDRAWITEMSTRUCT) WM_DRAWITEM + AfxSig_vMEASURE, // void (int, LPMEASUREITEMSTRUCT) WM_MEASUREITEM + AfxSig_vW, // void (CWnd*) WM_SETFOCUS/KILLFOCUS + AfxSig_vWp, // void (CWnd*, CPoint) WM_CONTEXTMENU + AfxSig_bWww, // BOOL (CWnd*, UINT, UINT) WM_SETCURSOR + AfxSig_vbw, // void (BOOL, UINT) WM_SHOWWINDOW + AfxSig_vwl, // void (UINT, LPARAM) WM_SYSCOMMAND + AfxSig_vw_ptr, // void (UINT_PTR) WM_TIMER + AfxSig_vw_uint, // void (UINT) WM_TIMER, pre-VS2005 handlers + AfxSig_hv, // HCURSOR () WM_QUERYDRAGICON + AfxSig_bHELPINFO, // BOOL (HELPINFO*) WM_HELP + AfxSig_vPOS, // void (MINMAXINFO*) WM_GETMINMAXINFO + AfxSig_vwWb, // void (UINT, CWnd*, BOOL) WM_ACTIVATE + AfxSig_wv, // UINT () WM_GETDLGCODE + AfxSig_vHDROP, // void (HDROP) WM_DROPFILES + AfxSig_vMwb, // void (CMenu*, UINT, BOOL) WM_INITMENUPOPUP + AfxSig_vii, // void (int, int) WM_MOVE + AfxSig_vwW, // void (UINT, CWnd*) + AfxSig_vbWW, // void (BOOL, CWnd*, CWnd*) WM_MDIACTIVATE + AfxSig_bb, // BOOL (BOOL) WM_NCACTIVATE + AfxSig_vb, // void (BOOL) WM_ENABLE + AfxSig_vwwh, // void (UINT, UINT, HMENU) WM_MENUSELECT + AfxSig_vRECT, // void (UINT, LPRECT) WM_SIZING/MOVING + AfxSig_vv_reflect, // void () reflected control notifications + AfxSig_bv_reflect, // BOOL () ON_CONTROL_REFLECT_EX + AfxSig_vNMHDRpl, // void (NMHDR*, LRESULT*) ON_NOTIFY_REFLECT + AfxSig_bNMHDRpl, // BOOL (NMHDR*, LRESULT*) ON_NOTIFY_REFLECT_EX + AfxSig_vv_event, // OLE event sink, unused +}; + +#define CN_COMMAND 0 +#define CN_UPDATE_COMMAND_UI ((UINT)(-1)) +#define CN_EVENT ((UINT)(-2)) +#define CN_OLEEVENT ((UINT)(-3)) +#define WM_REFLECT_BASE 0xBC00 + +struct AFX_MSGMAP_ENTRY { + UINT nMessage; + UINT nCode; + UINT nID; + UINT nLastID; + UINT_PTR nSig; + AFX_PMSG pfn; +}; + +struct AFX_MSGMAP { + const AFX_MSGMAP* (*pfnGetBaseMap)(); + const AFX_MSGMAP_ENTRY* lpEntries; +}; + +struct AFX_CMDHANDLERINFO { + CCmdTarget* pTarget; + AFX_PMSG pmf; +}; + +// Old code declares OnTimer(UINT), newer code OnTimer(UINT_PTR); both are accepted. +template +constexpr UINT_PTR AfxSigTimer(void (C::*)(UINT_PTR)) { return AfxSig_vw_ptr; } +template ::value>::type> +constexpr UINT_PTR AfxSigTimer(void (C::*)(UINT)) { return AfxSig_vw_uint; } +template +AFX_PMSG AfxPmsgTimer(void (C::*f)(UINT_PTR)) { return (AFX_PMSG)(AFX_PMSGW)static_cast(f); } +template ::value>::type> +AFX_PMSG AfxPmsgTimer(void (C::*f)(UINT)) { return (AFX_PMSG)(AFX_PMSGW)(void (CWnd::*)(UINT))static_cast(f); } + +#define DECLARE_MESSAGE_MAP() \ +protected: \ + static const AFX_MSGMAP* GetThisMessageMap(); \ + const AFX_MSGMAP* GetMessageMap() const override; + +#define BEGIN_MESSAGE_MAP(theClass, baseClass) \ + const AFX_MSGMAP* theClass::GetMessageMap() const { return GetThisMessageMap(); } \ + const AFX_MSGMAP* theClass::GetThisMessageMap() { \ + typedef theClass ThisClass; \ + typedef baseClass TheBaseClass; \ + (void)sizeof(ThisClass*); \ + static const AFX_MSGMAP_ENTRY _messageEntries[] = { + +#define BEGIN_TEMPLATE_MESSAGE_MAP(theClass, type_name, baseClass) \ + template \ + const AFX_MSGMAP* theClass::GetMessageMap() const { return GetThisMessageMap(); } \ + template \ + const AFX_MSGMAP* theClass::GetThisMessageMap() { \ + typedef theClass ThisClass; \ + typedef baseClass TheBaseClass; \ + static const AFX_MSGMAP_ENTRY _messageEntries[] = { + +#define END_MESSAGE_MAP() \ + {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}}; \ + static const AFX_MSGMAP messageMap = {&TheBaseClass::GetThisMessageMap, &_messageEntries[0]}; \ + return &messageMap; \ + } + +#define AFX_MFN(sig, fn) ((AFX_PMSG)(static_cast(fn))) +#define AFX_MFNW(sig, fn) ((AFX_PMSG)(AFX_PMSGW)(static_cast(fn))) + +// command and notification handlers +#define ON_COMMAND(id, memberFxn) \ + {WM_COMMAND, CN_COMMAND, (UINT)(WORD)(id), (UINT)(WORD)(id), AfxSigCmd_v, AFX_MFN(void (CCmdTarget::*)(void), memberFxn)}, +#define ON_COMMAND_EX(id, memberFxn) \ + {WM_COMMAND, CN_COMMAND, (UINT)(WORD)(id), (UINT)(WORD)(id), AfxSigCmd_EX, AFX_MFN(BOOL (CCmdTarget::*)(UINT), memberFxn)}, +#define ON_COMMAND_RANGE(id, idLast, memberFxn) \ + {WM_COMMAND, CN_COMMAND, (UINT)(WORD)(id), (UINT)(WORD)(idLast), AfxSigCmd_RANGE, AFX_MFN(void (CCmdTarget::*)(UINT), memberFxn)}, +#define ON_COMMAND_EX_RANGE(id, idLast, memberFxn) \ + {WM_COMMAND, CN_COMMAND, (UINT)(WORD)(id), (UINT)(WORD)(idLast), AfxSigCmd_EX, AFX_MFN(BOOL (CCmdTarget::*)(UINT), memberFxn)}, +#define ON_UPDATE_COMMAND_UI(id, memberFxn) \ + {WM_COMMAND, CN_UPDATE_COMMAND_UI, (UINT)(WORD)(id), (UINT)(WORD)(id), AfxSigCmdUI, AFX_MFN(void (CCmdTarget::*)(CCmdUI*), memberFxn)}, +#define ON_UPDATE_COMMAND_UI_RANGE(id, idLast, memberFxn) \ + {WM_COMMAND, CN_UPDATE_COMMAND_UI, (UINT)(WORD)(id), (UINT)(WORD)(idLast), AfxSigCmdUI, AFX_MFN(void (CCmdTarget::*)(CCmdUI*), memberFxn)}, +#define ON_CONTROL(wNotifyCode, id, memberFxn) \ + {WM_COMMAND, (UINT)(WORD)(wNotifyCode), (UINT)(WORD)(id), (UINT)(WORD)(id), AfxSigCmd_v, AFX_MFN(void (CCmdTarget::*)(void), memberFxn)}, +#define ON_CONTROL_RANGE(wNotifyCode, id, idLast, memberFxn) \ + {WM_COMMAND, (UINT)(WORD)(wNotifyCode), (UINT)(WORD)(id), (UINT)(WORD)(idLast), AfxSigCmd_RANGE, AFX_MFN(void (CCmdTarget::*)(UINT), memberFxn)}, +#define ON_NOTIFY(wNotifyCode, id, memberFxn) \ + {WM_NOTIFY, (UINT)(wNotifyCode), (UINT)(WORD)(id), (UINT)(WORD)(id), AfxSigNotify_v, AFX_MFN(void (CCmdTarget::*)(NMHDR*, LRESULT*), memberFxn)}, +#define ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn) \ + {WM_NOTIFY, (UINT)(wNotifyCode), (UINT)(WORD)(id), (UINT)(WORD)(idLast), AfxSigNotify_RANGE, AFX_MFN(void (CCmdTarget::*)(UINT, NMHDR*, LRESULT*), memberFxn)}, +#define ON_NOTIFY_EX(wNotifyCode, id, memberFxn) \ + {WM_NOTIFY, (UINT)(wNotifyCode), (UINT)(WORD)(id), (UINT)(WORD)(id), AfxSigNotify_EX, AFX_MFN(BOOL (CCmdTarget::*)(UINT, NMHDR*, LRESULT*), memberFxn)}, +#define ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn) \ + {WM_NOTIFY, (UINT)(wNotifyCode), (UINT)(WORD)(id), (UINT)(WORD)(idLast), AfxSigNotify_EX, AFX_MFN(BOOL (CCmdTarget::*)(UINT, NMHDR*, LRESULT*), memberFxn)}, + +#define ON_BN_CLICKED(id, memberFxn) ON_CONTROL(BN_CLICKED, id, memberFxn) +#define ON_BN_DOUBLECLICKED(id, memberFxn) ON_CONTROL(BN_DOUBLECLICKED, id, memberFxn) +#define ON_BN_SETFOCUS(id, memberFxn) ON_CONTROL(BN_SETFOCUS, id, memberFxn) +#define ON_BN_KILLFOCUS(id, memberFxn) ON_CONTROL(BN_KILLFOCUS, id, memberFxn) +#define ON_BN_HILITE(id, memberFxn) ON_CONTROL(BN_HILITE, id, memberFxn) +#define ON_BN_UNHILITE(id, memberFxn) ON_CONTROL(BN_UNHILITE, id, memberFxn) +#define ON_BN_PUSHED(id, memberFxn) ON_CONTROL(BN_PUSHED, id, memberFxn) +#define ON_BN_UNPUSHED(id, memberFxn) ON_CONTROL(BN_UNPUSHED, id, memberFxn) +#define ON_EN_SETFOCUS(id, memberFxn) ON_CONTROL(EN_SETFOCUS, id, memberFxn) +#define ON_EN_KILLFOCUS(id, memberFxn) ON_CONTROL(EN_KILLFOCUS, id, memberFxn) +#define ON_EN_CHANGE(id, memberFxn) ON_CONTROL(EN_CHANGE, id, memberFxn) +#define ON_EN_UPDATE(id, memberFxn) ON_CONTROL(EN_UPDATE, id, memberFxn) +#define ON_EN_ERRSPACE(id, memberFxn) ON_CONTROL(EN_ERRSPACE, id, memberFxn) +#define ON_EN_MAXTEXT(id, memberFxn) ON_CONTROL(EN_MAXTEXT, id, memberFxn) +#define ON_EN_HSCROLL(id, memberFxn) ON_CONTROL(EN_HSCROLL, id, memberFxn) +#define ON_EN_VSCROLL(id, memberFxn) ON_CONTROL(EN_VSCROLL, id, memberFxn) +#define ON_STN_CLICKED(id, memberFxn) ON_CONTROL(STN_CLICKED, id, memberFxn) +#define ON_STN_DBLCLK(id, memberFxn) ON_CONTROL(STN_DBLCLK, id, memberFxn) +#define ON_STN_ENABLE(id, memberFxn) ON_CONTROL(STN_ENABLE, id, memberFxn) +#define ON_STN_DISABLE(id, memberFxn) ON_CONTROL(STN_DISABLE, id, memberFxn) +#define ON_CBN_ERRSPACE(id, memberFxn) ON_CONTROL(CBN_ERRSPACE, id, memberFxn) +#define ON_CBN_SELCHANGE(id, memberFxn) ON_CONTROL(CBN_SELCHANGE, id, memberFxn) +#define ON_CBN_DBLCLK(id, memberFxn) ON_CONTROL(CBN_DBLCLK, id, memberFxn) +#define ON_CBN_SETFOCUS(id, memberFxn) ON_CONTROL(CBN_SETFOCUS, id, memberFxn) +#define ON_CBN_KILLFOCUS(id, memberFxn) ON_CONTROL(CBN_KILLFOCUS, id, memberFxn) +#define ON_CBN_EDITCHANGE(id, memberFxn) ON_CONTROL(CBN_EDITCHANGE, id, memberFxn) +#define ON_CBN_EDITUPDATE(id, memberFxn) ON_CONTROL(CBN_EDITUPDATE, id, memberFxn) +#define ON_CBN_DROPDOWN(id, memberFxn) ON_CONTROL(CBN_DROPDOWN, id, memberFxn) +#define ON_CBN_CLOSEUP(id, memberFxn) ON_CONTROL(CBN_CLOSEUP, id, memberFxn) +#define ON_CBN_SELENDOK(id, memberFxn) ON_CONTROL(CBN_SELENDOK, id, memberFxn) +#define ON_CBN_SELENDCANCEL(id, memberFxn) ON_CONTROL(CBN_SELENDCANCEL, id, memberFxn) +#define ON_LBN_ERRSPACE(id, memberFxn) ON_CONTROL(LBN_ERRSPACE, id, memberFxn) +#define ON_LBN_SELCHANGE(id, memberFxn) ON_CONTROL(LBN_SELCHANGE, id, memberFxn) +#define ON_LBN_DBLCLK(id, memberFxn) ON_CONTROL(LBN_DBLCLK, id, memberFxn) +#define ON_LBN_SELCANCEL(id, memberFxn) ON_CONTROL(LBN_SELCANCEL, id, memberFxn) +#define ON_LBN_SETFOCUS(id, memberFxn) ON_CONTROL(LBN_SETFOCUS, id, memberFxn) +#define ON_LBN_KILLFOCUS(id, memberFxn) ON_CONTROL(LBN_KILLFOCUS, id, memberFxn) + +// reflected notifications (handled by the control itself) +#define ON_CONTROL_REFLECT(wNotifyCode, memberFxn) \ + {WM_COMMAND + WM_REFLECT_BASE, (UINT)(WORD)(wNotifyCode), 0, 0, AfxSig_vv_reflect, AFX_MFN(void (CCmdTarget::*)(void), memberFxn)}, +#define ON_CONTROL_REFLECT_EX(wNotifyCode, memberFxn) \ + {WM_COMMAND + WM_REFLECT_BASE, (UINT)(WORD)(wNotifyCode), 0, 0, AfxSig_bv_reflect, AFX_MFN(BOOL (CCmdTarget::*)(void), memberFxn)}, +#define ON_NOTIFY_REFLECT(wNotifyCode, memberFxn) \ + {WM_NOTIFY + WM_REFLECT_BASE, (UINT)(wNotifyCode), 0, 0, AfxSig_vNMHDRpl, AFX_MFN(void (CCmdTarget::*)(NMHDR*, LRESULT*), memberFxn)}, +#define ON_NOTIFY_REFLECT_EX(wNotifyCode, memberFxn) \ + {WM_NOTIFY + WM_REFLECT_BASE, (UINT)(wNotifyCode), 0, 0, AfxSig_bNMHDRpl, AFX_MFN(BOOL (CCmdTarget::*)(NMHDR*, LRESULT*), memberFxn)}, +#define ON_EN_CHANGE_REFLECT(memberFxn) ON_CONTROL_REFLECT(EN_CHANGE, memberFxn) +#define ON_WM_CTLCOLOR_REFLECT() \ + {WM_CTLCOLOR + WM_REFLECT_BASE, 0, 0, 0, AfxSig_hDw, AFX_MFNW(HBRUSH (CWnd::*)(CDC*, UINT), &ThisClass::CtlColor)}, +#define ON_WM_DRAWITEM_REFLECT() \ + {WM_DRAWITEM + WM_REFLECT_BASE, 0, 0, 0, AfxSig_vOWNER, AFX_MFNW(void (CWnd::*)(LPDRAWITEMSTRUCT), &ThisClass::DrawItem)}, +#define ON_WM_HSCROLL_REFLECT() \ + {WM_HSCROLL + WM_REFLECT_BASE, 0, 0, 0, AfxSig_vwwW, AFX_MFNW(void (CWnd::*)(UINT, UINT), &ThisClass::HScroll)}, +#define ON_WM_VSCROLL_REFLECT() \ + {WM_VSCROLL + WM_REFLECT_BASE, 0, 0, 0, AfxSig_vwwW, AFX_MFNW(void (CWnd::*)(UINT, UINT), &ThisClass::VScroll)}, + +// generic messages +#define ON_MESSAGE(message, memberFxn) \ + {(UINT)(message), 0, 0, 0, AfxSig_lwl, AFX_MFNW(LRESULT (CWnd::*)(WPARAM, LPARAM), memberFxn)}, +#define ON_REGISTERED_MESSAGE(nMessageVariable, memberFxn) \ + {0xC000, 0, 0, 0, (UINT_PTR)(UINT*)(&nMessageVariable), AFX_MFNW(LRESULT (CWnd::*)(WPARAM, LPARAM), memberFxn)}, +#define ON_THREAD_MESSAGE(message, memberFxn) \ + {(UINT)(message), 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(static_cast(memberFxn))}, +#define ON_EVENT(theClass, id, dispid, pfnHandler, vtsParams) + +// window messages with fixed handler names +#define ON_WM_CREATE() {WM_CREATE, 0, 0, 0, AfxSig_is, AFX_MFNW(int (CWnd::*)(LPCREATESTRUCT), &ThisClass::OnCreate)}, +#define ON_WM_DESTROY() {WM_DESTROY, 0, 0, 0, AfxSig_vv, AFX_MFNW(void (CWnd::*)(void), &ThisClass::OnDestroy)}, +#define ON_WM_NCDESTROY() {WM_NCDESTROY, 0, 0, 0, AfxSig_vv, AFX_MFNW(void (CWnd::*)(void), &ThisClass::OnNcDestroy)}, +#define ON_WM_CLOSE() {WM_CLOSE, 0, 0, 0, AfxSig_vv, AFX_MFNW(void (CWnd::*)(void), &ThisClass::OnClose)}, +#define ON_WM_PAINT() {WM_PAINT, 0, 0, 0, AfxSig_vv, AFX_MFNW(void (CWnd::*)(void), &ThisClass::OnPaint)}, +#define ON_WM_ERASEBKGND() {WM_ERASEBKGND, 0, 0, 0, AfxSig_bD, AFX_MFNW(BOOL (CWnd::*)(CDC*), &ThisClass::OnEraseBkgnd)}, +#define ON_WM_SIZE() {WM_SIZE, 0, 0, 0, AfxSig_vwii, AFX_MFNW(void (CWnd::*)(UINT, int, int), &ThisClass::OnSize)}, +#define ON_WM_MOVE() {WM_MOVE, 0, 0, 0, AfxSig_vii, AFX_MFNW(void (CWnd::*)(int, int), &ThisClass::OnMove)}, +#define ON_WM_TIMER() {WM_TIMER, 0, 0, 0, AfxSigTimer(&ThisClass::OnTimer), AfxPmsgTimer(&ThisClass::OnTimer)}, +#define ON_WM_KEYDOWN() {WM_KEYDOWN, 0, 0, 0, AfxSig_vwwx, AFX_MFNW(void (CWnd::*)(UINT, UINT, UINT), &ThisClass::OnKeyDown)}, +#define ON_WM_KEYUP() {WM_KEYUP, 0, 0, 0, AfxSig_vwwx, AFX_MFNW(void (CWnd::*)(UINT, UINT, UINT), &ThisClass::OnKeyUp)}, +#define ON_WM_CHAR() {WM_CHAR, 0, 0, 0, AfxSig_vwwx, AFX_MFNW(void (CWnd::*)(UINT, UINT, UINT), &ThisClass::OnChar)}, +#define ON_WM_SYSKEYDOWN() {WM_SYSKEYDOWN, 0, 0, 0, AfxSig_vwwx, AFX_MFNW(void (CWnd::*)(UINT, UINT, UINT), &ThisClass::OnSysKeyDown)}, +#define ON_WM_SYSKEYUP() {WM_SYSKEYUP, 0, 0, 0, AfxSig_vwwx, AFX_MFNW(void (CWnd::*)(UINT, UINT, UINT), &ThisClass::OnSysKeyUp)}, +#define ON_WM_SYSCHAR() {WM_SYSCHAR, 0, 0, 0, AfxSig_vwwx, AFX_MFNW(void (CWnd::*)(UINT, UINT, UINT), &ThisClass::OnSysChar)}, +#define ON_WM_MOUSEMOVE() {WM_MOUSEMOVE, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnMouseMove)}, +#define ON_WM_LBUTTONDOWN() {WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnLButtonDown)}, +#define ON_WM_LBUTTONUP() {WM_LBUTTONUP, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnLButtonUp)}, +#define ON_WM_LBUTTONDBLCLK() {WM_LBUTTONDBLCLK, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnLButtonDblClk)}, +#define ON_WM_RBUTTONDOWN() {WM_RBUTTONDOWN, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnRButtonDown)}, +#define ON_WM_RBUTTONUP() {WM_RBUTTONUP, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnRButtonUp)}, +#define ON_WM_RBUTTONDBLCLK() {WM_RBUTTONDBLCLK, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnRButtonDblClk)}, +#define ON_WM_MBUTTONDOWN() {WM_MBUTTONDOWN, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnMButtonDown)}, +#define ON_WM_MBUTTONUP() {WM_MBUTTONUP, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnMButtonUp)}, +#define ON_WM_MOUSEWHEEL() {WM_MOUSEWHEEL, 0, 0, 0, AfxSig_bwsp, AFX_MFNW(BOOL (CWnd::*)(UINT, short, CPoint), &ThisClass::OnMouseWheel)}, +#define ON_WM_HSCROLL() {WM_HSCROLL, 0, 0, 0, AfxSig_vwwW, AFX_MFNW(void (CWnd::*)(UINT, UINT, CScrollBar*), &ThisClass::OnHScroll)}, +#define ON_WM_VSCROLL() {WM_VSCROLL, 0, 0, 0, AfxSig_vwwW, AFX_MFNW(void (CWnd::*)(UINT, UINT, CScrollBar*), &ThisClass::OnVScroll)}, +#define ON_WM_CTLCOLOR() {WM_CTLCOLOR, 0, 0, 0, AfxSig_hDWw, AFX_MFNW(HBRUSH (CWnd::*)(CDC*, CWnd*, UINT), &ThisClass::OnCtlColor)}, +#define ON_WM_DRAWITEM() {WM_DRAWITEM, 0, 0, 0, AfxSig_vOWNER, AFX_MFNW(void (CWnd::*)(int, LPDRAWITEMSTRUCT), &ThisClass::OnDrawItem)}, +#define ON_WM_MEASUREITEM() {WM_MEASUREITEM, 0, 0, 0, AfxSig_vMEASURE, AFX_MFNW(void (CWnd::*)(int, LPMEASUREITEMSTRUCT), &ThisClass::OnMeasureItem)}, +#define ON_WM_SETFOCUS() {WM_SETFOCUS, 0, 0, 0, AfxSig_vW, AFX_MFNW(void (CWnd::*)(CWnd*), &ThisClass::OnSetFocus)}, +#define ON_WM_KILLFOCUS() {WM_KILLFOCUS, 0, 0, 0, AfxSig_vW, AFX_MFNW(void (CWnd::*)(CWnd*), &ThisClass::OnKillFocus)}, +#define ON_WM_CONTEXTMENU() {WM_CONTEXTMENU, 0, 0, 0, AfxSig_vWp, AFX_MFNW(void (CWnd::*)(CWnd*, CPoint), &ThisClass::OnContextMenu)}, +#define ON_WM_SETCURSOR() {WM_SETCURSOR, 0, 0, 0, AfxSig_bWww, AFX_MFNW(BOOL (CWnd::*)(CWnd*, UINT, UINT), &ThisClass::OnSetCursor)}, +#define ON_WM_SHOWWINDOW() {WM_SHOWWINDOW, 0, 0, 0, AfxSig_vbw, AFX_MFNW(void (CWnd::*)(BOOL, UINT), &ThisClass::OnShowWindow)}, +#define ON_WM_SYSCOMMAND() {WM_SYSCOMMAND, 0, 0, 0, AfxSig_vwl, AFX_MFNW(void (CWnd::*)(UINT, LPARAM), &ThisClass::OnSysCommand)}, +#define ON_WM_QUERYDRAGICON() {WM_QUERYDRAGICON, 0, 0, 0, AfxSig_hv, AFX_MFNW(HCURSOR (CWnd::*)(void), &ThisClass::OnQueryDragIcon)}, +#define ON_WM_HELPINFO() {WM_HELP, 0, 0, 0, AfxSig_bHELPINFO, AFX_MFNW(BOOL (CWnd::*)(HELPINFO*), &ThisClass::OnHelpInfo)}, +#define ON_WM_GETMINMAXINFO() {WM_GETMINMAXINFO, 0, 0, 0, AfxSig_vPOS, AFX_MFNW(void (CWnd::*)(MINMAXINFO*), &ThisClass::OnGetMinMaxInfo)}, +#define ON_WM_ACTIVATE() {WM_ACTIVATE, 0, 0, 0, AfxSig_vwWb, AFX_MFNW(void (CWnd::*)(UINT, CWnd*, BOOL), &ThisClass::OnActivate)}, +#define ON_WM_GETDLGCODE() {WM_GETDLGCODE, 0, 0, 0, AfxSig_wv, AFX_MFNW(UINT (CWnd::*)(void), &ThisClass::OnGetDlgCode)}, +#define ON_WM_DROPFILES() {WM_DROPFILES, 0, 0, 0, AfxSig_vHDROP, AFX_MFNW(void (CWnd::*)(HDROP), &ThisClass::OnDropFiles)}, +#define ON_WM_INITMENUPOPUP() {WM_INITMENUPOPUP, 0, 0, 0, AfxSig_vMwb, AFX_MFNW(void (CWnd::*)(CMenu*, UINT, BOOL), &ThisClass::OnInitMenuPopup)}, +#define ON_WM_MDIACTIVATE() {WM_MDIACTIVATE, 0, 0, 0, AfxSig_vbWW, AFX_MFNW(void (CWnd::*)(BOOL, CWnd*, CWnd*), &ThisClass::OnMDIActivate)}, +#define ON_WM_ENABLE() {WM_ENABLE, 0, 0, 0, AfxSig_vb, AFX_MFNW(void (CWnd::*)(BOOL), &ThisClass::OnEnable)}, +#define ON_WM_NCACTIVATE() {WM_NCACTIVATE, 0, 0, 0, AfxSig_bb, AFX_MFNW(BOOL (CWnd::*)(BOOL), &ThisClass::OnNcActivate)}, +#define ON_WM_MENUSELECT() {WM_MENUSELECT, 0, 0, 0, AfxSig_vwwh, AFX_MFNW(void (CWnd::*)(UINT, UINT, HMENU), &ThisClass::OnMenuSelect)}, +#define ON_WM_SIZING() {WM_SIZING, 0, 0, 0, AfxSig_vRECT, AFX_MFNW(void (CWnd::*)(UINT, LPRECT), &ThisClass::OnSizing)}, +#define ON_WM_NCLBUTTONDOWN() {WM_NCLBUTTONDOWN, 0, 0, 0, AfxSig_vwp, AFX_MFNW(void (CWnd::*)(UINT, CPoint), &ThisClass::OnNcLButtonDown)}, +#define ON_WM_NCHITTEST() +#define ON_WM_NCPAINT() +#define ON_WM_NCCALCSIZE() +#define ON_WM_WINDOWPOSCHANGED() +#define ON_WM_WINDOWPOSCHANGING() +#define ON_WM_SETTINGCHANGE() +#define ON_WM_SYSCOLORCHANGE() +#define ON_WM_PALETTECHANGED() +#define ON_WM_QUERYNEWPALETTE() +#define ON_WM_CAPTURECHANGED() +#define ON_WM_MOUSEACTIVATE() +#define ON_WM_ACTIVATEAPP() +#define ON_WM_ENTERIDLE() diff --git a/port/mfcwx/include/mfcwx/rcdata.h b/port/mfcwx/include/mfcwx/rcdata.h new file mode 100644 index 000000000..bcbb1f1f0 --- /dev/null +++ b/port/mfcwx/include/mfcwx/rcdata.h @@ -0,0 +1,130 @@ +#pragma once + +#include + +// Resource tables generated from .rc files by port/rc/rc2cpp.py. +// All strings are UTF-8. A resource is identified either by a numeric id (name == nullptr) +// or by a string name (id == 0). +namespace mfcwx { +namespace rc { + +struct Control { + const char* cls; // window class as written in the .rc ("Button", "Edit", "Static", "ComboBox", + // "ListBox", "ScrollBar", "msctls_progress32", "msctls_trackbar32", + // "msctls_updown32", "SysListView32", "SysTreeView32", "SysTabControl32", + // "RICHEDIT", "RichEdit20A", "SysDateTimePick32", "SysAnimate32", ...) + const char* text; // caption, or resource name for SS_BITMAP/SS_ICON/BS_BITMAP ("#123" for numeric ids) + int id; // control id, -1 for IDC_STATIC + int16_t x, y, cx, cy; // dialog units + uint32_t style; // full style including the implied bits of the statement keyword + uint32_t exStyle; +}; + +struct Dialog { + int id; + const char* name; + int16_t x, y, cx, cy; + uint32_t style; + uint32_t exStyle; + const char* caption; + const char* fontName; // nullptr if DS_SETFONT not given + int16_t fontSize; + int16_t fontWeight; + uint8_t fontItalic; + const char* menuName; // nullptr if none + int menuId; + const Control* controls; + int controlCount; +}; + +struct MenuItem { + int16_t depth; // 0 = top level of the menu resource + int id; // command id, 0 for popups and separators + uint32_t flags; // MF_POPUP, MF_SEPARATOR, MF_GRAYED, MF_DISABLED, MF_CHECKED, MF_MENUBARBREAK, MF_MENUBREAK, MF_HELP + const char* text; // with '&' mnemonics and "\t" accelerator hints as in the .rc +}; + +struct Menu { + int id; + const char* name; + const MenuItem* items; + int itemCount; +}; + +struct StringEntry { + int id; + const char* text; +}; + +struct Accel { + int key; // virtual key code if (flags & FVIRTKEY), else the character code + int id; + uint32_t flags; // FVIRTKEY | FSHIFT | FCONTROL | FALT | FNOINVERT +}; + +struct AccelTable { + int id; + const char* name; + const Accel* items; + int itemCount; +}; + +struct Toolbar { + int id; + const char* name; + int16_t buttonWidth, buttonHeight; + const int* buttons; // command ids, 0 = separator + int buttonCount; +}; + +// BITMAP, ICON, CURSOR, GIF, AVI, HTML, WAVE and other file-backed resources. +struct FileResource { + const char* type; // "BITMAP", "ICON", "CURSOR", or the custom type name as in the .rc + int id; + const char* name; + const char* path; // relative to the directory of the .rc file, with '/' separators +}; + +// DLGINIT: initial list entries of combo boxes. +struct DlgInitEntry { + int dialogId; + int controlId; + const char* text; +}; + +struct VersionInfo { + uint16_t fileVersion[4]; + uint16_t productVersion[4]; + const char* const* keys; // alternating key/value pairs from the first StringFileInfo block + int keyCount; // number of pairs +}; + +struct Language { + const char* code; // "de", "en", "fr", "es", "pl", "el", "rs", ... + int langId; // MAKELANGID(primary, sub) + int codepage; // code page of the original .rc section + const Dialog* dialogs; + int dialogCount; + const Menu* menus; + int menuCount; + const StringEntry* strings; // sorted by id + int stringCount; + const AccelTable* accels; + int accelCount; + const Toolbar* toolbars; + int toolbarCount; + const FileResource* files; + int fileCount; + const DlgInitEntry* dlgInits; + int dlgInitCount; + const VersionInfo* version; // nullptr if none +}; + +struct Module { + const char* name; // e.g. "CrypTool" + const Language* const* languages; + int languageCount; +}; + +} // namespace rc +} // namespace mfcwx diff --git a/port/mfcwx/include/mfcwx/regkey.h b/port/mfcwx/include/mfcwx/regkey.h new file mode 100644 index 000000000..80c85f1bc --- /dev/null +++ b/port/mfcwx/include/mfcwx/regkey.h @@ -0,0 +1,44 @@ +#pragma once + +// ATL CRegKey, backed by the registry emulation of mfcwx (wxConfig). +class CRegKey { +public: + CRegKey() : m_hKey(nullptr) {} + ~CRegKey() { Close(); } + operator HKEY() const { return m_hKey; } + LONG Create(HKEY hKeyParent, const char* lpszKeyName, LPSTR lpszClass = nullptr, + DWORD dwOptions = REG_OPTION_NON_VOLATILE, REGSAM samDesired = KEY_READ | KEY_WRITE, + LPSECURITY_ATTRIBUTES lpSecAttr = nullptr, LPDWORD lpdwDisposition = nullptr); + LONG Open(HKEY hKeyParent, const char* lpszKeyName, REGSAM samDesired = KEY_READ | KEY_WRITE); + LONG Close(); + LONG QueryDWORDValue(const char* pszValueName, DWORD& dwValue); + LONG QueryStringValue(const char* pszValueName, LPSTR pszValue, ULONG* pnChars); + LONG QueryValue(DWORD& dwValue, const char* lpszValueName) { return QueryDWORDValue(lpszValueName, dwValue); } + LONG QueryValue(unsigned long& dwValue, const char* lpszValueName) { + DWORD v = 0; + LONG r = QueryDWORDValue(lpszValueName, v); + if (r == ERROR_SUCCESS) + dwValue = v; + return r; + } + LONG QueryValue(LPSTR szValue, const char* lpszValueName, unsigned long* pdwCount) { + DWORD n = pdwCount ? static_cast(*pdwCount) : 0; + LONG r = QueryValue(szValue, lpszValueName, &n); + if (pdwCount) + *pdwCount = n; + return r; + } + LONG QueryValue(LPSTR szValue, const char* lpszValueName, DWORD* pdwCount); + LONG QueryBinaryValue(const char* pszValueName, void* pValue, ULONG* pnBytes); + LONG SetDWORDValue(const char* pszValueName, DWORD dwValue); + LONG SetStringValue(const char* pszValueName, const char* pszValue, DWORD dwType = REG_SZ); + LONG SetValue(DWORD dwValue, const char* lpszValueName) { return SetDWORDValue(lpszValueName, dwValue); } + LONG SetValue(unsigned long dwValue, const char* lpszValueName) { return SetDWORDValue(lpszValueName, static_cast(dwValue)); } + LONG SetValue(int dwValue, const char* lpszValueName) { return SetDWORDValue(lpszValueName, static_cast(dwValue)); } + LONG SetValue(const char* lpszValue, const char* lpszValueName = nullptr) { return SetStringValue(lpszValueName, lpszValue); } + LONG SetBinaryValue(const char* pszValueName, const void* pValue, ULONG nBytes); + LONG DeleteValue(const char* lpszValue); + LONG DeleteSubKey(const char* lpszSubKey); + LONG RecurseDeleteKey(const char* lpszKey) { return DeleteSubKey(lpszKey); } + HKEY m_hKey; +}; diff --git a/port/mfcwx/include/mfcwx/win32.h b/port/mfcwx/include/mfcwx/win32.h new file mode 100644 index 000000000..33f863a9c --- /dev/null +++ b/port/mfcwx/include/mfcwx/win32.h @@ -0,0 +1,325 @@ +#pragma once + +/* Win32 API subset implemented on top of wxWidgets / POSIX. C compatible declarations; + functions taking or returning C++ types live in the afx headers. */ + +#include "mfcwx/wintypes.h" +#include "mfcwx/winconst.h" +#include "mfcwx/crtcompat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAKEWORD(a, b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) +#define MAKELONG(a, b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) +#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) +#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) +#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) +#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) +#define MAKEWPARAM(l, h) ((WPARAM)(DWORD)MAKELONG(l, h)) +#define MAKELPARAM(l, h) ((LPARAM)(DWORD)MAKELONG(l, h)) +#define MAKELRESULT(l, h) ((LRESULT)(DWORD)MAKELONG(l, h)) +#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) +#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) +#define RGB(r, g, b) ((COLORREF)(((BYTE)(r) | ((WORD)((BYTE)(g)) << 8)) | (((DWORD)(BYTE)(b)) << 16))) +#define PALETTERGB(r, g, b) (0x02000000 | RGB(r, g, b)) +#define GetRValue(rgb) (LOBYTE(rgb)) +#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) +#define GetBValue(rgb) (LOBYTE((rgb) >> 16)) +#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) +#define MAKEINTRESOURCE(i) MAKEINTRESOURCEA(i) +#define IS_INTRESOURCE(r) ((((ULONG_PTR)(r)) >> 16) == 0) +#define MAKELANGID(p, s) ((((WORD)(s)) << 10) | (WORD)(p)) +#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) +#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) +#define MAKELCID(lgid, srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) +#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#define FAILED(hr) (((HRESULT)(hr)) < 0) +#define S_OK ((HRESULT)0L) +#define S_FALSE ((HRESULT)1L) +#define E_FAIL ((HRESULT)0x80004005L) +#define E_NOTIMPL ((HRESULT)0x80004001L) +#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) +#define E_INVALIDARG ((HRESULT)0x80070057L) +#define UNREFERENCED_PARAMETER(P) (void)(P) +#define DBG_UNREFERENCED_PARAMETER(P) (void)(P) +#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (void)(V) +#define ZeroMemory(d, l) memset((d), 0, (l)) +#define SecureZeroMemory(d, l) memset((d), 0, (l)) +#define FillMemory(d, l, f) memset((d), (f), (l)) +#define CopyMemory(d, s, l) memcpy((d), (s), (l)) +#define MoveMemory(d, s, l) memmove((d), (s), (l)) +#define RtlZeroMemory ZeroMemory +#define RtlCopyMemory CopyMemory +#define RtlMoveMemory MoveMemory +#define RtlFillMemory FillMemory +#define _countof(a) (sizeof(a) / sizeof((a)[0])) +#define ARRAYSIZE(a) _countof(a) +#undef _T +#undef _TEXT +#undef TEXT +#define TEXT(s) s +#define __TEXT(s) s +#define _T(s) s +#define _TEXT(s) s +#define MAKEPOINTS(l) (*((POINTS*)&(l))) + +/* threads / timing / process */ +DWORD GetTickCount(void); +ULONGLONG GetTickCount64(void); +void Sleep(DWORD ms); +DWORD GetLastError(void); +void SetLastError(DWORD err); +DWORD GetCurrentThreadId(void); +DWORD GetCurrentProcessId(void); +HANDLE GetCurrentProcess(void); +HANDLE GetCurrentThread(void); +BOOL QueryPerformanceCounter(LARGE_INTEGER* c); +BOOL QueryPerformanceFrequency(LARGE_INTEGER* f); +void GetSystemTime(LPSYSTEMTIME st); +void GetLocalTime(LPSYSTEMTIME st); +void GetSystemTimeAsFileTime(LPFILETIME ft); +BOOL SystemTimeToFileTime(const SYSTEMTIME* st, LPFILETIME ft); +BOOL FileTimeToSystemTime(const FILETIME* ft, LPSYSTEMTIME st); +BOOL FileTimeToLocalFileTime(const FILETIME* ft, LPFILETIME lft); +void GetSystemInfo(LPSYSTEM_INFO si); +BOOL GetVersionEx(LPOSVERSIONINFO vi); +DWORD GetVersion(void); +void GlobalMemoryStatus(LPMEMORYSTATUS ms); +BOOL SetThreadPriority(HANDLE thread, int priority); +int GetThreadPriority(HANDLE thread); +BOOL SetPriorityClass(HANDLE process, DWORD cls); +DWORD WaitForSingleObject(HANDLE h, DWORD ms); +DWORD WaitForMultipleObjects(DWORD count, const HANDLE* handles, BOOL waitAll, DWORD ms); +BOOL CloseHandle(HANDLE h); +BOOL GetExitCodeThread(HANDLE thread, LPDWORD code); +BOOL GetExitCodeProcess(HANDLE process, LPDWORD code); +BOOL TerminateThread(HANDLE thread, DWORD code); +BOOL TerminateProcess(HANDLE process, UINT code); +HANDLE CreateThread(LPSECURITY_ATTRIBUTES sa, SIZE_T stack, LPTHREAD_START_ROUTINE fn, LPVOID param, DWORD flags, + LPDWORD threadId); +DWORD ResumeThread(HANDLE thread); +DWORD SuspendThread(HANDLE thread); +void ExitThread(DWORD code); +HANDLE CreateEventA(LPSECURITY_ATTRIBUTES sa, BOOL manualReset, BOOL initialState, LPCSTR name); +#define CreateEvent CreateEventA +BOOL SetEvent(HANDLE h); +BOOL ResetEvent(HANDLE h); +BOOL PulseEvent(HANDLE h); +HANDLE CreateMutexA(LPSECURITY_ATTRIBUTES sa, BOOL initialOwner, LPCSTR name); +#define CreateMutex CreateMutexA +BOOL ReleaseMutex(HANDLE h); +HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES sa, LONG initial, LONG max, LPCSTR name); +#define CreateSemaphore CreateSemaphoreA +BOOL ReleaseSemaphore(HANDLE h, LONG count, LPLONG previous); +void InitializeCriticalSection(LPCRITICAL_SECTION cs); +void DeleteCriticalSection(LPCRITICAL_SECTION cs); +void EnterCriticalSection(LPCRITICAL_SECTION cs); +void LeaveCriticalSection(LPCRITICAL_SECTION cs); +BOOL TryEnterCriticalSection(LPCRITICAL_SECTION cs); +LONG InterlockedIncrement(LONG volatile* p); +LONG InterlockedDecrement(LONG volatile* p); +LONG InterlockedExchange(LONG volatile* p, LONG v); +LONG InterlockedExchangeAdd(LONG volatile* p, LONG v); +LONG InterlockedCompareExchange(LONG volatile* p, LONG exchange, LONG comparand); +BOOL CreateProcessA(LPCSTR app, LPSTR cmdLine, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta, BOOL inherit, + DWORD flags, LPVOID env, LPCSTR curDir, LPSTARTUPINFO si, LPPROCESS_INFORMATION pi); +#define CreateProcess CreateProcessA +UINT WinExec(LPCSTR cmdLine, UINT show); +HINSTANCE ShellExecuteA(HWND hwnd, LPCSTR op, LPCSTR file, LPCSTR params, LPCSTR dir, int show); +#define ShellExecute ShellExecuteA +void ExitProcess(UINT code); +DWORD FormatMessageA(DWORD flags, LPCVOID source, DWORD msgId, DWORD langId, LPSTR buffer, DWORD size, va_list* args); +#define FormatMessage FormatMessageA +HLOCAL LocalAlloc(UINT flags, SIZE_T bytes); +HLOCAL LocalFree(HLOCAL mem); +HGLOBAL GlobalAlloc(UINT flags, SIZE_T bytes); +HGLOBAL GlobalFree(HGLOBAL mem); +LPVOID GlobalLock(HGLOBAL mem); +BOOL GlobalUnlock(HGLOBAL mem); +SIZE_T GlobalSize(HGLOBAL mem); +HGLOBAL GlobalReAlloc(HGLOBAL mem, SIZE_T bytes, UINT flags); +DWORD GetEnvironmentVariableA(LPCSTR name, LPSTR buffer, DWORD size); +#define GetEnvironmentVariable GetEnvironmentVariableA +BOOL SetEnvironmentVariableA(LPCSTR name, LPCSTR value); +#define SetEnvironmentVariable SetEnvironmentVariableA +DWORD ExpandEnvironmentStringsA(LPCSTR src, LPSTR dst, DWORD size); +#define ExpandEnvironmentStrings ExpandEnvironmentStringsA +LPSTR GetCommandLineA(void); +#define GetCommandLine GetCommandLineA +UINT SetErrorMode(UINT mode); +void OutputDebugStringA(LPCSTR s); +#define OutputDebugString OutputDebugStringA +void DebugBreak(void); +BOOL Beep(DWORD freq, DWORD duration); +BOOL MessageBeep(UINT type); +int MulDiv(int number, int numerator, int denominator); +BOOL IsBadReadPtr(const void* p, UINT_PTR cb); +BOOL IsBadWritePtr(LPVOID p, UINT_PTR cb); +DWORD GetUserDefaultLangID(void); +LCID GetUserDefaultLCID(void); +LCID GetSystemDefaultLCID(void); +LCID GetThreadLocale(void); +BOOL SetThreadLocale(LCID lcid); +UINT GetACP(void); +UINT GetOEMCP(void); +int MultiByteToWideChar(UINT cp, DWORD flags, LPCSTR src, int srcLen, LPWSTR dst, int dstLen); +int WideCharToMultiByte(UINT cp, DWORD flags, LPCWSTR src, int srcLen, LPSTR dst, int dstLen, LPCSTR defChar, + LPBOOL usedDef); +BOOL GetUserNameA(LPSTR buffer, LPDWORD size); +#define GetUserName GetUserNameA +BOOL GetComputerNameA(LPSTR buffer, LPDWORD size); +#define GetComputerName GetComputerNameA + +/* modules */ +HMODULE LoadLibraryA(LPCSTR name); +#define LoadLibrary LoadLibraryA +HMODULE LoadLibraryExA(LPCSTR name, HANDLE file, DWORD flags); +#define LoadLibraryEx LoadLibraryExA +BOOL FreeLibrary(HMODULE mod); +FARPROC GetProcAddress(HMODULE mod, LPCSTR name); +HMODULE GetModuleHandleA(LPCSTR name); +#define GetModuleHandle GetModuleHandleA +DWORD GetModuleFileNameA(HMODULE mod, LPSTR buffer, DWORD size); +#define GetModuleFileName GetModuleFileNameA + +/* files and directories */ +HANDLE CreateFileA(LPCSTR name, DWORD access, DWORD share, LPSECURITY_ATTRIBUTES sa, DWORD disposition, DWORD flags, + HANDLE templ); +#define CreateFile CreateFileA +BOOL ReadFile(HANDLE f, LPVOID buffer, DWORD toRead, LPDWORD read, LPOVERLAPPED ov); +BOOL WriteFile(HANDLE f, LPCVOID buffer, DWORD toWrite, LPDWORD written, LPOVERLAPPED ov); +DWORD SetFilePointer(HANDLE f, LONG distance, PLONG distanceHigh, DWORD method); +BOOL SetEndOfFile(HANDLE f); +DWORD GetFileSize(HANDLE f, LPDWORD high); +BOOL GetFileSizeEx(HANDLE f, PLARGE_INTEGER size); +BOOL FlushFileBuffers(HANDLE f); +BOOL GetFileTime(HANDLE f, LPFILETIME creation, LPFILETIME access, LPFILETIME write); +BOOL DeleteFileA(LPCSTR name); +#define DeleteFile DeleteFileA +BOOL CopyFileA(LPCSTR from, LPCSTR to, BOOL failIfExists); +#define CopyFile CopyFileA +BOOL MoveFileA(LPCSTR from, LPCSTR to); +#define MoveFile MoveFileA +BOOL MoveFileExA(LPCSTR from, LPCSTR to, DWORD flags); +#define MoveFileEx MoveFileExA +#define MOVEFILE_REPLACE_EXISTING 0x00000001 +#define MOVEFILE_COPY_ALLOWED 0x00000002 +BOOL CreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sa); +#define CreateDirectory CreateDirectoryA +BOOL RemoveDirectoryA(LPCSTR path); +#define RemoveDirectory RemoveDirectoryA +BOOL SetCurrentDirectoryA(LPCSTR path); +#define SetCurrentDirectory SetCurrentDirectoryA +DWORD GetCurrentDirectoryA(DWORD size, LPSTR buffer); +#define GetCurrentDirectory GetCurrentDirectoryA +DWORD GetTempPathA(DWORD size, LPSTR buffer); +#define GetTempPath GetTempPathA +UINT GetTempFileNameA(LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer); +#define GetTempFileName GetTempFileNameA +DWORD GetFileAttributesA(LPCSTR name); +#define GetFileAttributes GetFileAttributesA +BOOL SetFileAttributesA(LPCSTR name, DWORD attrs); +#define SetFileAttributes SetFileAttributesA +DWORD GetFullPathNameA(LPCSTR name, DWORD size, LPSTR buffer, LPSTR* filePart); +#define GetFullPathName GetFullPathNameA +DWORD GetShortPathNameA(LPCSTR longPath, LPSTR shortPath, DWORD size); +#define GetShortPathName GetShortPathNameA +DWORD GetLongPathNameA(LPCSTR shortPath, LPSTR longPath, DWORD size); +#define GetLongPathName GetLongPathNameA +HANDLE FindFirstFileA(LPCSTR pattern, LPWIN32_FIND_DATA data); +#define FindFirstFile FindFirstFileA +BOOL FindNextFileA(HANDLE find, LPWIN32_FIND_DATA data); +#define FindNextFile FindNextFileA +BOOL FindClose(HANDLE find); +UINT GetWindowsDirectoryA(LPSTR buffer, UINT size); +#define GetWindowsDirectory GetWindowsDirectoryA +UINT GetSystemDirectoryA(LPSTR buffer, UINT size); +#define GetSystemDirectory GetSystemDirectoryA +UINT GetDriveTypeA(LPCSTR root); +#define GetDriveType GetDriveTypeA +BOOL GetDiskFreeSpaceExA(LPCSTR dir, PULARGE_INTEGER freeToCaller, PULARGE_INTEGER total, PULARGE_INTEGER totalFree); +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA + +/* ini files, mapped onto simple INI parsing */ +DWORD GetPrivateProfileStringA(LPCSTR app, LPCSTR key, LPCSTR def, LPSTR ret, DWORD size, LPCSTR file); +#define GetPrivateProfileString GetPrivateProfileStringA +UINT GetPrivateProfileIntA(LPCSTR app, LPCSTR key, INT def, LPCSTR file); +#define GetPrivateProfileInt GetPrivateProfileIntA +BOOL WritePrivateProfileStringA(LPCSTR app, LPCSTR key, LPCSTR value, LPCSTR file); +#define WritePrivateProfileString WritePrivateProfileStringA +DWORD GetPrivateProfileSectionA(LPCSTR app, LPSTR ret, DWORD size, LPCSTR file); +#define GetPrivateProfileSection GetPrivateProfileSectionA + +/* registry, mapped onto wxConfig */ +LONG RegOpenKeyExA(HKEY key, LPCSTR sub, DWORD options, REGSAM sam, PHKEY result); +#define RegOpenKeyEx RegOpenKeyExA +LONG RegOpenKeyA(HKEY key, LPCSTR sub, PHKEY result); +#define RegOpenKey RegOpenKeyA +LONG RegCreateKeyExA(HKEY key, LPCSTR sub, DWORD reserved, LPSTR cls, DWORD options, REGSAM sam, + LPSECURITY_ATTRIBUTES sa, PHKEY result, LPDWORD disposition); +#define RegCreateKeyEx RegCreateKeyExA +LONG RegCreateKeyA(HKEY key, LPCSTR sub, PHKEY result); +#define RegCreateKey RegCreateKeyA +LONG RegCloseKey(HKEY key); +LONG RegQueryValueExA(HKEY key, LPCSTR name, LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD size); +#define RegQueryValueEx RegQueryValueExA +LONG RegSetValueExA(HKEY key, LPCSTR name, DWORD reserved, DWORD type, const BYTE* data, DWORD size); +#define RegSetValueEx RegSetValueExA +LONG RegDeleteValueA(HKEY key, LPCSTR name); +#define RegDeleteValue RegDeleteValueA +LONG RegDeleteKeyA(HKEY key, LPCSTR sub); +#define RegDeleteKey RegDeleteKeyA +LONG RegEnumKeyExA(HKEY key, DWORD index, LPSTR name, LPDWORD nameSize, LPDWORD reserved, LPSTR cls, LPDWORD clsSize, + PFILETIME lastWrite); +#define RegEnumKeyEx RegEnumKeyExA + +/* strings */ +int lstrlenA(LPCSTR s); +#define lstrlen lstrlenA +LPSTR lstrcpyA(LPSTR d, LPCSTR s); +#define lstrcpy lstrcpyA +LPSTR lstrcpynA(LPSTR d, LPCSTR s, int n); +#define lstrcpyn lstrcpynA +LPSTR lstrcatA(LPSTR d, LPCSTR s); +#define lstrcat lstrcatA +int lstrcmpA(LPCSTR a, LPCSTR b); +#define lstrcmp lstrcmpA +int lstrcmpiA(LPCSTR a, LPCSTR b); +#define lstrcmpi lstrcmpiA +int wsprintfA(LPSTR buf, LPCSTR fmt, ...); +#define wsprintf wsprintfA +int wvsprintfA(LPSTR buf, LPCSTR fmt, va_list args); +#define wvsprintf wvsprintfA +LPSTR CharUpperA(LPSTR s); +#define CharUpper CharUpperA +LPSTR CharLowerA(LPSTR s); +#define CharLower CharLowerA +DWORD CharUpperBuffA(LPSTR s, DWORD len); +#define CharUpperBuff CharUpperBuffA +DWORD CharLowerBuffA(LPSTR s, DWORD len); +#define CharLowerBuff CharLowerBuffA +LPSTR CharNextA(LPCSTR s); +#define CharNext CharNextA +LPSTR CharPrevA(LPCSTR start, LPCSTR s); +#define CharPrev CharPrevA +BOOL IsCharAlphaA(CHAR c); +#define IsCharAlpha IsCharAlphaA +BOOL IsCharAlphaNumericA(CHAR c); +#define IsCharAlphaNumeric IsCharAlphaNumericA +BOOL IsCharUpperA(CHAR c); +#define IsCharUpper IsCharUpperA +BOOL IsCharLowerA(CHAR c); +#define IsCharLower IsCharLowerA +BOOL IsDBCSLeadByte(BYTE c); +BOOL OemToCharA(LPCSTR src, LPSTR dst); +#define OemToChar OemToCharA +BOOL CharToOemA(LPCSTR src, LPSTR dst); +#define CharToOem CharToOemA + +#ifdef __cplusplus +} +#endif diff --git a/port/mfcwx/include/mfcwx/winapi_gui.h b/port/mfcwx/include/mfcwx/winapi_gui.h new file mode 100644 index 000000000..346d48081 --- /dev/null +++ b/port/mfcwx/include/mfcwx/winapi_gui.h @@ -0,0 +1,283 @@ +#pragma once + +// Win32 user/gdi functions operating on HWND/HDC handles (HWND is a wxWindow*, HDC an opaque handle to an internal DC state). + +LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL SendNotifyMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL PostThreadMessage(DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam); +void PostQuitMessage(int nExitCode); +UINT RegisterWindowMessage(const char* lpString); +UINT RegisterWindowMessageA(const char* lpString); +BOOL PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); +BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); +BOOL TranslateMessage(const MSG* lpMsg); +LRESULT DispatchMessage(const MSG* lpMsg); +BOOL WaitMessage(); +DWORD MsgWaitForMultipleObjects(DWORD nCount, const HANDLE* pHandles, BOOL fWaitAll, DWORD dwMilliseconds, + DWORD dwWakeMask); +LRESULT DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +BOOL IsWindow(HWND hWnd); +BOOL IsWindowVisible(HWND hWnd); +BOOL IsWindowEnabled(HWND hWnd); +BOOL EnableWindow(HWND hWnd, BOOL bEnable); +BOOL ShowWindow(HWND hWnd, int nCmdShow); +BOOL IsIconic(HWND hWnd); +BOOL IsZoomed(HWND hWnd); +BOOL IsChild(HWND hWndParent, HWND hWnd); +HWND GetParent(HWND hWnd); +HWND SetParent(HWND hWndChild, HWND hWndNewParent); +HWND GetWindow(HWND hWnd, UINT uCmd); +HWND GetTopWindow(HWND hWnd); +HWND GetDesktopWindow(); +HWND GetActiveWindow(); +HWND SetActiveWindow(HWND hWnd); +HWND GetForegroundWindow(); +BOOL SetForegroundWindow(HWND hWnd); +HWND GetFocus(); +HWND SetFocus(HWND hWnd); +HWND GetCapture(); +HWND SetCapture(HWND hWnd); +BOOL ReleaseCapture(); +HWND FindWindow(const char* lpClassName, const char* lpWindowName); +HWND FindWindowA(const char* lpClassName, const char* lpWindowName); +HWND WindowFromPoint(POINT Point); +HWND ChildWindowFromPoint(HWND hWndParent, POINT Point); +BOOL DestroyWindow(HWND hWnd); +BOOL CloseWindow(HWND hWnd); +BOOL BringWindowToTop(HWND hWnd); +BOOL SetWindowText(HWND hWnd, const char* lpString); +BOOL SetWindowTextA(HWND hWnd, const char* lpString); +int GetWindowText(HWND hWnd, char* lpString, int nMaxCount); +int GetWindowTextA(HWND hWnd, char* lpString, int nMaxCount); +int GetWindowTextLength(HWND hWnd); +int GetClassName(HWND hWnd, char* lpClassName, int nMaxCount); +LONG GetWindowLong(HWND hWnd, int nIndex); +LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong); +LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex); +LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong); +BOOL GetWindowRect(HWND hWnd, LPRECT lpRect); +BOOL GetClientRect(HWND hWnd, LPRECT lpRect); +BOOL ClientToScreen(HWND hWnd, LPPOINT lpPoint); +BOOL ScreenToClient(HWND hWnd, LPPOINT lpPoint); +int MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints); +BOOL MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint); +BOOL SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); +BOOL InvalidateRect(HWND hWnd, const RECT* lpRect, BOOL bErase); +BOOL ValidateRect(HWND hWnd, const RECT* lpRect); +BOOL UpdateWindow(HWND hWnd); +BOOL RedrawWindow(HWND hWnd, const RECT* lprcUpdate, HRGN hrgnUpdate, UINT flags); +HDC GetDC(HWND hWnd); +HDC GetWindowDC(HWND hWnd); +int ReleaseDC(HWND hWnd, HDC hDC); +HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); +BOOL EndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint); +UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc); +BOOL KillTimer(HWND hWnd, UINT_PTR uIDEvent); + +HWND GetDlgItem(HWND hDlg, int nIDDlgItem); +int GetDlgCtrlID(HWND hWnd); +UINT GetDlgItemInt(HWND hDlg, int nIDDlgItem, BOOL* lpTranslated, BOOL bSigned); +BOOL SetDlgItemInt(HWND hDlg, int nIDDlgItem, UINT uValue, BOOL bSigned); +UINT GetDlgItemText(HWND hDlg, int nIDDlgItem, char* lpString, int cchMax); +UINT GetDlgItemTextA(HWND hDlg, int nIDDlgItem, char* lpString, int cchMax); +BOOL SetDlgItemText(HWND hDlg, int nIDDlgItem, const char* lpString); +BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, const char* lpString); +BOOL CheckDlgButton(HWND hDlg, int nIDButton, UINT uCheck); +UINT IsDlgButtonChecked(HWND hDlg, int nIDButton); +BOOL CheckRadioButton(HWND hDlg, int nIDFirstButton, int nIDLastButton, int nIDCheckButton); +LRESULT SendDlgItemMessage(HWND hDlg, int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL EndDialog(HWND hDlg, INT_PTR nResult); +HWND GetNextDlgTabItem(HWND hDlg, HWND hCtl, BOOL bPrevious); +HWND GetNextDlgGroupItem(HWND hDlg, HWND hCtl, BOOL bPrevious); +BOOL MapDialogRect(HWND hDlg, LPRECT lpRect); +LONG GetDialogBaseUnits(); + +int MessageBox(HWND hWnd, const char* lpText, const char* lpCaption, UINT uType); +int MessageBoxA(HWND hWnd, const char* lpText, const char* lpCaption, UINT uType); +BOOL WinHelp(HWND hWndMain, const char* lpszHelp, UINT uCommand, ULONG_PTR dwData); +BOOL WinHelpA(HWND hWndMain, const char* lpszHelp, UINT uCommand, ULONG_PTR dwData); + +int GetSystemMetrics(int nIndex); +DWORD GetSysColor(int nIndex); +HBRUSH GetSysColorBrush(int nIndex); +BOOL SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni); +BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni); +SHORT GetKeyState(int nVirtKey); +SHORT GetAsyncKeyState(int vKey); +BOOL GetKeyboardState(BYTE* lpKeyState); +BOOL GetCursorPos(LPPOINT lpPoint); +BOOL SetCursorPos(int X, int Y); +HCURSOR SetCursor(HCURSOR hCursor); +HCURSOR GetCursor(); +int ShowCursor(BOOL bShow); +HCURSOR LoadCursor(HINSTANCE hInstance, const char* lpCursorName); +HCURSOR LoadCursorA(HINSTANCE hInstance, const char* lpCursorName); +HCURSOR LoadCursorFromFile(const char* lpFileName); +HICON LoadIcon(HINSTANCE hInstance, const char* lpIconName); +HICON LoadIconA(HINSTANCE hInstance, const char* lpIconName); +BOOL DestroyIcon(HICON hIcon); +BOOL DestroyCursor(HCURSOR hCursor); +BOOL DrawIcon(HDC hDC, int X, int Y, HICON hIcon); +HANDLE LoadImage(HINSTANCE hInst, const char* name, UINT type, int cx, int cy, UINT fuLoad); +HANDLE LoadImageA(HINSTANCE hInst, const char* name, UINT type, int cx, int cy, UINT fuLoad); +HBITMAP LoadBitmap(HINSTANCE hInstance, const char* lpBitmapName); +HBITMAP LoadBitmapA(HINSTANCE hInstance, const char* lpBitmapName); +int LoadString(HINSTANCE hInstance, UINT uID, char* lpBuffer, int cchBufferMax); +int LoadStringA(HINSTANCE hInstance, UINT uID, char* lpBuffer, int cchBufferMax); +HMENU LoadMenu(HINSTANCE hInstance, const char* lpMenuName); +HACCEL LoadAccelerators(HINSTANCE hInstance, const char* lpTableName); +int TranslateAccelerator(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg); +HRSRC FindResource(HMODULE hModule, const char* lpName, const char* lpType); +HRSRC FindResourceA(HMODULE hModule, const char* lpName, const char* lpType); +HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo); +LPVOID LockResource(HGLOBAL hResData); +DWORD SizeofResource(HMODULE hModule, HRSRC hResInfo); +BOOL FreeResource(HGLOBAL hResData); +#define RT_CURSOR MAKEINTRESOURCE(1) +#define RT_BITMAP MAKEINTRESOURCE(2) +#define RT_ICON MAKEINTRESOURCE(3) +#define RT_MENU MAKEINTRESOURCE(4) +#define RT_DIALOG MAKEINTRESOURCE(5) +#define RT_STRING MAKEINTRESOURCE(6) +#define RT_ACCELERATOR MAKEINTRESOURCE(9) +#define RT_RCDATA MAKEINTRESOURCE(10) +#define RT_GROUP_CURSOR MAKEINTRESOURCE(12) +#define RT_GROUP_ICON MAKEINTRESOURCE(14) +#define RT_VERSION MAKEINTRESOURCE(16) +#define RT_DLGINIT MAKEINTRESOURCE(240) +#define RT_HTML MAKEINTRESOURCE(23) + +#define IDC_ARROW MAKEINTRESOURCE(32512) +#define IDC_IBEAM MAKEINTRESOURCE(32513) +#define IDC_WAIT MAKEINTRESOURCE(32514) +#define IDC_CROSS MAKEINTRESOURCE(32515) +#define IDC_UPARROW MAKEINTRESOURCE(32516) +#define IDC_SIZE MAKEINTRESOURCE(32640) +#define IDC_ICON MAKEINTRESOURCE(32641) +#define IDC_SIZENWSE MAKEINTRESOURCE(32642) +#define IDC_SIZENESW MAKEINTRESOURCE(32643) +#define IDC_SIZEWE MAKEINTRESOURCE(32644) +#define IDC_SIZENS MAKEINTRESOURCE(32645) +#define IDC_SIZEALL MAKEINTRESOURCE(32646) +#define IDC_NO MAKEINTRESOURCE(32648) +#define IDC_HAND MAKEINTRESOURCE(32649) +#define IDC_APPSTARTING MAKEINTRESOURCE(32650) +#define IDC_HELP MAKEINTRESOURCE(32651) +#define IDI_APPLICATION MAKEINTRESOURCE(32512) +#define IDI_HAND MAKEINTRESOURCE(32513) +#define IDI_QUESTION MAKEINTRESOURCE(32514) +#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) +#define IDI_ASTERISK MAKEINTRESOURCE(32516) +#define IDI_WINLOGO MAKEINTRESOURCE(32517) +#define IDI_WARNING IDI_EXCLAMATION +#define IDI_ERROR IDI_HAND +#define IDI_INFORMATION IDI_ASTERISK + +HMENU GetMenu(HWND hWnd); +BOOL SetMenu(HWND hWnd, HMENU hMenu); +HMENU GetSubMenu(HMENU hMenu, int nPos); +HMENU GetSystemMenu(HWND hWnd, BOOL bRevert); +HMENU CreateMenu(); +HMENU CreatePopupMenu(); +BOOL DestroyMenu(HMENU hMenu); +BOOL AppendMenu(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem); +BOOL AppendMenuA(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem); +BOOL InsertMenu(HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem); +BOOL DeleteMenu(HMENU hMenu, UINT uPosition, UINT uFlags); +BOOL RemoveMenu(HMENU hMenu, UINT uPosition, UINT uFlags); +BOOL ModifyMenu(HMENU hMnu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem); +DWORD CheckMenuItem(HMENU hMenu, UINT uIDCheckItem, UINT uCheck); +BOOL EnableMenuItem(HMENU hMenu, UINT uIDEnableItem, UINT uEnable); +int GetMenuItemCount(HMENU hMenu); +UINT GetMenuItemID(HMENU hMenu, int nPos); +UINT GetMenuState(HMENU hMenu, UINT uId, UINT uFlags); +int GetMenuString(HMENU hMenu, UINT uIDItem, char* lpString, int cchMax, UINT flags); +BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, int nReserved, HWND hWnd, const RECT* prcRect); +BOOL DrawMenuBar(HWND hWnd); + +BOOL OpenClipboard(HWND hWndNewOwner); +BOOL CloseClipboard(); +BOOL EmptyClipboard(); +HANDLE GetClipboardData(UINT uFormat); +HANDLE SetClipboardData(UINT uFormat, HANDLE hMem); +BOOL IsClipboardFormatAvailable(UINT format); +UINT RegisterClipboardFormat(const char* lpszFormat); +UINT RegisterClipboardFormatA(const char* lpszFormat); +UINT DragQueryFile(HDROP hDrop, UINT iFile, char* lpszFile, UINT cch); +UINT DragQueryFileA(HDROP hDrop, UINT iFile, char* lpszFile, UINT cch); +void DragFinish(HDROP hDrop); +void DragAcceptFiles(HWND hWnd, BOOL fAccept); + +HGDIOBJ GetStockObject(int i); +BOOL DeleteObject(HGDIOBJ ho); +HGDIOBJ SelectObject(HDC hdc, HGDIOBJ h); +int GetObject(HANDLE h, int c, LPVOID pv); +int GetObjectA(HANDLE h, int c, LPVOID pv); +HBRUSH CreateSolidBrush(COLORREF color); +HBRUSH CreateHatchBrush(int iHatch, COLORREF color); +HBRUSH CreatePatternBrush(HBITMAP hbm); +HPEN CreatePen(int iStyle, int cWidth, COLORREF color); +HFONT CreateFont(int cHeight, int cWidth, int cEscapement, int cOrientation, int cWeight, DWORD bItalic, + DWORD bUnderline, DWORD bStrikeOut, DWORD iCharSet, DWORD iOutPrecision, DWORD iClipPrecision, + DWORD iQuality, DWORD iPitchAndFamily, const char* pszFaceName); +HFONT CreateFontA(int cHeight, int cWidth, int cEscapement, int cOrientation, int cWeight, DWORD bItalic, + DWORD bUnderline, DWORD bStrikeOut, DWORD iCharSet, DWORD iOutPrecision, DWORD iClipPrecision, + DWORD iQuality, DWORD iPitchAndFamily, const char* pszFaceName); +HFONT CreateFontIndirect(const LOGFONT* lplf); +HFONT CreateFontIndirectA(const LOGFONT* lplf); +HBITMAP CreateCompatibleBitmap(HDC hdc, int cx, int cy); +HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitCount, const void* lpBits); +HDC CreateCompatibleDC(HDC hdc); +BOOL DeleteDC(HDC hdc); +COLORREF SetTextColor(HDC hdc, COLORREF color); +COLORREF SetBkColor(HDC hdc, COLORREF color); +int SetBkMode(HDC hdc, int mode); +BOOL TextOut(HDC hdc, int x, int y, const char* lpString, int c); +BOOL TextOutA(HDC hdc, int x, int y, const char* lpString, int c); +int DrawText(HDC hdc, const char* lpchText, int cchText, LPRECT lprc, UINT format); +int DrawTextA(HDC hdc, const char* lpchText, int cchText, LPRECT lprc, UINT format); +BOOL GetTextExtentPoint32(HDC hdc, const char* lpString, int c, LPSIZE psizl); +BOOL GetTextExtentPoint32A(HDC hdc, const char* lpString, int c, LPSIZE psizl); +BOOL GetTextMetrics(HDC hdc, LPTEXTMETRIC lptm); +BOOL GetTextMetricsA(HDC hdc, LPTEXTMETRIC lptm); +int GetDeviceCaps(HDC hdc, int index); +BOOL BitBlt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop); +BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdcSrc, int xSrc, int ySrc, int wSrc, + int hSrc, DWORD rop); +BOOL MoveToEx(HDC hdc, int x, int y, LPPOINT lppt); +BOOL LineTo(HDC hdc, int x, int y); +BOOL Rectangle(HDC hdc, int left, int top, int right, int bottom); +BOOL Ellipse(HDC hdc, int left, int top, int right, int bottom); +BOOL Polygon(HDC hdc, const POINT* apt, int cpt); +BOOL Polyline(HDC hdc, const POINT* apt, int cpt); +int FillRect(HDC hDC, const RECT* lprc, HBRUSH hbr); +int FrameRect(HDC hDC, const RECT* lprc, HBRUSH hbr); +COLORREF SetPixel(HDC hdc, int x, int y, COLORREF color); +COLORREF GetPixel(HDC hdc, int x, int y); +BOOL DrawEdge(HDC hdc, LPRECT qrc, UINT edge, UINT grfFlags); +BOOL DrawFocusRect(HDC hDC, const RECT* lprc); +int SaveDC(HDC hdc); +BOOL RestoreDC(HDC hdc, int nSavedDC); +HRGN CreateRectRgn(int x1, int y1, int x2, int y2); +HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2); +int SelectClipRgn(HDC hdc, HRGN hrgn); +int SetDIBitsToDevice(HDC hdc, int xDest, int yDest, DWORD w, DWORD h, int xSrc, int ySrc, UINT StartScan, + UINT cLines, const void* lpvBits, const BITMAPINFO* lpbmi, UINT ColorUse); +int StretchDIBits(HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc, int SrcWidth, + int SrcHeight, const void* lpBits, const BITMAPINFO* lpbmi, UINT iUsage, DWORD rop); + +BOOL SetRect(LPRECT lprc, int xLeft, int yTop, int xRight, int yBottom); +BOOL SetRectEmpty(LPRECT lprc); +BOOL CopyRect(LPRECT lprcDst, const RECT* lprcSrc); +BOOL InflateRect(LPRECT lprc, int dx, int dy); +BOOL OffsetRect(LPRECT lprc, int dx, int dy); +BOOL IntersectRect(LPRECT lprcDst, const RECT* lprcSrc1, const RECT* lprcSrc2); +BOOL UnionRect(LPRECT lprcDst, const RECT* lprcSrc1, const RECT* lprcSrc2); +BOOL IsRectEmpty(const RECT* lprc); +BOOL PtInRect(const RECT* lprc, POINT pt); +BOOL EqualRect(const RECT* lprc1, const RECT* lprc2); diff --git a/port/mfcwx/include/mfcwx/winconst.h b/port/mfcwx/include/mfcwx/winconst.h new file mode 100644 index 000000000..c3a9b4e82 --- /dev/null +++ b/port/mfcwx/include/mfcwx/winconst.h @@ -0,0 +1,1946 @@ +#pragma once + +/* Win32 constants with their original numeric values. Parsed by port/rc/rc2cpp.py. */ + +#define FALSE 0 +#define TRUE 1 +#define MAX_PATH 260 +#define _MAX_PATH 260 +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 256 +#define _MAX_EXT 256 +#define INFINITE 0xFFFFFFFF +#define VS_VERSION_INFO 1 + +/* window styles */ +#define WS_OVERLAPPED 0x00000000L +#define WS_POPUP 0x80000000L +#define WS_CHILD 0x40000000L +#define WS_MINIMIZE 0x20000000L +#define WS_VISIBLE 0x10000000L +#define WS_DISABLED 0x08000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_MAXIMIZE 0x01000000L +#define WS_CAPTION 0x00C00000L +#define WS_BORDER 0x00800000L +#define WS_DLGFRAME 0x00400000L +#define WS_VSCROLL 0x00200000L +#define WS_HSCROLL 0x00100000L +#define WS_SYSMENU 0x00080000L +#define WS_THICKFRAME 0x00040000L +#define WS_GROUP 0x00020000L +#define WS_TABSTOP 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_TILED WS_OVERLAPPED +#define WS_ICONIC WS_MINIMIZE +#define WS_SIZEBOX WS_THICKFRAME +#define WS_CHILDWINDOW WS_CHILD +#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW +#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) + +#define WS_EX_DLGMODALFRAME 0x00000001L +#define WS_EX_NOPARENTNOTIFY 0x00000004L +#define WS_EX_TOPMOST 0x00000008L +#define WS_EX_ACCEPTFILES 0x00000010L +#define WS_EX_TRANSPARENT 0x00000020L +#define WS_EX_MDICHILD 0x00000040L +#define WS_EX_TOOLWINDOW 0x00000080L +#define WS_EX_WINDOWEDGE 0x00000100L +#define WS_EX_CLIENTEDGE 0x00000200L +#define WS_EX_CONTEXTHELP 0x00000400L +#define WS_EX_RIGHT 0x00001000L +#define WS_EX_LEFT 0x00000000L +#define WS_EX_RTLREADING 0x00002000L +#define WS_EX_LTRREADING 0x00000000L +#define WS_EX_LEFTSCROLLBAR 0x00004000L +#define WS_EX_RIGHTSCROLLBAR 0x00000000L +#define WS_EX_CONTROLPARENT 0x00010000L +#define WS_EX_STATICEDGE 0x00020000L +#define WS_EX_APPWINDOW 0x00040000L +#define WS_EX_LAYERED 0x00080000L +#define WS_EX_NOINHERITLAYOUT 0x00100000L +#define WS_EX_LAYOUTRTL 0x00400000L +#define WS_EX_COMPOSITED 0x02000000L +#define WS_EX_NOACTIVATE 0x08000000L +#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) +#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) + +/* dialog styles */ +#define DS_ABSALIGN 0x01L +#define DS_SYSMODAL 0x02L +#define DS_3DLOOK 0x04L +#define DS_FIXEDSYS 0x08L +#define DS_NOFAILCREATE 0x10L +#define DS_LOCALEDIT 0x20L +#define DS_SETFONT 0x40L +#define DS_MODALFRAME 0x80L +#define DS_NOIDLEMSG 0x100L +#define DS_SETFOREGROUND 0x200L +#define DS_CONTROL 0x0400L +#define DS_CENTER 0x0800L +#define DS_CENTERMOUSE 0x1000L +#define DS_CONTEXTHELP 0x2000L +#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) + +/* edit styles */ +#define ES_LEFT 0x0000L +#define ES_CENTER 0x0001L +#define ES_RIGHT 0x0002L +#define ES_MULTILINE 0x0004L +#define ES_UPPERCASE 0x0008L +#define ES_LOWERCASE 0x0010L +#define ES_PASSWORD 0x0020L +#define ES_AUTOVSCROLL 0x0040L +#define ES_AUTOHSCROLL 0x0080L +#define ES_NOHIDESEL 0x0100L +#define ES_OEMCONVERT 0x0400L +#define ES_READONLY 0x0800L +#define ES_WANTRETURN 0x1000L +#define ES_NUMBER 0x2000L +#define ES_DISABLENOSCROLL 0x00002000L +#define ES_SUNKEN 0x00004000L +#define ES_SAVESEL 0x00008000L +#define ES_SELFIME 0x00040000L +#define ES_NOIME 0x00080000L +#define ES_VERTICAL 0x00400000L +#define ES_SELECTIONBAR 0x01000000L +#define ES_EX_NOCALLOLEINIT 0x00000000L + +/* button styles */ +#define BS_PUSHBUTTON 0x00000000L +#define BS_DEFPUSHBUTTON 0x00000001L +#define BS_CHECKBOX 0x00000002L +#define BS_AUTOCHECKBOX 0x00000003L +#define BS_RADIOBUTTON 0x00000004L +#define BS_3STATE 0x00000005L +#define BS_AUTO3STATE 0x00000006L +#define BS_GROUPBOX 0x00000007L +#define BS_USERBUTTON 0x00000008L +#define BS_AUTORADIOBUTTON 0x00000009L +#define BS_PUSHBOX 0x0000000AL +#define BS_OWNERDRAW 0x0000000BL +#define BS_SPLITBUTTON 0x0000000CL +#define BS_DEFSPLITBUTTON 0x0000000DL +#define BS_COMMANDLINK 0x0000000EL +#define BS_DEFCOMMANDLINK 0x0000000FL +#define BS_TYPEMASK 0x0000000FL +#define BS_LEFTTEXT 0x00000020L +#define BS_TEXT 0x00000000L +#define BS_ICON 0x00000040L +#define BS_BITMAP 0x00000080L +#define BS_LEFT 0x00000100L +#define BS_RIGHT 0x00000200L +#define BS_CENTER 0x00000300L +#define BS_TOP 0x00000400L +#define BS_BOTTOM 0x00000800L +#define BS_VCENTER 0x00000C00L +#define BS_PUSHLIKE 0x00001000L +#define BS_MULTILINE 0x00002000L +#define BS_NOTIFY 0x00004000L +#define BS_FLAT 0x00008000L +#define BS_RIGHTBUTTON BS_LEFTTEXT + +/* static styles */ +#define SS_LEFT 0x00000000L +#define SS_CENTER 0x00000001L +#define SS_RIGHT 0x00000002L +#define SS_ICON 0x00000003L +#define SS_BLACKRECT 0x00000004L +#define SS_GRAYRECT 0x00000005L +#define SS_WHITERECT 0x00000006L +#define SS_BLACKFRAME 0x00000007L +#define SS_GRAYFRAME 0x00000008L +#define SS_WHITEFRAME 0x00000009L +#define SS_USERITEM 0x0000000AL +#define SS_SIMPLE 0x0000000BL +#define SS_LEFTNOWORDWRAP 0x0000000CL +#define SS_OWNERDRAW 0x0000000DL +#define SS_BITMAP 0x0000000EL +#define SS_ENHMETAFILE 0x0000000FL +#define SS_ETCHEDHORZ 0x00000010L +#define SS_ETCHEDVERT 0x00000011L +#define SS_ETCHEDFRAME 0x00000012L +#define SS_TYPEMASK 0x0000001FL +#define SS_REALSIZECONTROL 0x00000040L +#define SS_NOPREFIX 0x00000080L +#define SS_NOTIFY 0x00000100L +#define SS_CENTERIMAGE 0x00000200L +#define SS_RIGHTJUST 0x00000400L +#define SS_REALSIZEIMAGE 0x00000800L +#define SS_SUNKEN 0x00001000L +#define SS_EDITCONTROL 0x00002000L +#define SS_ENDELLIPSIS 0x00004000L +#define SS_PATHELLIPSIS 0x00008000L +#define SS_WORDELLIPSIS 0x0000C000L +#define SS_ELLIPSISMASK 0x0000C000L + +/* combo box styles */ +#define CBS_SIMPLE 0x0001L +#define CBS_DROPDOWN 0x0002L +#define CBS_DROPDOWNLIST 0x0003L +#define CBS_OWNERDRAWFIXED 0x0010L +#define CBS_OWNERDRAWVARIABLE 0x0020L +#define CBS_AUTOHSCROLL 0x0040L +#define CBS_OEMCONVERT 0x0080L +#define CBS_SORT 0x0100L +#define CBS_HASSTRINGS 0x0200L +#define CBS_NOINTEGRALHEIGHT 0x0400L +#define CBS_DISABLENOSCROLL 0x0800L +#define CBS_UPPERCASE 0x2000L +#define CBS_LOWERCASE 0x4000L + +/* list box styles */ +#define LBS_NOTIFY 0x0001L +#define LBS_SORT 0x0002L +#define LBS_NOREDRAW 0x0004L +#define LBS_MULTIPLESEL 0x0008L +#define LBS_OWNERDRAWFIXED 0x0010L +#define LBS_OWNERDRAWVARIABLE 0x0020L +#define LBS_HASSTRINGS 0x0040L +#define LBS_USETABSTOPS 0x0080L +#define LBS_NOINTEGRALHEIGHT 0x0100L +#define LBS_MULTICOLUMN 0x0200L +#define LBS_WANTKEYBOARDINPUT 0x0400L +#define LBS_EXTENDEDSEL 0x0800L +#define LBS_DISABLENOSCROLL 0x1000L +#define LBS_NODATA 0x2000L +#define LBS_NOSEL 0x4000L +#define LBS_COMBOBOX 0x8000L +#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) + +/* scroll bar styles */ +#define SBS_HORZ 0x0000L +#define SBS_VERT 0x0001L +#define SBS_TOPALIGN 0x0002L +#define SBS_LEFTALIGN 0x0002L +#define SBS_BOTTOMALIGN 0x0004L +#define SBS_RIGHTALIGN 0x0004L +#define SBS_SIZEBOX 0x0008L +#define SBS_SIZEGRIP 0x0010L + +/* common control styles */ +#define CCS_TOP 0x00000001L +#define CCS_NOMOVEY 0x00000002L +#define CCS_BOTTOM 0x00000003L +#define CCS_NORESIZE 0x00000004L +#define CCS_NOPARENTALIGN 0x00000008L +#define CCS_ADJUSTABLE 0x00000020L +#define CCS_NODIVIDER 0x00000040L +#define CCS_VERT 0x00000080L + +#define TBS_AUTOTICKS 0x0001 +#define TBS_VERT 0x0002 +#define TBS_HORZ 0x0000 +#define TBS_TOP 0x0004 +#define TBS_BOTTOM 0x0000 +#define TBS_LEFT 0x0004 +#define TBS_RIGHT 0x0000 +#define TBS_BOTH 0x0008 +#define TBS_NOTICKS 0x0010 +#define TBS_ENABLESELRANGE 0x0020 +#define TBS_FIXEDLENGTH 0x0040 +#define TBS_NOTHUMB 0x0080 +#define TBS_TOOLTIPS 0x0100 +#define TBS_REVERSED 0x0200 + +#define UDS_WRAP 0x0001 +#define UDS_SETBUDDYINT 0x0002 +#define UDS_ALIGNRIGHT 0x0004 +#define UDS_ALIGNLEFT 0x0008 +#define UDS_AUTOBUDDY 0x0010 +#define UDS_ARROWKEYS 0x0020 +#define UDS_HORZ 0x0040 +#define UDS_NOTHOUSANDS 0x0080 +#define UDS_HOTTRACK 0x0100 + +#define PBS_SMOOTH 0x01 +#define PBS_VERTICAL 0x04 +#define PBS_MARQUEE 0x08 + +#define LVS_ICON 0x0000 +#define LVS_REPORT 0x0001 +#define LVS_SMALLICON 0x0002 +#define LVS_LIST 0x0003 +#define LVS_TYPEMASK 0x0003 +#define LVS_SINGLESEL 0x0004 +#define LVS_SHOWSELALWAYS 0x0008 +#define LVS_SORTASCENDING 0x0010 +#define LVS_SORTDESCENDING 0x0020 +#define LVS_SHAREIMAGELISTS 0x0040 +#define LVS_NOLABELWRAP 0x0080 +#define LVS_AUTOARRANGE 0x0100 +#define LVS_EDITLABELS 0x0200 +#define LVS_OWNERDRAWFIXED 0x0400 +#define LVS_ALIGNTOP 0x0000 +#define LVS_ALIGNLEFT 0x0800 +#define LVS_OWNERDATA 0x1000 +#define LVS_NOSCROLL 0x2000 +#define LVS_NOCOLUMNHEADER 0x4000 +#define LVS_NOSORTHEADER 0x8000 + +#define LVS_EX_GRIDLINES 0x00000001 +#define LVS_EX_SUBITEMIMAGES 0x00000002 +#define LVS_EX_CHECKBOXES 0x00000004 +#define LVS_EX_TRACKSELECT 0x00000008 +#define LVS_EX_HEADERDRAGDROP 0x00000010 +#define LVS_EX_FULLROWSELECT 0x00000020 +#define LVS_EX_ONECLICKACTIVATE 0x00000040 +#define LVS_EX_TWOCLICKACTIVATE 0x00000080 +#define LVS_EX_FLATSB 0x00000100 +#define LVS_EX_REGIONAL 0x00000200 +#define LVS_EX_INFOTIP 0x00000400 +#define LVS_EX_UNDERLINEHOT 0x00000800 +#define LVS_EX_UNDERLINECOLD 0x00001000 +#define LVS_EX_MULTIWORKAREAS 0x00002000 +#define LVS_EX_LABELTIP 0x00004000 +#define LVS_EX_BORDERSELECT 0x00008000 +#define LVS_EX_DOUBLEBUFFER 0x00010000 + +#define TVS_HASBUTTONS 0x0001 +#define TVS_HASLINES 0x0002 +#define TVS_LINESATROOT 0x0004 +#define TVS_EDITLABELS 0x0008 +#define TVS_DISABLEDRAGDROP 0x0010 +#define TVS_SHOWSELALWAYS 0x0020 +#define TVS_RTLREADING 0x0040 +#define TVS_NOTOOLTIPS 0x0080 +#define TVS_CHECKBOXES 0x0100 +#define TVS_TRACKSELECT 0x0200 +#define TVS_SINGLEEXPAND 0x0400 +#define TVS_INFOTIP 0x0800 +#define TVS_FULLROWSELECT 0x1000 +#define TVS_NOSCROLL 0x2000 +#define TVS_NONEVENHEIGHT 0x4000 + +#define TCS_SCROLLOPPOSITE 0x0001 +#define TCS_BOTTOM 0x0002 +#define TCS_RIGHT 0x0002 +#define TCS_MULTISELECT 0x0004 +#define TCS_FLATBUTTONS 0x0008 +#define TCS_FORCEICONLEFT 0x0010 +#define TCS_FORCELABELLEFT 0x0020 +#define TCS_HOTTRACK 0x0040 +#define TCS_VERTICAL 0x0080 +#define TCS_TABS 0x0000 +#define TCS_BUTTONS 0x0100 +#define TCS_SINGLELINE 0x0000 +#define TCS_MULTILINE 0x0200 +#define TCS_RIGHTJUSTIFY 0x0000 +#define TCS_FIXEDWIDTH 0x0400 +#define TCS_RAGGEDRIGHT 0x0800 +#define TCS_FOCUSONBUTTONDOWN 0x1000 +#define TCS_OWNERDRAWFIXED 0x2000 +#define TCS_TOOLTIPS 0x4000 +#define TCS_FOCUSNEVER 0x8000 + +#define ACS_CENTER 0x0001 +#define ACS_TRANSPARENT 0x0002 +#define ACS_AUTOPLAY 0x0004 +#define ACS_TIMER 0x0008 + +#define DTS_UPDOWN 0x0001 +#define DTS_SHOWNONE 0x0002 +#define DTS_SHORTDATEFORMAT 0x0000 +#define DTS_LONGDATEFORMAT 0x0004 +#define DTS_TIMEFORMAT 0x0009 +#define DTS_APPCANPARSE 0x0010 +#define DTS_RIGHTALIGN 0x0020 + +#define HDS_HORZ 0x0000 +#define HDN_BEGINTRACK (HDN_FIRST - 6) +#define HDN_ENDTRACK (HDN_FIRST - 7) +#define HDN_TRACK (HDN_FIRST - 8) +#define HDN_ITEMCHANGING (HDN_FIRST - 0) +#define HDN_ITEMCHANGED (HDN_FIRST - 1) +#define HDN_DIVIDERDBLCLICK (HDN_FIRST - 5) +#define HDI_WIDTH 0x0001 +#define HDI_TEXT 0x0002 +#define HDI_FORMAT 0x0004 +#define HDI_LPARAM 0x0008 +#define HDS_BUTTONS 0x0002 +#define HDS_HOTTRACK 0x0004 + +#define TTS_ALWAYSTIP 0x01 +#define TTS_NOPREFIX 0x02 +#define TTS_BALLOON 0x40 + +#define SBARS_SIZEGRIP 0x0100 + +#define TBSTYLE_BUTTON 0x0000 +#define TBSTYLE_SEP 0x0001 +#define TBSTYLE_CHECK 0x0002 +#define TBSTYLE_GROUP 0x0004 +#define TBSTYLE_CHECKGROUP (TBSTYLE_GROUP | TBSTYLE_CHECK) +#define TBSTYLE_DROPDOWN 0x0008 +#define TBSTYLE_AUTOSIZE 0x0010 +#define TBSTYLE_NOPREFIX 0x0020 +#define TBSTYLE_TOOLTIPS 0x0100 +#define TBSTYLE_WRAPABLE 0x0200 +#define TBSTYLE_ALTDRAG 0x0400 +#define TBSTYLE_FLAT 0x0800 +#define TBSTYLE_LIST 0x1000 +#define TBSTYLE_TRANSPARENT 0x8000 + +/* MFC control bar styles */ +#define CBRS_ALIGN_LEFT 0x1000L +#define CBRS_ALIGN_TOP 0x2000L +#define CBRS_ALIGN_RIGHT 0x4000L +#define CBRS_ALIGN_BOTTOM 0x8000L +#define CBRS_ALIGN_ANY 0xF000L +#define CBRS_BORDER_LEFT 0x0100L +#define CBRS_BORDER_TOP 0x0200L +#define CBRS_BORDER_RIGHT 0x0400L +#define CBRS_BORDER_BOTTOM 0x0800L +#define CBRS_BORDER_ANY 0x0F00L +#define CBRS_TOOLTIPS 0x0010L +#define CBRS_FLYBY 0x0020L +#define CBRS_FLOAT_MULTI 0x0040L +#define CBRS_BORDER_3D 0x0080L +#define CBRS_HIDE_INPLACE 0x0008L +#define CBRS_SIZE_DYNAMIC 0x0004L +#define CBRS_SIZE_FIXED 0x0002L +#define CBRS_FLOATING 0x0001L +#define CBRS_GRIPPER 0x00400000L +#define CBRS_ORIENT_HORZ (CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM) +#define CBRS_ORIENT_VERT (CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT) +#define CBRS_ORIENT_ANY (CBRS_ORIENT_HORZ | CBRS_ORIENT_VERT) +#define CBRS_ALL 0x0040FFFFL +#define CBRS_NOALIGN 0x00000000L +#define CBRS_LEFT (CBRS_ALIGN_LEFT | CBRS_BORDER_RIGHT) +#define CBRS_TOP (CBRS_ALIGN_TOP | CBRS_BORDER_BOTTOM) +#define CBRS_RIGHT (CBRS_ALIGN_RIGHT | CBRS_BORDER_LEFT) +#define CBRS_BOTTOM (CBRS_ALIGN_BOTTOM | CBRS_BORDER_TOP) + +/* window messages */ +#define WM_NULL 0x0000 +#define WM_CREATE 0x0001 +#define WM_DESTROY 0x0002 +#define WM_MOVE 0x0003 +#define WM_SIZE 0x0005 +#define WM_ACTIVATE 0x0006 +#define WM_SETFOCUS 0x0007 +#define WM_KILLFOCUS 0x0008 +#define WM_ENABLE 0x000A +#define WM_SETREDRAW 0x000B +#define WM_SETTEXT 0x000C +#define WM_GETTEXT 0x000D +#define WM_GETTEXTLENGTH 0x000E +#define WM_PAINT 0x000F +#define WM_CLOSE 0x0010 +#define WM_QUERYENDSESSION 0x0011 +#define WM_QUIT 0x0012 +#define WM_QUERYOPEN 0x0013 +#define WM_ERASEBKGND 0x0014 +#define WM_SYSCOLORCHANGE 0x0015 +#define WM_ENDSESSION 0x0016 +#define WM_SHOWWINDOW 0x0018 +#define WM_CTLCOLOR 0x0019 +#define WM_SETTINGCHANGE 0x001A +#define WM_WININICHANGE 0x001A +#define WM_ACTIVATEAPP 0x001C +#define WM_FONTCHANGE 0x001D +#define WM_TIMECHANGE 0x001E +#define WM_CANCELMODE 0x001F +#define WM_SETCURSOR 0x0020 +#define WM_MOUSEACTIVATE 0x0021 +#define WM_CHILDACTIVATE 0x0022 +#define WM_GETMINMAXINFO 0x0024 +#define WM_NEXTDLGCTL 0x0028 +#define WM_DRAWITEM 0x002B +#define WM_MEASUREITEM 0x002C +#define WM_DELETEITEM 0x002D +#define WM_VKEYTOITEM 0x002E +#define WM_CHARTOITEM 0x002F +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_QUERYDRAGICON 0x0037 +#define WM_COMPAREITEM 0x0039 +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 +#define WM_NOTIFY 0x004E +#define WM_HELP 0x0053 +#define WM_CONTEXTMENU 0x007B +#define WM_STYLECHANGING 0x007C +#define WM_STYLECHANGED 0x007D +#define WM_DISPLAYCHANGE 0x007E +#define WM_GETICON 0x007F +#define WM_SETICON 0x0080 +#define WM_NCCREATE 0x0081 +#define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 +#define WM_NCHITTEST 0x0084 +#define WM_NCPAINT 0x0085 +#define WM_NCACTIVATE 0x0086 +#define WM_GETDLGCODE 0x0087 +#define WM_NCMOUSEMOVE 0x00A0 +#define WM_NCLBUTTONDOWN 0x00A1 +#define WM_NCLBUTTONUP 0x00A2 +#define WM_NCLBUTTONDBLCLK 0x00A3 +#define WM_KEYFIRST 0x0100 +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_KEYLAST 0x0108 +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_MOUSELAST 0x020A +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 +#define WM_MDISETMENU 0x0230 +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 +#define WM_MOUSEHOVER 0x02A1 +#define WM_MOUSELEAVE 0x02A3 +#define WM_CUT 0x0300 +#define WM_COPY 0x0301 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 +#define WM_RENDERFORMAT 0x0305 +#define WM_DESTROYCLIPBOARD 0x0307 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 +#define WM_APPCOMMAND 0x0319 +#define WM_THEMECHANGED 0x031A +#define WM_USER 0x0400 +#define WM_APP 0x8000 + +/* MFC private messages */ +#define WM_QUERYAFXWNDPROC 0x0360 +#define WM_SIZEPARENT 0x0361 +#define WM_SETMESSAGESTRING 0x0362 +#define WM_IDLEUPDATECMDUI 0x0363 +#define WM_INITIALUPDATE 0x0364 +#define WM_COMMANDHELP 0x0365 +#define WM_HELPHITTEST 0x0366 +#define WM_EXITHELPMODE 0x0367 +#define WM_RECALCPARENT 0x0368 +#define WM_SIZECHILD 0x0369 +#define WM_KICKIDLE 0x036A +#define WM_QUERYCENTERWND 0x036B +#define WM_DISABLEMODAL 0x036C +#define WM_FLOATSTATUS 0x036D +#define WM_ACTIVATETOPLEVEL 0x036E + +/* edit control messages and notifications */ +#define EM_GETSEL 0x00B0 +#define EM_SETSEL 0x00B1 +#define EM_GETRECT 0x00B2 +#define EM_SETRECT 0x00B3 +#define EM_SETRECTNP 0x00B4 +#define EM_SCROLL 0x00B5 +#define EM_LINESCROLL 0x00B6 +#define EM_SCROLLCARET 0x00B7 +#define EM_GETMODIFY 0x00B8 +#define EM_SETMODIFY 0x00B9 +#define EM_GETLINECOUNT 0x00BA +#define EM_LINEINDEX 0x00BB +#define EM_SETHANDLE 0x00BC +#define EM_GETHANDLE 0x00BD +#define EM_GETTHUMB 0x00BE +#define EM_LINELENGTH 0x00C1 +#define EM_REPLACESEL 0x00C2 +#define EM_GETLINE 0x00C4 +#define EM_LIMITTEXT 0x00C5 +#define EM_SETLIMITTEXT EM_LIMITTEXT +#define EM_CANUNDO 0x00C6 +#define EM_UNDO 0x00C7 +#define EM_FMTLINES 0x00C8 +#define EM_LINEFROMCHAR 0x00C9 +#define EM_SETTABSTOPS 0x00CB +#define EM_SETPASSWORDCHAR 0x00CC +#define EM_EMPTYUNDOBUFFER 0x00CD +#define EM_GETFIRSTVISIBLELINE 0x00CE +#define EM_SETREADONLY 0x00CF +#define EM_SETWORDBREAKPROC 0x00D0 +#define EM_GETWORDBREAKPROC 0x00D1 +#define EM_GETPASSWORDCHAR 0x00D2 +#define EM_SETMARGINS 0x00D3 +#define EM_GETMARGINS 0x00D4 +#define EM_GETLIMITTEXT 0x00D5 +#define EM_POSFROMCHAR 0x00D6 +#define EM_CHARFROMPOS 0x00D7 +#define EC_LEFTMARGIN 0x0001 +#define EC_RIGHTMARGIN 0x0002 +#define EC_USEFONTINFO 0xffff + +#define EN_SETFOCUS 0x0100 +#define EN_KILLFOCUS 0x0200 +#define EN_CHANGE 0x0300 +#define EN_UPDATE 0x0400 +#define EN_ERRSPACE 0x0500 +#define EN_MAXTEXT 0x0501 +#define EN_HSCROLL 0x0601 +#define EN_VSCROLL 0x0602 +#define EN_MSGFILTER 0x0700 +#define EN_REQUESTRESIZE 0x0701 +#define EN_SELCHANGE 0x0702 +#define EN_DROPFILES 0x0703 +#define EN_PROTECTED 0x0704 +#define EN_LINK 0x070b + +/* rich edit messages */ +#define EM_CANPASTE (WM_USER + 50) +#define EM_DISPLAYBAND (WM_USER + 51) +#define EM_EXGETSEL (WM_USER + 52) +#define EM_EXLIMITTEXT (WM_USER + 53) +#define EM_EXLINEFROMCHAR (WM_USER + 54) +#define EM_EXSETSEL (WM_USER + 55) +#define EM_FINDTEXT (WM_USER + 56) +#define EM_FORMATRANGE (WM_USER + 57) +#define EM_GETCHARFORMAT (WM_USER + 58) +#define EM_GETEVENTMASK (WM_USER + 59) +#define EM_GETOLEINTERFACE (WM_USER + 60) +#define EM_GETPARAFORMAT (WM_USER + 61) +#define EM_GETSELTEXT (WM_USER + 62) +#define EM_HIDESELECTION (WM_USER + 63) +#define EM_PASTESPECIAL (WM_USER + 64) +#define EM_REQUESTRESIZE (WM_USER + 65) +#define EM_SELECTIONTYPE (WM_USER + 66) +#define EM_SETBKGNDCOLOR (WM_USER + 67) +#define EM_SETCHARFORMAT (WM_USER + 68) +#define EM_SETEVENTMASK (WM_USER + 69) +#define EM_SETOLECALLBACK (WM_USER + 70) +#define EM_SETPARAFORMAT (WM_USER + 71) +#define EM_SETTARGETDEVICE (WM_USER + 72) +#define EM_STREAMIN (WM_USER + 73) +#define EM_STREAMOUT (WM_USER + 74) +#define EM_GETTEXTRANGE (WM_USER + 75) +#define EM_FINDWORDBREAK (WM_USER + 76) +#define EM_SETOPTIONS (WM_USER + 77) +#define EM_GETOPTIONS (WM_USER + 78) +#define EM_FINDTEXTEX (WM_USER + 79) +#define EM_SETUNDOLIMIT (WM_USER + 82) +#define EM_REDO (WM_USER + 84) +#define EM_CANREDO (WM_USER + 85) +#define EM_SETTEXTMODE (WM_USER + 89) +#define EM_GETTEXTMODE (WM_USER + 90) +#define EM_AUTOURLDETECT (WM_USER + 91) +#define EM_GETTEXTEX (WM_USER + 94) +#define EM_GETTEXTLENGTHEX (WM_USER + 95) +#define EM_SETTEXTEX (WM_USER + 97) +#define ENM_NONE 0x00000000 +#define ENM_CHANGE 0x00000001 +#define ENM_UPDATE 0x00000002 +#define ENM_SCROLL 0x00000004 +#define ENM_KEYEVENTS 0x00010000 +#define ENM_MOUSEEVENTS 0x00020000 +#define ENM_REQUESTRESIZE 0x00040000 +#define ENM_SELCHANGE 0x00080000 +#define ENM_LINK 0x04000000 +#define SF_TEXT 0x0001 +#define SF_RTF 0x0002 +#define SFF_SELECTION 0x8000 +#define CFM_BOLD 0x00000001 +#define CFM_ITALIC 0x00000002 +#define CFM_UNDERLINE 0x00000004 +#define CFM_STRIKEOUT 0x00000008 +#define CFM_PROTECTED 0x00000010 +#define CFM_LINK 0x00000020 +#define CFM_SIZE 0x80000000 +#define CFM_COLOR 0x40000000 +#define CFM_FACE 0x20000000 +#define CFM_OFFSET 0x10000000 +#define CFM_CHARSET 0x08000000 +#define CFE_BOLD 0x0001 +#define CFE_ITALIC 0x0002 +#define CFE_UNDERLINE 0x0004 +#define CFE_STRIKEOUT 0x0008 +#define CFE_PROTECTED 0x0010 +#define CFE_LINK 0x0020 +#define CFE_AUTOCOLOR 0x40000000 +#define SCF_SELECTION 0x0001 +#define SCF_WORD 0x0002 +#define SCF_DEFAULT 0x0000 +#define SCF_ALL 0x0004 + +/* button messages and notifications */ +#define BM_GETCHECK 0x00F0 +#define BM_SETCHECK 0x00F1 +#define BM_GETSTATE 0x00F2 +#define BM_SETSTATE 0x00F3 +#define BM_SETSTYLE 0x00F4 +#define BM_CLICK 0x00F5 +#define BM_GETIMAGE 0x00F6 +#define BM_SETIMAGE 0x00F7 +#define BST_UNCHECKED 0x0000 +#define BST_CHECKED 0x0001 +#define BST_INDETERMINATE 0x0002 +#define BST_PUSHED 0x0004 +#define BST_FOCUS 0x0008 +#define BN_CLICKED 0 +#define BN_PAINT 1 +#define BN_HILITE 2 +#define BN_UNHILITE 3 +#define BN_DISABLE 4 +#define BN_DOUBLECLICKED 5 +#define BN_PUSHED BN_HILITE +#define BN_UNPUSHED BN_UNHILITE +#define BN_DBLCLK BN_DOUBLECLICKED +#define BN_SETFOCUS 6 +#define BN_KILLFOCUS 7 + +/* static messages and notifications */ +#define STM_SETICON 0x0170 +#define STM_GETICON 0x0171 +#define STM_SETIMAGE 0x0172 +#define STM_GETIMAGE 0x0173 +#define STN_CLICKED 0 +#define STN_DBLCLK 1 +#define STN_ENABLE 2 +#define STN_DISABLE 3 +#define IMAGE_BITMAP 0 +#define IMAGE_ICON 1 +#define IMAGE_CURSOR 2 +#define IMAGE_ENHMETAFILE 3 +#define LR_DEFAULTCOLOR 0x0000 +#define LR_MONOCHROME 0x0001 +#define LR_LOADFROMFILE 0x0010 +#define LR_LOADTRANSPARENT 0x0020 +#define LR_DEFAULTSIZE 0x0040 +#define LR_LOADMAP3DCOLORS 0x1000 +#define LR_CREATEDIBSECTION 0x2000 +#define LR_SHARED 0x8000 + +/* combo box messages and notifications */ +#define CB_OKAY 0 +#define CB_ERR (-1) +#define CB_ERRSPACE (-2) +#define CBN_ERRSPACE (-1) +#define CBN_SELCHANGE 1 +#define CBN_DBLCLK 2 +#define CBN_SETFOCUS 3 +#define CBN_KILLFOCUS 4 +#define CBN_EDITCHANGE 5 +#define CBN_EDITUPDATE 6 +#define CBN_DROPDOWN 7 +#define CBN_CLOSEUP 8 +#define CBN_SELENDOK 9 +#define CBN_SELENDCANCEL 10 +#define CB_GETEDITSEL 0x0140 +#define CB_LIMITTEXT 0x0141 +#define CB_SETEDITSEL 0x0142 +#define CB_ADDSTRING 0x0143 +#define CB_DELETESTRING 0x0144 +#define CB_DIR 0x0145 +#define CB_GETCOUNT 0x0146 +#define CB_GETCURSEL 0x0147 +#define CB_GETLBTEXT 0x0148 +#define CB_GETLBTEXTLEN 0x0149 +#define CB_INSERTSTRING 0x014A +#define CB_RESETCONTENT 0x014B +#define CB_FINDSTRING 0x014C +#define CB_SELECTSTRING 0x014D +#define CB_SETCURSEL 0x014E +#define CB_SHOWDROPDOWN 0x014F +#define CB_GETITEMDATA 0x0150 +#define CB_SETITEMDATA 0x0151 +#define CB_GETDROPPEDCONTROLRECT 0x0152 +#define CB_SETITEMHEIGHT 0x0153 +#define CB_GETITEMHEIGHT 0x0154 +#define CB_SETEXTENDEDUI 0x0155 +#define CB_GETEXTENDEDUI 0x0156 +#define CB_GETDROPPEDSTATE 0x0157 +#define CB_FINDSTRINGEXACT 0x0158 +#define CB_SETLOCALE 0x0159 +#define CB_GETLOCALE 0x015A +#define CB_GETTOPINDEX 0x015B +#define CB_SETTOPINDEX 0x015C +#define CB_GETHORIZONTALEXTENT 0x015D +#define CB_SETHORIZONTALEXTENT 0x015E +#define CB_GETDROPPEDWIDTH 0x015F +#define CB_SETDROPPEDWIDTH 0x0160 +#define CB_INITSTORAGE 0x0161 + +/* list box messages and notifications */ +#define LB_OKAY 0 +#define LB_ERR (-1) +#define LB_ERRSPACE (-2) +#define LBN_ERRSPACE (-2) +#define LBN_SELCHANGE 1 +#define LBN_DBLCLK 2 +#define LBN_SELCANCEL 3 +#define LBN_SETFOCUS 4 +#define LBN_KILLFOCUS 5 +#define LB_ADDSTRING 0x0180 +#define LB_INSERTSTRING 0x0181 +#define LB_DELETESTRING 0x0182 +#define LB_SELITEMRANGEEX 0x0183 +#define LB_RESETCONTENT 0x0184 +#define LB_SETSEL 0x0185 +#define LB_SETCURSEL 0x0186 +#define LB_GETSEL 0x0187 +#define LB_GETCURSEL 0x0188 +#define LB_GETTEXT 0x0189 +#define LB_GETTEXTLEN 0x018A +#define LB_GETCOUNT 0x018B +#define LB_SELECTSTRING 0x018C +#define LB_DIR 0x018D +#define LB_GETTOPINDEX 0x018E +#define LB_FINDSTRING 0x018F +#define LB_GETSELCOUNT 0x0190 +#define LB_GETSELITEMS 0x0191 +#define LB_SETTABSTOPS 0x0192 +#define LB_GETHORIZONTALEXTENT 0x0193 +#define LB_SETHORIZONTALEXTENT 0x0194 +#define LB_SETCOLUMNWIDTH 0x0195 +#define LB_ADDFILE 0x0196 +#define LB_SETTOPINDEX 0x0197 +#define LB_GETITEMRECT 0x0198 +#define LB_GETITEMDATA 0x0199 +#define LB_SETITEMDATA 0x019A +#define LB_SELITEMRANGE 0x019B +#define LB_SETANCHORINDEX 0x019C +#define LB_GETANCHORINDEX 0x019D +#define LB_SETCARETINDEX 0x019E +#define LB_GETCARETINDEX 0x019F +#define LB_SETITEMHEIGHT 0x01A0 +#define LB_GETITEMHEIGHT 0x01A1 +#define LB_FINDSTRINGEXACT 0x01A2 + +/* scroll bar */ +#define SB_LINEUP 0 +#define SB_LINELEFT 0 +#define SB_LINEDOWN 1 +#define SB_LINERIGHT 1 +#define SB_PAGEUP 2 +#define SB_PAGELEFT 2 +#define SB_PAGEDOWN 3 +#define SB_PAGERIGHT 3 +#define SB_THUMBPOSITION 4 +#define SB_THUMBTRACK 5 +#define SB_TOP 6 +#define SB_LEFT 6 +#define SB_BOTTOM 7 +#define SB_RIGHT 7 +#define SB_ENDSCROLL 8 +#define SB_HORZ 0 +#define SB_VERT 1 +#define SB_CTL 2 +#define SB_BOTH 3 +#define SIF_RANGE 0x0001 +#define SIF_PAGE 0x0002 +#define SIF_POS 0x0004 +#define SIF_DISABLENOSCROLL 0x0008 +#define SIF_TRACKPOS 0x0010 +#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) +#define ESB_ENABLE_BOTH 0x0000 +#define ESB_DISABLE_BOTH 0x0003 +#define SBM_SETPOS 0x00E0 +#define SBM_GETPOS 0x00E1 +#define SBM_SETRANGE 0x00E2 +#define SBM_GETRANGE 0x00E3 +#define SBM_SETRANGEREDRAW 0x00E6 +#define SBM_SETSCROLLINFO 0x00E9 +#define SBM_GETSCROLLINFO 0x00EA + +/* trackbar */ +#define TBM_GETPOS (WM_USER) +#define TBM_GETRANGEMIN (WM_USER + 1) +#define TBM_GETRANGEMAX (WM_USER + 2) +#define TBM_GETTIC (WM_USER + 3) +#define TBM_SETTIC (WM_USER + 4) +#define TBM_SETPOS (WM_USER + 5) +#define TBM_SETRANGE (WM_USER + 6) +#define TBM_SETRANGEMIN (WM_USER + 7) +#define TBM_SETRANGEMAX (WM_USER + 8) +#define TBM_CLEARTICS (WM_USER + 9) +#define TBM_SETSEL (WM_USER + 10) +#define TBM_SETSELSTART (WM_USER + 11) +#define TBM_SETSELEND (WM_USER + 12) +#define TBM_GETPTICS (WM_USER + 14) +#define TBM_GETTICPOS (WM_USER + 15) +#define TBM_GETNUMTICS (WM_USER + 16) +#define TBM_GETSELSTART (WM_USER + 17) +#define TBM_GETSELEND (WM_USER + 18) +#define TBM_CLEARSEL (WM_USER + 19) +#define TBM_SETTICFREQ (WM_USER + 20) +#define TBM_SETPAGESIZE (WM_USER + 21) +#define TBM_GETPAGESIZE (WM_USER + 22) +#define TBM_SETLINESIZE (WM_USER + 23) +#define TBM_GETLINESIZE (WM_USER + 24) +#define TB_LINEUP 0 +#define TB_LINEDOWN 1 +#define TB_PAGEUP 2 +#define TB_PAGEDOWN 3 +#define TB_THUMBPOSITION 4 +#define TB_THUMBTRACK 5 +#define TB_TOP 6 +#define TB_BOTTOM 7 +#define TB_ENDTRACK 8 + +/* progress bar */ +#define PBM_SETRANGE (WM_USER + 1) +#define PBM_SETPOS (WM_USER + 2) +#define PBM_DELTAPOS (WM_USER + 3) +#define PBM_SETSTEP (WM_USER + 4) +#define PBM_STEPIT (WM_USER + 5) +#define PBM_SETRANGE32 (WM_USER + 6) +#define PBM_GETRANGE (WM_USER + 7) +#define PBM_GETPOS (WM_USER + 8) +#define PBM_SETBARCOLOR (WM_USER + 9) +#define PBM_SETMARQUEE (WM_USER + 10) +#define CCM_FIRST 0x2000 +#define CCM_SETBKCOLOR (CCM_FIRST + 1) +#define PBM_SETBKCOLOR CCM_SETBKCOLOR + +/* up-down */ +#define UDM_SETRANGE (WM_USER + 101) +#define UDM_GETRANGE (WM_USER + 102) +#define UDM_SETPOS (WM_USER + 103) +#define UDM_GETPOS (WM_USER + 104) +#define UDM_SETBUDDY (WM_USER + 105) +#define UDM_GETBUDDY (WM_USER + 106) +#define UDM_SETACCEL (WM_USER + 107) +#define UDM_GETACCEL (WM_USER + 108) +#define UDM_SETBASE (WM_USER + 109) +#define UDM_GETBASE (WM_USER + 110) +#define UDM_SETRANGE32 (WM_USER + 111) +#define UDM_GETRANGE32 (WM_USER + 112) +#define UDM_SETPOS32 (WM_USER + 113) +#define UDM_GETPOS32 (WM_USER + 114) +#define UD_MAXVAL 0x7fff +#define UD_MINVAL (-UD_MAXVAL) + +/* WM_NOTIFY codes */ +#define NM_FIRST (0U - 0U) +#define NM_OUTOFMEMORY (NM_FIRST - 1) +#define NM_CLICK (NM_FIRST - 2) +#define NM_DBLCLK (NM_FIRST - 3) +#define NM_RETURN (NM_FIRST - 4) +#define NM_RCLICK (NM_FIRST - 5) +#define NM_RDBLCLK (NM_FIRST - 6) +#define NM_SETFOCUS (NM_FIRST - 7) +#define NM_KILLFOCUS (NM_FIRST - 8) +#define NM_CUSTOMDRAW (NM_FIRST - 12) +#define NM_HOVER (NM_FIRST - 13) +#define NM_NCHITTEST (NM_FIRST - 14) +#define NM_KEYDOWN (NM_FIRST - 15) +#define NM_RELEASEDCAPTURE (NM_FIRST - 16) +#define NM_SETCURSOR (NM_FIRST - 17) +#define NM_CHAR (NM_FIRST - 18) +#define LVN_FIRST (0U - 100U) +#define LVN_ITEMCHANGING (LVN_FIRST - 0) +#define LVN_ITEMCHANGED (LVN_FIRST - 1) +#define LVN_INSERTITEM (LVN_FIRST - 2) +#define LVN_DELETEITEM (LVN_FIRST - 3) +#define LVN_DELETEALLITEMS (LVN_FIRST - 4) +#define LVN_BEGINLABELEDIT (LVN_FIRST - 5) +#define LVN_ENDLABELEDIT (LVN_FIRST - 6) +#define LVN_COLUMNCLICK (LVN_FIRST - 8) +#define LVN_BEGINDRAG (LVN_FIRST - 9) +#define LVN_BEGINRDRAG (LVN_FIRST - 11) +#define LVN_ODCACHEHINT (LVN_FIRST - 13) +#define LVN_ITEMACTIVATE (LVN_FIRST - 14) +#define LVN_ODSTATECHANGED (LVN_FIRST - 15) +#define LVN_HOTTRACK (LVN_FIRST - 21) +#define LVN_GETDISPINFO (LVN_FIRST - 50) +#define LVN_SETDISPINFO (LVN_FIRST - 51) +#define LVN_ODFINDITEM (LVN_FIRST - 52) +#define LVN_KEYDOWN (LVN_FIRST - 55) +#define LVN_GETINFOTIP (LVN_FIRST - 57) +#define HDN_FIRST (0U - 300U) +#define HDN_ITEMCLICK (HDN_FIRST - 2) +#define TVN_FIRST (0U - 400U) +#define TVN_SELCHANGING (TVN_FIRST - 1) +#define TVN_SELCHANGED (TVN_FIRST - 2) +#define TVN_GETDISPINFO (TVN_FIRST - 3) +#define TVN_SETDISPINFO (TVN_FIRST - 4) +#define TVN_ITEMEXPANDING (TVN_FIRST - 5) +#define TVN_ITEMEXPANDED (TVN_FIRST - 6) +#define TVN_BEGINDRAG (TVN_FIRST - 7) +#define TVN_KEYDOWN (TVN_FIRST - 12) +#define TTN_FIRST (0U - 520U) +#define TTN_GETDISPINFO (TTN_FIRST - 0) +#define TTN_NEEDTEXT TTN_GETDISPINFO +#define TTN_SHOW (TTN_FIRST - 1) +#define TTN_POP (TTN_FIRST - 2) +#define TCN_FIRST (0U - 550U) +#define TCN_KEYDOWN (TCN_FIRST - 0) +#define TCN_SELCHANGE (TCN_FIRST - 1) +#define TCN_SELCHANGING (TCN_FIRST - 2) +#define UDN_FIRST (0U - 721U) +#define UDN_DELTAPOS (UDN_FIRST - 1) +#define DTN_FIRST (0U - 760U) +#define DTN_DATETIMECHANGE (DTN_FIRST + 1) +#define MCN_FIRST (0U - 750U) + +/* list view */ +#define LVM_FIRST 0x1000 +#define LVM_GETITEMCOUNT (LVM_FIRST + 4) +#define LVM_GETITEMRECT (LVM_FIRST + 14) +#define LVM_GETTOPINDEX (LVM_FIRST + 39) +#define LVM_GETITEMTEXT (LVM_FIRST + 45) +#define LVM_SETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 54) +#define LVM_GETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 55) +#define LVM_GETSUBITEMRECT (LVM_FIRST + 56) +#define LVM_SUBITEMHITTEST (LVM_FIRST + 57) +#define LVCF_FMT 0x0001 +#define LVCF_WIDTH 0x0002 +#define LVCF_TEXT 0x0004 +#define LVCF_SUBITEM 0x0008 +#define LVCF_IMAGE 0x0010 +#define LVCF_ORDER 0x0020 +#define LVCFMT_LEFT 0x0000 +#define LVCFMT_RIGHT 0x0001 +#define LVCFMT_CENTER 0x0002 +#define LVCFMT_JUSTIFYMASK 0x0003 +#define LVIF_TEXT 0x0001 +#define LVIF_IMAGE 0x0002 +#define LVIF_PARAM 0x0004 +#define LVIF_STATE 0x0008 +#define LVIF_INDENT 0x0010 +#define LVIF_NORECOMPUTE 0x0800 +#define LVIS_FOCUSED 0x0001 +#define LVIS_SELECTED 0x0002 +#define LVIS_CUT 0x0004 +#define LVIS_DROPHILITED 0x0008 +#define LVIS_OVERLAYMASK 0x0F00 +#define LVIS_STATEIMAGEMASK 0xF000 +#define LVNI_ALL 0x0000 +#define LVNI_FOCUSED 0x0001 +#define LVNI_SELECTED 0x0002 +#define LVNI_CUT 0x0004 +#define LVNI_DROPHILITED 0x0008 +#define LVNI_ABOVE 0x0100 +#define LVNI_BELOW 0x0200 +#define LVNI_TOLEFT 0x0400 +#define LVNI_TORIGHT 0x0800 +#define LVSCW_AUTOSIZE (-1) +#define LVSCW_AUTOSIZE_USEHEADER (-2) +#define LVIR_BOUNDS 0 +#define LVIR_ICON 1 +#define LVIR_LABEL 2 +#define LVIR_SELECTBOUNDS 3 +#define LVHT_NOWHERE 0x0001 +#define LVHT_ONITEMICON 0x0002 +#define LVHT_ONITEMLABEL 0x0004 +#define LVHT_ONITEMSTATEICON 0x0008 +#define LVHT_ONITEM (LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON) +#define LVSIL_NORMAL 0 +#define LVSIL_SMALL 1 +#define LVSIL_STATE 2 +#define LVFI_PARAM 0x0001 +#define LVFI_STRING 0x0002 +#define LVFI_PARTIAL 0x0008 +#define LVFI_WRAP 0x0020 +#define LVFI_NEARESTXY 0x0040 +#define LVA_DEFAULT 0x0000 + +/* tree view */ +#define TVI_ROOT ((HTREEITEM)(intptr_t)-0x10000) +#define TVI_FIRST ((HTREEITEM)(intptr_t)-0x0FFFF) +#define TVI_LAST ((HTREEITEM)(intptr_t)-0x0FFFE) +#define TVI_SORT ((HTREEITEM)(intptr_t)-0x0FFFD) +#define TVIF_TEXT 0x0001 +#define TVIF_IMAGE 0x0002 +#define TVIF_PARAM 0x0004 +#define TVIF_STATE 0x0008 +#define TVIF_HANDLE 0x0010 +#define TVIF_SELECTEDIMAGE 0x0020 +#define TVIF_CHILDREN 0x0040 +#define TVIS_SELECTED 0x0002 +#define TVIS_BOLD 0x0010 +#define TVIS_EXPANDED 0x0020 +#define TVE_COLLAPSE 0x0001 +#define TVE_EXPAND 0x0002 +#define TVE_TOGGLE 0x0003 +#define TVGN_ROOT 0x0000 +#define TVGN_NEXT 0x0001 +#define TVGN_PREVIOUS 0x0002 +#define TVGN_PARENT 0x0003 +#define TVGN_CHILD 0x0004 +#define TVGN_FIRSTVISIBLE 0x0005 +#define TVGN_NEXTVISIBLE 0x0006 +#define TVGN_PREVIOUSVISIBLE 0x0007 +#define TVGN_DROPHILITE 0x0008 +#define TVGN_CARET 0x0009 + +/* tab control */ +#define TCIF_TEXT 0x0001 +#define TCIF_IMAGE 0x0002 +#define TCIF_RTLREADING 0x0004 +#define TCIF_PARAM 0x0008 +#define TCIF_STATE 0x0010 + +/* virtual keys */ +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +#define VK_BACK 0x08 +#define VK_TAB 0x09 +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 +#define VK_ESCAPE 0x1B +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F +#define VK_LWIN 0x5B +#define VK_RWIN 0x5C +#define VK_APPS 0x5D +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +#define VK_LSHIFT 0xA0 +#define VK_RSHIFT 0xA1 +#define VK_LCONTROL 0xA2 +#define VK_RCONTROL 0xA3 +#define VK_LMENU 0xA4 +#define VK_RMENU 0xA5 +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE + +/* accelerators */ +#define FVIRTKEY 0x01 +#define FNOINVERT 0x02 +#define FSHIFT 0x04 +#define FCONTROL 0x08 +#define FALT 0x10 + +/* menus */ +#define MF_INSERT 0x00000000L +#define MF_CHANGE 0x00000080L +#define MF_APPEND 0x00000100L +#define MF_DELETE 0x00000200L +#define MF_REMOVE 0x00001000L +#define MF_BYCOMMAND 0x00000000L +#define MF_BYPOSITION 0x00000400L +#define MF_SEPARATOR 0x00000800L +#define MF_ENABLED 0x00000000L +#define MF_GRAYED 0x00000001L +#define MF_DISABLED 0x00000002L +#define MF_UNCHECKED 0x00000000L +#define MF_CHECKED 0x00000008L +#define MF_USECHECKBITMAPS 0x00000200L +#define MF_STRING 0x00000000L +#define MF_BITMAP 0x00000004L +#define MF_OWNERDRAW 0x00000100L +#define MF_POPUP 0x00000010L +#define MF_MENUBARBREAK 0x00000020L +#define MF_MENUBREAK 0x00000040L +#define MF_UNHILITE 0x00000000L +#define MF_HILITE 0x00000080L +#define MF_DEFAULT 0x00001000L +#define MF_SYSMENU 0x00002000L +#define MF_HELP 0x00004000L +#define MF_RIGHTJUSTIFY 0x00004000L +#define MF_MOUSESELECT 0x00008000L +#define MF_END 0x00000080L +#define MFT_STRING MF_STRING +#define MFT_SEPARATOR MF_SEPARATOR +#define MFT_RADIOCHECK 0x00000200L +#define MFS_GRAYED 0x00000003L +#define MFS_DISABLED MFS_GRAYED +#define MFS_CHECKED MF_CHECKED +#define MFS_ENABLED MF_ENABLED +#define MFS_DEFAULT MF_DEFAULT +#define TPM_LEFTBUTTON 0x0000L +#define TPM_RIGHTBUTTON 0x0002L +#define TPM_LEFTALIGN 0x0000L +#define TPM_CENTERALIGN 0x0004L +#define TPM_RIGHTALIGN 0x0008L +#define TPM_TOPALIGN 0x0000L +#define TPM_VCENTERALIGN 0x0010L +#define TPM_BOTTOMALIGN 0x0020L +#define TPM_NONOTIFY 0x0080L +#define TPM_RETURNCMD 0x0100L + +/* message boxes */ +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L +#define MB_CANCELTRYCONTINUE 0x00000006L +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND +#define MB_DEFBUTTON1 0x00000000L +#define MB_DEFBUTTON2 0x00000100L +#define MB_DEFBUTTON3 0x00000200L +#define MB_DEFBUTTON4 0x00000300L +#define MB_APPLMODAL 0x00000000L +#define MB_SYSTEMMODAL 0x00001000L +#define MB_TASKMODAL 0x00002000L +#define MB_HELP 0x00004000L +#define MB_NOFOCUS 0x00008000L +#define MB_SETFOREGROUND 0x00010000L +#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L +#define MB_TOPMOST 0x00040000L +#define MB_RIGHT 0x00080000L +#define MB_RTLREADING 0x00100000L +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 +#define IDCLOSE 8 +#define IDHELP 9 +#define IDTRYAGAIN 10 +#define IDCONTINUE 11 + +/* ShowWindow / SetWindowPos */ +#define SW_HIDE 0 +#define SW_SHOWNORMAL 1 +#define SW_NORMAL 1 +#define SW_SHOWMINIMIZED 2 +#define SW_SHOWMAXIMIZED 3 +#define SW_MAXIMIZE 3 +#define SW_SHOWNOACTIVATE 4 +#define SW_SHOW 5 +#define SW_MINIMIZE 6 +#define SW_SHOWMINNOACTIVE 7 +#define SW_SHOWNA 8 +#define SW_RESTORE 9 +#define SW_SHOWDEFAULT 10 +#define SW_FORCEMINIMIZE 11 +#define SWP_NOSIZE 0x0001 +#define SWP_NOMOVE 0x0002 +#define SWP_NOZORDER 0x0004 +#define SWP_NOREDRAW 0x0008 +#define SWP_NOACTIVATE 0x0010 +#define SWP_FRAMECHANGED 0x0020 +#define SWP_SHOWWINDOW 0x0040 +#define SWP_HIDEWINDOW 0x0080 +#define SWP_NOCOPYBITS 0x0100 +#define SWP_NOOWNERZORDER 0x0200 +#define SWP_NOSENDCHANGING 0x0400 +#define SWP_DRAWFRAME SWP_FRAMECHANGED +#define SWP_NOREPOSITION SWP_NOOWNERZORDER +#define SIZE_RESTORED 0 +#define SIZE_MINIMIZED 1 +#define SIZE_MAXIMIZED 2 +#define SIZE_MAXSHOW 3 +#define SIZE_MAXHIDE 4 +#define WA_INACTIVE 0 +#define WA_ACTIVE 1 +#define WA_CLICKACTIVE 2 + +#define GWL_WNDPROC (-4) +#define GWL_HINSTANCE (-6) +#define GWL_HWNDPARENT (-8) +#define GWL_STYLE (-16) +#define GWL_EXSTYLE (-20) +#define GWL_USERDATA (-21) +#define GWL_ID (-12) +#define GWLP_WNDPROC (-4) +#define GWLP_HINSTANCE (-6) +#define GWLP_HWNDPARENT (-8) +#define GWLP_USERDATA (-21) +#define GWLP_ID (-12) +#define GW_HWNDFIRST 0 +#define GW_HWNDLAST 1 +#define GW_HWNDNEXT 2 +#define GW_HWNDPREV 3 +#define GW_OWNER 4 +#define GW_CHILD 5 + +#define SC_SIZE 0xF000 +#define SC_MOVE 0xF010 +#define SC_MINIMIZE 0xF020 +#define SC_MAXIMIZE 0xF030 +#define SC_NEXTWINDOW 0xF040 +#define SC_PREVWINDOW 0xF050 +#define SC_CLOSE 0xF060 +#define SC_VSCROLL 0xF070 +#define SC_HSCROLL 0xF080 +#define SC_MOUSEMENU 0xF090 +#define SC_KEYMENU 0xF100 +#define SC_RESTORE 0xF120 +#define SC_TASKLIST 0xF130 +#define SC_CONTEXTHELP 0xF180 + +#define DLGC_WANTARROWS 0x0001 +#define DLGC_WANTTAB 0x0002 +#define DLGC_WANTALLKEYS 0x0004 +#define DLGC_WANTMESSAGE 0x0004 +#define DLGC_HASSETSEL 0x0008 +#define DLGC_DEFPUSHBUTTON 0x0010 +#define DLGC_UNDEFPUSHBUTTON 0x0020 +#define DLGC_RADIOBUTTON 0x0040 +#define DLGC_WANTCHARS 0x0080 +#define DLGC_STATIC 0x0100 +#define DLGC_BUTTON 0x2000 +#define DM_GETDEFID (WM_USER + 0) +#define DM_SETDEFID (WM_USER + 1) +#define DC_HASDEFID 0x534B + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 +#define WHEEL_DELTA 120 + +#define HTERROR (-2) +#define HTTRANSPARENT (-1) +#define HTNOWHERE 0 +#define HTCLIENT 1 +#define HTCAPTION 2 +#define HTSYSMENU 3 + +#define CTLCOLOR_MSGBOX 0 +#define CTLCOLOR_EDIT 1 +#define CTLCOLOR_LISTBOX 2 +#define CTLCOLOR_BTN 3 +#define CTLCOLOR_DLG 4 +#define CTLCOLOR_SCROLLBAR 5 +#define CTLCOLOR_STATIC 6 + +#define ODT_MENU 1 +#define ODT_LISTBOX 2 +#define ODT_COMBOBOX 3 +#define ODT_BUTTON 4 +#define ODT_STATIC 5 +#define ODA_DRAWENTIRE 0x0001 +#define ODA_SELECT 0x0002 +#define ODA_FOCUS 0x0004 +#define ODS_SELECTED 0x0001 +#define ODS_GRAYED 0x0002 +#define ODS_DISABLED 0x0004 +#define ODS_CHECKED 0x0008 +#define ODS_FOCUS 0x0010 +#define ODS_DEFAULT 0x0020 +#define ODS_HOTLIGHT 0x0040 +#define ODS_INACTIVE 0x0080 +#define ODS_NOACCEL 0x0100 +#define ODS_NOFOCUSRECT 0x0200 + +/* GDI */ +#define DT_TOP 0x00000000 +#define DT_LEFT 0x00000000 +#define DT_CENTER 0x00000001 +#define DT_RIGHT 0x00000002 +#define DT_VCENTER 0x00000004 +#define DT_BOTTOM 0x00000008 +#define DT_WORDBREAK 0x00000010 +#define DT_SINGLELINE 0x00000020 +#define DT_EXPANDTABS 0x00000040 +#define DT_TABSTOP 0x00000080 +#define DT_NOCLIP 0x00000100 +#define DT_EXTERNALLEADING 0x00000200 +#define DT_CALCRECT 0x00000400 +#define DT_NOPREFIX 0x00000800 +#define DT_INTERNAL 0x00001000 +#define DT_EDITCONTROL 0x00002000 +#define DT_PATH_ELLIPSIS 0x00004000 +#define DT_END_ELLIPSIS 0x00008000 +#define DT_MODIFYSTRING 0x00010000 +#define DT_RTLREADING 0x00020000 +#define DT_WORD_ELLIPSIS 0x00040000 +#define TA_NOUPDATECP 0 +#define TA_UPDATECP 1 +#define TA_LEFT 0 +#define TA_RIGHT 2 +#define TA_CENTER 6 +#define TA_TOP 0 +#define TA_BOTTOM 8 +#define TA_BASELINE 24 +#define TRANSPARENT 1 +#define OPAQUE 2 +#define ETO_OPAQUE 0x0002 +#define ETO_CLIPPED 0x0004 +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 +#define PS_USERSTYLE 7 +#define PS_ALTERNATE 8 +#define PS_STYLE_MASK 0x0000000F +#define PS_ENDCAP_ROUND 0x00000000 +#define PS_ENDCAP_SQUARE 0x00000100 +#define PS_ENDCAP_FLAT 0x00000200 +#define PS_JOIN_ROUND 0x00000000 +#define PS_JOIN_BEVEL 0x00001000 +#define PS_JOIN_MITER 0x00002000 +#define PS_COSMETIC 0x00000000 +#define PS_GEOMETRIC 0x00010000 +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW BS_NULL +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define HS_HORIZONTAL 0 +#define HS_VERTICAL 1 +#define HS_FDIAGONAL 2 +#define HS_BDIAGONAL 3 +#define HS_CROSS 4 +#define HS_DIAGCROSS 5 +#define WHITE_BRUSH 0 +#define LTGRAY_BRUSH 1 +#define GRAY_BRUSH 2 +#define DKGRAY_BRUSH 3 +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 +#define HOLLOW_BRUSH NULL_BRUSH +#define WHITE_PEN 6 +#define BLACK_PEN 7 +#define NULL_PEN 8 +#define OEM_FIXED_FONT 10 +#define ANSI_FIXED_FONT 11 +#define ANSI_VAR_FONT 12 +#define SYSTEM_FONT 13 +#define DEVICE_DEFAULT_FONT 14 +#define DEFAULT_PALETTE 15 +#define SYSTEM_FIXED_FONT 16 +#define DEFAULT_GUI_FONT 17 +#define DC_BRUSH 18 +#define DC_PEN 19 +#define SRCCOPY 0x00CC0020UL +#define SRCPAINT 0x00EE0086UL +#define SRCAND 0x008800C6UL +#define SRCINVERT 0x00660046UL +#define SRCERASE 0x00440328UL +#define NOTSRCCOPY 0x00330008UL +#define NOTSRCERASE 0x001100A6UL +#define MERGECOPY 0x00C000CAUL +#define MERGEPAINT 0x00BB0226UL +#define PATCOPY 0x00F00021UL +#define PATPAINT 0x00FB0A09UL +#define PATINVERT 0x005A0049UL +#define DSTINVERT 0x00550009UL +#define BLACKNESS 0x00000042UL +#define WHITENESS 0x00FF0062UL +#define R2_BLACK 1 +#define R2_NOTMERGEPEN 2 +#define R2_MASKNOTPEN 3 +#define R2_NOTCOPYPEN 4 +#define R2_MASKPENNOT 5 +#define R2_NOT 6 +#define R2_XORPEN 7 +#define R2_NOTMASKPEN 8 +#define R2_MASKPEN 9 +#define R2_NOTXORPEN 10 +#define R2_NOP 11 +#define R2_MERGENOTPEN 12 +#define R2_COPYPEN 13 +#define R2_MERGEPENNOT 14 +#define R2_MERGEPEN 15 +#define R2_WHITE 16 +#define MM_TEXT 1 +#define MM_LOMETRIC 2 +#define MM_HIMETRIC 3 +#define MM_LOENGLISH 4 +#define MM_HIENGLISH 5 +#define MM_TWIPS 6 +#define MM_ISOTROPIC 7 +#define MM_ANISOTROPIC 8 +#define ALTERNATE 1 +#define WINDING 2 +#define BLACKONWHITE 1 +#define WHITEONBLACK 2 +#define COLORONCOLOR 3 +#define HALFTONE 4 +#define STRETCH_DELETESCANS COLORONCOLOR +#define LOGPIXELSX 88 +#define LOGPIXELSY 90 +#define HORZRES 8 +#define VERTRES 10 +#define BITSPIXEL 12 +#define PLANES 14 +#define NUMCOLORS 24 +#define RASTERCAPS 38 +#define HORZSIZE 4 +#define VERTSIZE 6 +#define DIB_RGB_COLORS 0 +#define DIB_PAL_COLORS 1 +#define BI_RGB 0L +#define CLR_INVALID 0xFFFFFFFF +#define CLR_NONE 0xFFFFFFFFL +#define CLR_DEFAULT 0xFF000000L +#define BDR_RAISEDOUTER 0x0001 +#define BDR_SUNKENOUTER 0x0002 +#define BDR_RAISEDINNER 0x0004 +#define BDR_SUNKENINNER 0x0008 +#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) +#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) +#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) +#define BF_LEFT 0x0001 +#define BF_TOP 0x0002 +#define BF_RIGHT 0x0004 +#define BF_BOTTOM 0x0008 +#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) +#define BF_MIDDLE 0x0800 +#define BF_SOFT 0x1000 +#define BF_ADJUST 0x2000 +#define BF_FLAT 0x4000 +#define BF_MONO 0x8000 +#define DFC_CAPTION 1 +#define DFC_MENU 2 +#define DFC_SCROLL 3 +#define DFC_BUTTON 4 +#define DFCS_BUTTONCHECK 0x0000 +#define DFCS_BUTTONRADIO 0x0004 +#define DFCS_BUTTONPUSH 0x0010 +#define DFCS_INACTIVE 0x0100 +#define DFCS_PUSHED 0x0200 +#define DFCS_CHECKED 0x0400 +#define DFCS_FLAT 0x4000 +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_XOR 3 +#define RGN_DIFF 4 +#define RGN_COPY 5 +#define NULLREGION 1 +#define SIMPLEREGION 2 +#define COMPLEXREGION 3 +#define ERROR 0 + +#define FW_DONTCARE 0 +#define FW_THIN 100 +#define FW_EXTRALIGHT 200 +#define FW_LIGHT 300 +#define FW_NORMAL 400 +#define FW_REGULAR 400 +#define FW_MEDIUM 500 +#define FW_SEMIBOLD 600 +#define FW_DEMIBOLD 600 +#define FW_BOLD 700 +#define FW_EXTRABOLD 800 +#define FW_ULTRABOLD 800 +#define FW_HEAVY 900 +#define FW_BLACK 900 +#define ANSI_CHARSET 0 +#define DEFAULT_CHARSET 1 +#define SYMBOL_CHARSET 2 +#define SHIFTJIS_CHARSET 128 +#define GREEK_CHARSET 161 +#define TURKISH_CHARSET 162 +#define BALTIC_CHARSET 186 +#define RUSSIAN_CHARSET 204 +#define EASTEUROPE_CHARSET 238 +#define OEM_CHARSET 255 +#define OUT_DEFAULT_PRECIS 0 +#define OUT_STRING_PRECIS 1 +#define OUT_CHARACTER_PRECIS 2 +#define OUT_STROKE_PRECIS 3 +#define OUT_TT_PRECIS 4 +#define OUT_DEVICE_PRECIS 5 +#define OUT_RASTER_PRECIS 6 +#define OUT_TT_ONLY_PRECIS 7 +#define OUT_OUTLINE_PRECIS 8 +#define CLIP_DEFAULT_PRECIS 0 +#define CLIP_CHARACTER_PRECIS 1 +#define CLIP_STROKE_PRECIS 2 +#define DEFAULT_QUALITY 0 +#define DRAFT_QUALITY 1 +#define PROOF_QUALITY 2 +#define NONANTIALIASED_QUALITY 3 +#define ANTIALIASED_QUALITY 4 +#define CLEARTYPE_QUALITY 5 +#define DEFAULT_PITCH 0 +#define FIXED_PITCH 1 +#define VARIABLE_PITCH 2 +#define FF_DONTCARE (0 << 4) +#define FF_ROMAN (1 << 4) +#define FF_SWISS (2 << 4) +#define FF_MODERN (3 << 4) +#define FF_SCRIPT (4 << 4) +#define FF_DECORATIVE (5 << 4) +#define LF_FACESIZE 32 + +#define COLOR_SCROLLBAR 0 +#define COLOR_BACKGROUND 1 +#define COLOR_ACTIVECAPTION 2 +#define COLOR_INACTIVECAPTION 3 +#define COLOR_MENU 4 +#define COLOR_WINDOW 5 +#define COLOR_WINDOWFRAME 6 +#define COLOR_MENUTEXT 7 +#define COLOR_WINDOWTEXT 8 +#define COLOR_CAPTIONTEXT 9 +#define COLOR_ACTIVEBORDER 10 +#define COLOR_INACTIVEBORDER 11 +#define COLOR_APPWORKSPACE 12 +#define COLOR_HIGHLIGHT 13 +#define COLOR_HIGHLIGHTTEXT 14 +#define COLOR_BTNFACE 15 +#define COLOR_BTNSHADOW 16 +#define COLOR_GRAYTEXT 17 +#define COLOR_BTNTEXT 18 +#define COLOR_INACTIVECAPTIONTEXT 19 +#define COLOR_BTNHIGHLIGHT 20 +#define COLOR_3DDKSHADOW 21 +#define COLOR_3DLIGHT 22 +#define COLOR_INFOTEXT 23 +#define COLOR_INFOBK 24 +#define COLOR_HOTLIGHT 26 +#define COLOR_DESKTOP COLOR_BACKGROUND +#define COLOR_3DFACE COLOR_BTNFACE +#define COLOR_3DSHADOW COLOR_BTNSHADOW +#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT +#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT +#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT + +#define SM_CXSCREEN 0 +#define SM_CYSCREEN 1 +#define SM_CXVSCROLL 2 +#define SM_CYHSCROLL 3 +#define SM_CYCAPTION 4 +#define SM_CXBORDER 5 +#define SM_CYBORDER 6 +#define SM_CXDLGFRAME 7 +#define SM_CYDLGFRAME 8 +#define SM_CYVTHUMB 9 +#define SM_CXHTHUMB 10 +#define SM_CXICON 11 +#define SM_CYICON 12 +#define SM_CXCURSOR 13 +#define SM_CYCURSOR 14 +#define SM_CYMENU 15 +#define SM_CXFULLSCREEN 16 +#define SM_CYFULLSCREEN 17 +#define SM_CYVSCROLL 20 +#define SM_CXHSCROLL 21 +#define SM_CXMIN 28 +#define SM_CYMIN 29 +#define SM_CXFRAME 32 +#define SM_CYFRAME 33 +#define SM_CXFIXEDFRAME SM_CXDLGFRAME +#define SM_CYFIXEDFRAME SM_CYDLGFRAME +#define SM_CXEDGE 45 +#define SM_CYEDGE 46 +#define SM_CXSMICON 49 +#define SM_CYSMICON 50 +#define SM_CXMAXIMIZED 61 +#define SM_CYMAXIMIZED 62 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 + +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_UNICODETEXT 13 +#define CF_HDROP 15 +#define GMEM_FIXED 0x0000 +#define GMEM_MOVEABLE 0x0002 +#define GMEM_ZEROINIT 0x0040 +#define GMEM_DDESHARE 0x2000 +#define GMEM_SHARE 0x2000 +#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) +#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) +#define GMEM_NODISCARD 0x0020 +#define GMEM_MODIFY 0x0080 +#define LMEM_FIXED 0x0000 +#define LMEM_MOVEABLE 0x0002 +#define LMEM_ZEROINIT 0x0040 +#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) +#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) + +/* help */ +#define HELP_CONTEXT 0x0001L +#define HELP_QUIT 0x0002L +#define HELP_INDEX 0x0003L +#define HELP_CONTENTS 0x0003L +#define HELP_HELPONHELP 0x0004L +#define HELP_SETINDEX 0x0005L +#define HELP_CONTEXTPOPUP 0x0008L +#define HELP_FINDER 0x000bL +#define HELP_WM_HELP 0x000cL +#define HELP_CONTEXTMENU 0x000aL +#define HELP_KEY 0x0101L +#define HELP_PARTIALKEY 0x0105L +#define HELPINFO_WINDOW 0x0001 +#define HELPINFO_MENUITEM 0x0002 +#define HH_DISPLAY_TOPIC 0x0000 +#define HH_HELP_FINDER 0x0000 +#define HH_DISPLAY_TOC 0x0001 +#define HH_DISPLAY_INDEX 0x0002 +#define HH_DISPLAY_SEARCH 0x0003 +#define HH_KEYWORD_LOOKUP 0x000D +#define HH_DISPLAY_TEXT_POPUP 0x000E +#define HH_HELP_CONTEXT 0x000F +#define HH_TP_HELP_CONTEXTMENU 0x0010 +#define HH_TP_HELP_WM_HELP 0x0011 +#define HH_CLOSE_ALL 0x0012 +#define HH_ALINK_LOOKUP 0x0013 +#define HH_INITIALIZE 0x001C +#define HH_UNINITIALIZE 0x001D + +/* cursor / icon ids (MAKEINTRESOURCE values) */ +#define IDC_ARROW_ID 32512 +#define IDC_IBEAM_ID 32513 +#define IDC_WAIT_ID 32514 +#define IDC_CROSS_ID 32515 +#define IDC_UPARROW_ID 32516 +#define IDC_SIZE_ID 32640 +#define IDC_ICON_ID 32641 +#define IDC_SIZENWSE_ID 32642 +#define IDC_SIZENESW_ID 32643 +#define IDC_SIZEWE_ID 32644 +#define IDC_SIZENS_ID 32645 +#define IDC_SIZEALL_ID 32646 +#define IDC_NO_ID 32648 +#define IDC_HAND_ID 32649 +#define IDC_APPSTARTING_ID 32650 +#define IDC_HELP_ID 32651 +#define IDI_APPLICATION_ID 32512 +#define IDI_HAND_ID 32513 +#define IDI_QUESTION_ID 32514 +#define IDI_EXCLAMATION_ID 32515 +#define IDI_ASTERISK_ID 32516 +#define IDI_WINLOGO_ID 32517 + +/* file API */ +#define GENERIC_READ 0x80000000L +#define GENERIC_WRITE 0x40000000L +#define GENERIC_EXECUTE 0x20000000L +#define GENERIC_ALL 0x10000000L +#define FILE_READ_DATA 0x0001 +#define FILE_WRITE_DATA 0x0002 +#define FILE_APPEND_DATA 0x0004 +#define FILE_READ_ATTRIBUTES 0x0080 +#define FILE_WRITE_ATTRIBUTES 0x0100 +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 +#define INVALID_FILE_SIZE 0xFFFFFFFF +#define INVALID_SET_FILE_POINTER 0xFFFFFFFF + +/* errors */ +#define NO_ERROR 0L +#define ERROR_SUCCESS 0L +#define ERROR_INVALID_FUNCTION 1L +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_PATH_NOT_FOUND 3L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_INVALID_HANDLE 6L +#define ERROR_NOT_ENOUGH_MEMORY 8L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_MORE_DATA 234L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_CANCELLED 1223L + +/* threads and sync */ +#define WAIT_OBJECT_0 0x00000000L +#define WAIT_ABANDONED 0x00000080L +#define WAIT_TIMEOUT 258L +#define WAIT_FAILED 0xFFFFFFFF +#define STILL_ACTIVE 0x00000103L +#define THREAD_PRIORITY_LOWEST (-2) +#define THREAD_PRIORITY_BELOW_NORMAL (-1) +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_HIGHEST 2 +#define THREAD_PRIORITY_ABOVE_NORMAL 1 +#define THREAD_PRIORITY_IDLE (-15) +#define THREAD_PRIORITY_TIME_CRITICAL 15 +#define CREATE_SUSPENDED 0x00000004 +#define CREATE_NO_WINDOW 0x08000000 +#define CREATE_NEW_CONSOLE 0x00000010 +#define NORMAL_PRIORITY_CLASS 0x00000020 +#define STARTF_USESHOWWINDOW 0x00000001 +#define STARTF_USESTDHANDLES 0x00000100 + +/* registry */ +#define KEY_QUERY_VALUE 0x0001 +#define KEY_SET_VALUE 0x0002 +#define KEY_CREATE_SUB_KEY 0x0004 +#define KEY_ENUMERATE_SUB_KEYS 0x0008 +#define KEY_NOTIFY 0x0010 +#define KEY_READ 0x20019 +#define KEY_WRITE 0x20006 +#define KEY_ALL_ACCESS 0xF003F +#define REG_NONE 0 +#define REG_SZ 1 +#define REG_EXPAND_SZ 2 +#define REG_BINARY 3 +#define REG_DWORD 4 +#define REG_OPTION_NON_VOLATILE 0x00000000L +#define REG_CREATED_NEW_KEY 0x00000001L +#define REG_OPENED_EXISTING_KEY 0x00000002L + +/* code pages / locale */ +#define CP_ACP 0 +#define CP_OEMCP 1 +#define CP_UTF8 65001 +#define LANG_NEUTRAL 0x00 +#define LANG_ENGLISH 0x09 +#define LANG_GERMAN 0x07 +#define LANG_FRENCH 0x0c +#define LANG_SPANISH 0x0a +#define LANG_POLISH 0x15 +#define LANG_GREEK 0x08 +#define LANG_SERBIAN 0x1a +#define SUBLANG_NEUTRAL 0x00 +#define SUBLANG_DEFAULT 0x01 +#define SUBLANG_SYS_DEFAULT 0x02 +#define SUBLANG_ENGLISH_US 0x01 +#define SUBLANG_ENGLISH_UK 0x02 +#define SUBLANG_GERMAN 0x01 +#define SUBLANG_GERMAN_SWISS 0x02 +#define SUBLANG_FRENCH 0x01 +#define SUBLANG_SPANISH 0x01 +#define SUBLANG_SPANISH_MODERN 0x03 +#define SUBLANG_SERBIAN_LATIN 0x02 +#define LOCALE_USER_DEFAULT 0x0400 +#define LOCALE_SYSTEM_DEFAULT 0x0800 +#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 +#define FORMAT_MESSAGE_FROM_STRING 0x00000400 +#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 +#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 + +/* misc */ +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 +#define PM_NOYIELD 0x0002 +#define QS_ALLINPUT 0x04FF +#define MWMO_INPUTAVAILABLE 0x0004 +#define MB_PRECOMPOSED 0x00000001 +#define WC_COMPOSITECHECK 0x00000200 +#define SPI_GETWORKAREA 0x0030 +#define SPI_GETNONCLIENTMETRICS 0x0029 +#define CW_USEDEFAULT ((int)0x80000000) +#define USER_TIMER_MINIMUM 0x0000000A +#define SEM_FAILCRITICALERRORS 0x0001 +#define SEM_NOOPENFILEERRORBOX 0x8000 diff --git a/port/mfcwx/include/mfcwx/wintypes.h b/port/mfcwx/include/mfcwx/wintypes.h new file mode 100644 index 000000000..7d7d28cf1 --- /dev/null +++ b/port/mfcwx/include/mfcwx/wintypes.h @@ -0,0 +1,643 @@ +#pragma once + +/* Win32 base types. C compatible. 32-bit widths follow the Windows LLP64 model. */ + +#include +#include +#include + +#ifndef _MFCWX_WINTYPES +#define _MFCWX_WINTYPES + +#define WINAPI +#define WINAPIV +#define APIENTRY +#define CALLBACK +#define PASCAL +#define _pascal +#define __pascal +#define FAR +#define NEAR +#define far +#define near +#define _far +#define _near +#define __far +#define __near +#define __stdcall +#define _stdcall +#define __cdecl +#define _cdecl +#define __fastcall +#define _fastcall +#define __declspec(x) +#define __forceinline inline +#define _inline inline +#define __inline inline +#define __w64 +#define __int8 char +#define __int16 short +#define __int32 int +#define __int64 long long +#define CONST const +#define VOID void +#define IN +#define OUT +#define OPTIONAL +#define UNALIGNED +#define AFXAPI +#define AFX_CDECL +#define AFX_STATIC static +#define AFX_STATIC_DATA static +#define AFX_INLINE inline +#define AFX_EXT_CLASS +#define AFX_EXT_API +#define AFX_EXT_DATA +#define AFX_CORE_DATA +#define AFX_DATA +#define AFX_DATADEF +#define AFX_COMDAT +#define AFX_NOVTABLE +#define AFX_IMPORT_DATA +#define AFX_API_EXPORT +#define DECLSPEC_NOVTABLE +#define DECLSPEC_IMPORT +#define DECLSPEC_EXPORT + +typedef int BOOL; +typedef unsigned char BOOLEAN; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned short WORD; +typedef uint32_t DWORD; +typedef unsigned int UINT; +typedef int INT; +typedef int32_t LONG; +typedef uint32_t ULONG; +typedef short SHORT; +typedef unsigned short USHORT; +typedef char CHAR; +typedef unsigned char UCHAR; +typedef char CCHAR; +typedef float FLOAT; +typedef double DOUBLE; +typedef long long LONGLONG; +typedef unsigned long long ULONGLONG; +typedef long long INT64; +typedef unsigned long long UINT64; +typedef int32_t INT32; +typedef uint32_t UINT32; +typedef int16_t INT16; +typedef uint16_t UINT16; +typedef int8_t INT8; +typedef uint8_t UINT8; +typedef uint32_t DWORD32; +typedef uint64_t DWORD64; +typedef uint64_t QWORD; +typedef intptr_t INT_PTR; +typedef uintptr_t UINT_PTR; +typedef intptr_t LONG_PTR; +typedef uintptr_t ULONG_PTR; +typedef uintptr_t DWORD_PTR; +typedef size_t SIZE_T; +typedef ptrdiff_t SSIZE_T; +typedef uintptr_t WPARAM; +typedef intptr_t LPARAM; +typedef intptr_t LRESULT; +typedef WORD ATOM; +typedef DWORD COLORREF; +typedef DWORD LCID; +typedef WORD LANGID; +typedef long HRESULT; +typedef DWORD ACCESS_MASK; + +typedef char TCHAR; +typedef unsigned char _TUCHAR; +typedef char _TCHAR; +typedef char _TSCHAR; +typedef wchar_t WCHAR; +typedef char* LPSTR; +typedef char* PSTR; +typedef char* NPSTR; +typedef const char* LPCSTR; +typedef const char* PCSTR; +typedef char* LPTSTR; +typedef char* PTSTR; +typedef const char* LPCTSTR; +typedef const char* PCTSTR; +typedef wchar_t* LPWSTR; +typedef wchar_t* PWSTR; +typedef const wchar_t* LPCWSTR; +typedef const wchar_t* PCWSTR; +typedef wchar_t OLECHAR; +typedef wchar_t* LPOLESTR; +typedef const wchar_t* LPCOLESTR; +typedef wchar_t* BSTR; +typedef unsigned char* LPBYTE; +typedef unsigned char* PBYTE; +typedef BOOL* LPBOOL; +typedef BOOL* PBOOL; +typedef WORD* LPWORD; +typedef WORD* PWORD; +typedef DWORD* LPDWORD; +typedef DWORD* PDWORD; +typedef LONG* LPLONG; +typedef LONG* PLONG; +typedef int* LPINT; +typedef int* PINT; +typedef UINT* LPUINT; +typedef UINT* PUINT; +typedef void* LPVOID; +typedef void* PVOID; +typedef const void* LPCVOID; +typedef COLORREF* LPCOLORREF; + +#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__* name +typedef void* HANDLE; +typedef HANDLE* PHANDLE; +typedef HANDLE* LPHANDLE; +DECLARE_HANDLE(HWND); +DECLARE_HANDLE(HINSTANCE); +DECLARE_HANDLE(HDC); +DECLARE_HANDLE(HGDIOBJ); +DECLARE_HANDLE(HMENU); +DECLARE_HANDLE(HACCEL); +DECLARE_HANDLE(HICON); +DECLARE_HANDLE(HKEY); +DECLARE_HANDLE(HTREEITEM); +DECLARE_HANDLE(HIMAGELIST); +DECLARE_HANDLE(HDROP); +DECLARE_HANDLE(HGLRC); +DECLARE_HANDLE(HDESK); +DECLARE_HANDLE(HHOOK); +DECLARE_HANDLE(HMONITOR); +DECLARE_HANDLE(HENHMETAFILE); +DECLARE_HANDLE(HMETAFILE); +DECLARE_HANDLE(HRSRC); +DECLARE_HANDLE(HTASK); +typedef HINSTANCE HMODULE; +typedef HICON HCURSOR; +typedef HGDIOBJ HBITMAP; +typedef HGDIOBJ HBRUSH; +typedef HGDIOBJ HPEN; +typedef HGDIOBJ HFONT; +typedef HGDIOBJ HRGN; +typedef HGDIOBJ HPALETTE; +typedef HANDLE HGLOBAL; +typedef HANDLE HLOCAL; +typedef HANDLE GLOBALHANDLE; +typedef HANDLE LOCALHANDLE; +typedef int HFILE; +typedef HKEY* PHKEY; +typedef LONG LSTATUS; +typedef DWORD REGSAM; + +#define INVALID_HANDLE_VALUE ((HANDLE)(intptr_t)-1) +#define HFILE_ERROR ((HFILE)-1) +#define HKEY_CLASSES_ROOT ((HKEY)(uintptr_t)0x80000000) +#define HKEY_CURRENT_USER ((HKEY)(uintptr_t)0x80000001) +#define HKEY_LOCAL_MACHINE ((HKEY)(uintptr_t)0x80000002) +#define HKEY_USERS ((HKEY)(uintptr_t)0x80000003) +#define HWND_TOP ((HWND)0) +#define HWND_BOTTOM ((HWND)1) +#define HWND_TOPMOST ((HWND)(intptr_t)-1) +#define HWND_NOTOPMOST ((HWND)(intptr_t)-2) +#define HWND_DESKTOP ((HWND)0) + +typedef LRESULT (*WNDPROC)(HWND, UINT, WPARAM, LPARAM); +typedef INT_PTR (*DLGPROC)(HWND, UINT, WPARAM, LPARAM); +typedef void (*TIMERPROC)(HWND, UINT, UINT_PTR, DWORD); +typedef INT_PTR (*FARPROC)(void); +typedef INT_PTR (*PROC)(void); +typedef DWORD (*LPTHREAD_START_ROUTINE)(LPVOID); + +typedef struct tagRECT { LONG left, top, right, bottom; } RECT, *PRECT, *LPRECT, *NPRECT; +typedef const RECT* LPCRECT; +typedef struct tagPOINT { LONG x, y; } POINT, *PPOINT, *LPPOINT, *NPPOINT; +typedef struct tagSIZE { LONG cx, cy; } SIZE, *PSIZE, *LPSIZE, SIZEL, *PSIZEL, *LPSIZEL; +typedef struct tagPOINTS { SHORT x, y; } POINTS, *PPOINTS, *LPPOINTS; + +typedef struct tagMSG { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; +} MSG, *PMSG, *LPMSG; + +typedef struct _FILETIME { DWORD dwLowDateTime, dwHighDateTime; } FILETIME, *PFILETIME, *LPFILETIME; +typedef struct _SYSTEMTIME { + WORD wYear, wMonth, wDayOfWeek, wDay, wHour, wMinute, wSecond, wMilliseconds; +} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; + +typedef union _LARGE_INTEGER { + struct { DWORD LowPart; LONG HighPart; } u; + struct { DWORD LowPart; LONG HighPart; }; + LONGLONG QuadPart; +} LARGE_INTEGER, *PLARGE_INTEGER; +typedef union _ULARGE_INTEGER { + struct { DWORD LowPart; DWORD HighPart; } u; + struct { DWORD LowPart; DWORD HighPart; }; + ULONGLONG QuadPart; +} ULARGE_INTEGER, *PULARGE_INTEGER; + +typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + BOOL bInheritHandle; +} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + +typedef struct _OVERLAPPED { + ULONG_PTR Internal, InternalHigh; + DWORD Offset, OffsetHigh; + HANDLE hEvent; +} OVERLAPPED, *LPOVERLAPPED; + +typedef struct _WIN32_FIND_DATAA { + DWORD dwFileAttributes; + FILETIME ftCreationTime, ftLastAccessTime, ftLastWriteTime; + DWORD nFileSizeHigh, nFileSizeLow; + DWORD dwReserved0, dwReserved1; + CHAR cFileName[260]; + CHAR cAlternateFileName[14]; +} WIN32_FIND_DATAA, WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA; + +typedef struct _STARTUPINFOA { + DWORD cb; + LPSTR lpReserved, lpDesktop, lpTitle; + DWORD dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags; + WORD wShowWindow, cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput, hStdOutput, hStdError; +} STARTUPINFOA, STARTUPINFO, *LPSTARTUPINFO; + +typedef struct _PROCESS_INFORMATION { + HANDLE hProcess, hThread; + DWORD dwProcessId, dwThreadId; +} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; + +typedef struct tagLOGFONTA { + LONG lfHeight, lfWidth, lfEscapement, lfOrientation, lfWeight; + BYTE lfItalic, lfUnderline, lfStrikeOut, lfCharSet, lfOutPrecision, lfClipPrecision, lfQuality, lfPitchAndFamily; + CHAR lfFaceName[32]; +} LOGFONTA, LOGFONT, *PLOGFONT, *LPLOGFONT; + +typedef struct tagTEXTMETRICA { + LONG tmHeight, tmAscent, tmDescent, tmInternalLeading, tmExternalLeading, tmAveCharWidth, tmMaxCharWidth, + tmWeight, tmOverhang, tmDigitizedAspectX, tmDigitizedAspectY; + BYTE tmFirstChar, tmLastChar, tmDefaultChar, tmBreakChar, tmItalic, tmUnderlined, tmStruckOut, tmPitchAndFamily, + tmCharSet; +} TEXTMETRICA, TEXTMETRIC, *PTEXTMETRIC, *LPTEXTMETRIC; + +typedef struct tagLOGPEN { UINT lopnStyle; POINT lopnWidth; COLORREF lopnColor; } LOGPEN, *PLOGPEN, *LPLOGPEN; +typedef struct tagLOGBRUSH { UINT lbStyle; COLORREF lbColor; ULONG_PTR lbHatch; } LOGBRUSH, *PLOGBRUSH, *LPLOGBRUSH; + +typedef struct tagBITMAP { + LONG bmType, bmWidth, bmHeight, bmWidthBytes; + WORD bmPlanes, bmBitsPixel; + LPVOID bmBits; +} BITMAP, *PBITMAP, *LPBITMAP; + +#pragma pack(push, 2) +typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1, bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; +#pragma pack(pop) + +typedef struct tagBITMAPINFOHEADER { + DWORD biSize; + LONG biWidth, biHeight; + WORD biPlanes, biBitCount; + DWORD biCompression, biSizeImage; + LONG biXPelsPerMeter, biYPelsPerMeter; + DWORD biClrUsed, biClrImportant; +} BITMAPINFOHEADER, *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; +typedef struct tagRGBQUAD { BYTE rgbBlue, rgbGreen, rgbRed, rgbReserved; } RGBQUAD, *LPRGBQUAD; +typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO; + +typedef struct tagPAINTSTRUCT { + HDC hdc; + BOOL fErase; + RECT rcPaint; + BOOL fRestore, fIncUpdate; + BYTE rgbReserved[32]; +} PAINTSTRUCT, *PPAINTSTRUCT, *LPPAINTSTRUCT; + +typedef struct tagDRAWITEMSTRUCT { + UINT CtlType, CtlID, itemID, itemAction, itemState; + HWND hwndItem; + HDC hDC; + RECT rcItem; + ULONG_PTR itemData; +} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT; + +typedef struct tagMEASUREITEMSTRUCT { + UINT CtlType, CtlID, itemID, itemWidth, itemHeight; + ULONG_PTR itemData; +} MEASUREITEMSTRUCT, *PMEASUREITEMSTRUCT, *LPMEASUREITEMSTRUCT; + +typedef struct tagCOMPAREITEMSTRUCT { + UINT CtlType, CtlID; + HWND hwndItem; + UINT itemID1; + ULONG_PTR itemData1; + UINT itemID2; + ULONG_PTR itemData2; + DWORD dwLocaleId; +} COMPAREITEMSTRUCT, *LPCOMPAREITEMSTRUCT; + +typedef struct tagDELETEITEMSTRUCT { + UINT CtlType, CtlID, itemID; + HWND hwndItem; + ULONG_PTR itemData; +} DELETEITEMSTRUCT, *LPDELETEITEMSTRUCT; + +typedef struct tagNMHDR { HWND hwndFrom; UINT_PTR idFrom; UINT code; } NMHDR, *LPNMHDR; +typedef struct _HD_ITEMA { + UINT mask; + int cxy; + LPSTR pszText; + HBITMAP hbm; + int cchTextMax, fmt; + LPARAM lParam; + int iImage, iOrder; +} HDITEM, HD_ITEM, *LPHDITEM; +typedef struct tagNMHEADERA { NMHDR hdr; int iItem; int iButton; HDITEM* pitem; } NMHEADER, HD_NOTIFY, *LPNMHEADER; + +typedef struct tagHELPINFO { + UINT cbSize; + int iContextType; + int iCtrlId; + HANDLE hItemHandle; + DWORD_PTR dwContextId; + POINT MousePos; +} HELPINFO, *LPHELPINFO; + +typedef struct tagMINMAXINFO { + POINT ptReserved, ptMaxSize, ptMaxPosition, ptMinTrackSize, ptMaxTrackSize; +} MINMAXINFO, *PMINMAXINFO, *LPMINMAXINFO; + +typedef struct tagCREATESTRUCTA { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy, cx, y, x; + LONG style; + LPCSTR lpszName, lpszClass; + DWORD dwExStyle; +} CREATESTRUCTA, CREATESTRUCT, *LPCREATESTRUCT; + +typedef struct tagWINDOWPLACEMENT { + UINT length, flags, showCmd; + POINT ptMinPosition, ptMaxPosition; + RECT rcNormalPosition; +} WINDOWPLACEMENT, *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; + +typedef struct tagWINDOWPOS { + HWND hwnd, hwndInsertAfter; + int x, y, cx, cy; + UINT flags; +} WINDOWPOS, *LPWINDOWPOS, *PWINDOWPOS; + +typedef struct tagSCROLLINFO { + UINT cbSize, fMask; + int nMin, nMax; + UINT nPage; + int nPos, nTrackPos; +} SCROLLINFO, *LPSCROLLINFO; +typedef const SCROLLINFO* LPCSCROLLINFO; + +typedef struct tagACCEL { BYTE fVirt; WORD key; WORD cmd; } ACCEL, *LPACCEL; + +typedef struct tagWNDCLASSA { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra, cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName, lpszClassName; +} WNDCLASSA, WNDCLASS, *LPWNDCLASS; + +typedef struct tagNMUPDOWN { NMHDR hdr; int iPos; int iDelta; } NMUPDOWN, *LPNMUPDOWN, NM_UPDOWN; + +typedef struct tagLVITEMA { + UINT mask; + int iItem, iSubItem; + UINT state, stateMask; + LPSTR pszText; + int cchTextMax, iImage; + LPARAM lParam; + int iIndent; +} LVITEMA, LVITEM, LV_ITEM, *LPLVITEM; + +typedef struct tagLVCOLUMNA { + UINT mask; + int fmt, cx; + LPSTR pszText; + int cchTextMax, iSubItem, iImage, iOrder; +} LVCOLUMNA, LVCOLUMN, LV_COLUMN, *LPLVCOLUMN; + +typedef struct tagNMLISTVIEW { + NMHDR hdr; + int iItem, iSubItem; + UINT uNewState, uOldState, uChanged; + POINT ptAction; + LPARAM lParam; +} NMLISTVIEW, NM_LISTVIEW, *LPNMLISTVIEW; + +typedef struct tagNMITEMACTIVATE { + NMHDR hdr; + int iItem, iSubItem; + UINT uNewState, uOldState, uChanged; + POINT ptAction; + LPARAM lParam; + UINT uKeyFlags; +} NMITEMACTIVATE, *LPNMITEMACTIVATE; + +typedef struct tagLVDISPINFO { NMHDR hdr; LVITEMA item; } NMLVDISPINFO, LV_DISPINFO, *LPNMLVDISPINFO; +typedef struct tagLVKEYDOWN { NMHDR hdr; WORD wVKey; UINT flags; } NMLVKEYDOWN, LV_KEYDOWN, *LPNMLVKEYDOWN; +typedef struct tagLVHITTESTINFO { POINT pt; UINT flags; int iItem, iSubItem, iGroup; } LVHITTESTINFO, *LPLVHITTESTINFO; +typedef struct tagLVFINDINFOA { UINT flags; LPCSTR psz; LPARAM lParam; POINT pt; UINT vkDirection; } LVFINDINFO, *LPFINDINFO; + +typedef struct tagTVITEMA { + UINT mask; + HTREEITEM hItem; + UINT state, stateMask; + LPSTR pszText; + int cchTextMax, iImage, iSelectedImage, cChildren; + LPARAM lParam; +} TVITEMA, TVITEM, TV_ITEM, *LPTVITEM; +typedef struct tagTVINSERTSTRUCTA { HTREEITEM hParent, hInsertAfter; TVITEMA item; } TVINSERTSTRUCT, *LPTVINSERTSTRUCT; +typedef struct tagNMTREEVIEWA { + NMHDR hdr; + UINT action; + TVITEMA itemOld, itemNew; + POINT ptDrag; +} NMTREEVIEW, NM_TREEVIEW, *LPNMTREEVIEW; + +typedef struct tagTCITEMA { + UINT mask; + DWORD dwState, dwStateMask; + LPSTR pszText; + int cchTextMax, iImage; + LPARAM lParam; +} TCITEMA, TCITEM, TC_ITEM, *LPTCITEM; + +typedef struct tagTOOLINFOA { + UINT cbSize, uFlags; + HWND hwnd; + UINT_PTR uId; + RECT rect; + HINSTANCE hinst; + LPSTR lpszText; + LPARAM lParam; +} TOOLINFOA, TOOLINFO, *LPTOOLINFO; + +typedef struct tagNMTTDISPINFOA { + NMHDR hdr; + LPSTR lpszText; + char szText[80]; + HINSTANCE hinst; + UINT uFlags; + LPARAM lParam; +} NMTTDISPINFO, TOOLTIPTEXT, TOOLTIPTEXTA, *LPNMTTDISPINFO, *LPTOOLTIPTEXT; + +typedef struct _charrange { LONG cpMin, cpMax; } CHARRANGE; +typedef struct _textrange { CHARRANGE chrg; LPSTR lpstrText; } TEXTRANGE; +typedef struct _findtextexa { CHARRANGE chrg; LPCSTR lpstrText; CHARRANGE chrgText; } FINDTEXTEX; +typedef struct _findtext { CHARRANGE chrg; LPCSTR lpstrText; } FINDTEXT; +typedef DWORD (*EDITSTREAMCALLBACK)(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG* pcb); +typedef struct _editstream { DWORD_PTR dwCookie; DWORD dwError; EDITSTREAMCALLBACK pfnCallback; } EDITSTREAM; +typedef struct _charformat { + UINT cbSize; + DWORD dwMask, dwEffects; + LONG yHeight, yOffset; + COLORREF crTextColor; + BYTE bCharSet, bPitchAndFamily; + char szFaceName[32]; +} CHARFORMAT, CHARFORMATA; +typedef struct _charformat2 { + UINT cbSize; + DWORD dwMask, dwEffects; + LONG yHeight, yOffset; + COLORREF crTextColor; + BYTE bCharSet, bPitchAndFamily; + char szFaceName[32]; + WORD wWeight; + SHORT sSpacing; + COLORREF crBackColor; + LCID lcid; + DWORD dwReserved; + SHORT sStyle; + WORD wKerning; + BYTE bUnderlineType, bAnimation, bRevAuthor, bReserved1; +} CHARFORMAT2, CHARFORMAT2A; +typedef struct _paraformat { + UINT cbSize; + DWORD dwMask; + WORD wNumbering, wReserved; + LONG dxStartIndent, dxRightIndent, dxOffset; + WORD wAlignment; + SHORT cTabCount; + LONG rgxTabs[32]; +} PARAFORMAT; +typedef struct _msgfilter { NMHDR nmhdr; UINT msg; WPARAM wParam; LPARAM lParam; } MSGFILTER; +typedef struct _selchange { NMHDR nmhdr; CHARRANGE chrg; WORD seltyp; } SELCHANGE; +typedef struct _enlink { NMHDR nmhdr; UINT msg; WPARAM wParam; LPARAM lParam; CHARRANGE chrg; } ENLINK; + +typedef struct tagOFNA { + DWORD lStructSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpstrFilter; + LPSTR lpstrCustomFilter; + DWORD nMaxCustFilter, nFilterIndex; + LPSTR lpstrFile; + DWORD nMaxFile; + LPSTR lpstrFileTitle; + DWORD nMaxFileTitle; + LPCSTR lpstrInitialDir, lpstrTitle; + DWORD Flags; + WORD nFileOffset, nFileExtension; + LPCSTR lpstrDefExt; + LPARAM lCustData; + LPVOID lpfnHook; + LPCSTR lpTemplateName; +} OPENFILENAMEA, OPENFILENAME, *LPOPENFILENAME; + +#define OFN_READONLY 0x00000001 +#define OFN_OVERWRITEPROMPT 0x00000002 +#define OFN_HIDEREADONLY 0x00000004 +#define OFN_NOCHANGEDIR 0x00000008 +#define OFN_SHOWHELP 0x00000010 +#define OFN_ENABLEHOOK 0x00000020 +#define OFN_ENABLETEMPLATE 0x00000040 +#define OFN_NOVALIDATE 0x00000100 +#define OFN_ALLOWMULTISELECT 0x00000200 +#define OFN_EXTENSIONDIFFERENT 0x00000400 +#define OFN_PATHMUSTEXIST 0x00000800 +#define OFN_FILEMUSTEXIST 0x00001000 +#define OFN_CREATEPROMPT 0x00002000 +#define OFN_SHAREAWARE 0x00004000 +#define OFN_NOREADONLYRETURN 0x00008000 +#define OFN_NOTESTFILECREATE 0x00010000 +#define OFN_EXPLORER 0x00080000 +#define OFN_NODEREFERENCELINKS 0x00100000 +#define OFN_LONGNAMES 0x00200000 +#define OFN_ENABLESIZING 0x00800000 + +typedef struct tagCHOOSECOLORA { + DWORD lStructSize; + HWND hwndOwner; + HWND hInstance; + COLORREF rgbResult; + COLORREF* lpCustColors; + DWORD Flags; + LPARAM lCustData; + LPVOID lpfnHook; + LPCSTR lpTemplateName; +} CHOOSECOLOR, *LPCHOOSECOLOR; +#define CC_RGBINIT 0x00000001 +#define CC_FULLOPEN 0x00000002 + +typedef struct tagNONCLIENTMETRICSA { + UINT cbSize; + int iBorderWidth, iScrollWidth, iScrollHeight, iCaptionWidth, iCaptionHeight; + LOGFONTA lfCaptionFont; + int iSmCaptionWidth, iSmCaptionHeight; + LOGFONTA lfSmCaptionFont; + int iMenuWidth, iMenuHeight; + LOGFONTA lfMenuFont, lfStatusFont, lfMessageFont; +} NONCLIENTMETRICS; + +typedef struct _MEMORYSTATUS { + DWORD dwLength, dwMemoryLoad; + SIZE_T dwTotalPhys, dwAvailPhys, dwTotalPageFile, dwAvailPageFile, dwTotalVirtual, dwAvailVirtual; +} MEMORYSTATUS, *LPMEMORYSTATUS; + +typedef struct _SYSTEM_INFO { + WORD wProcessorArchitecture, wReserved; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress, lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors, dwProcessorType, dwAllocationGranularity; + WORD wProcessorLevel, wProcessorRevision; +} SYSTEM_INFO, *LPSYSTEM_INFO; + +typedef struct _OSVERSIONINFOA { + DWORD dwOSVersionInfoSize, dwMajorVersion, dwMinorVersion, dwBuildNumber, dwPlatformId; + CHAR szCSDVersion[128]; +} OSVERSIONINFO, OSVERSIONINFOA, *LPOSVERSIONINFO; + +typedef struct _CRITICAL_SECTION { void* impl; } CRITICAL_SECTION, *LPCRITICAL_SECTION; + +typedef struct _GUID { DWORD Data1; WORD Data2, Data3; BYTE Data4[8]; } GUID, IID, CLSID; + +#endif /* _MFCWX_WINTYPES */ diff --git a/port/mfcwx/include/mmsystem.h b/port/mfcwx/include/mmsystem.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/mmsystem.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/objbase.h b/port/mfcwx/include/objbase.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/objbase.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/ole2.h b/port/mfcwx/include/ole2.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/ole2.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/process.h b/port/mfcwx/include/process.h new file mode 100644 index 000000000..dd01f07f1 --- /dev/null +++ b/port/mfcwx/include/process.h @@ -0,0 +1,9 @@ +#pragma once +#include "mfcwx/crtcompat.h" + +#define _P_WAIT 0 +#define _P_NOWAIT 1 +#define _P_OVERLAY 2 +#define _P_NOWAITO 3 +#define _P_DETACH 4 +intptr_t _spawnl(int mode, const char* cmdname, const char* arg0, ...); diff --git a/port/mfcwx/include/richedit.h b/port/mfcwx/include/richedit.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/richedit.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/share.h b/port/mfcwx/include/share.h new file mode 100644 index 000000000..fbffeb452 --- /dev/null +++ b/port/mfcwx/include/share.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/crtcompat.h" diff --git a/port/mfcwx/include/shellapi.h b/port/mfcwx/include/shellapi.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/shellapi.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/shlobj.h b/port/mfcwx/include/shlobj.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/shlobj.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/shlwapi.h b/port/mfcwx/include/shlwapi.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/shlwapi.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/tchar.h b/port/mfcwx/include/tchar.h new file mode 100644 index 000000000..deb747432 --- /dev/null +++ b/port/mfcwx/include/tchar.h @@ -0,0 +1,2 @@ +#pragma once +#include "mfcwx/win32.h" diff --git a/port/mfcwx/include/winbase.h b/port/mfcwx/include/winbase.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/winbase.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/wincrypt.h b/port/mfcwx/include/wincrypt.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/wincrypt.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/windef.h b/port/mfcwx/include/windef.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/windef.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/windows.h b/port/mfcwx/include/windows.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/windows.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/wingdi.h b/port/mfcwx/include/wingdi.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/wingdi.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/winnt.h b/port/mfcwx/include/winnt.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/winnt.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/winreg.h b/port/mfcwx/include/winreg.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/winreg.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/winsock.h b/port/mfcwx/include/winsock.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/winsock.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/winsvc.h b/port/mfcwx/include/winsvc.h new file mode 100644 index 000000000..38b8341c6 --- /dev/null +++ b/port/mfcwx/include/winsvc.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afxwin.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/include/winuser.h b/port/mfcwx/include/winuser.h new file mode 100644 index 000000000..17bdd6cc2 --- /dev/null +++ b/port/mfcwx/include/winuser.h @@ -0,0 +1,6 @@ +#pragma once +#ifdef __cplusplus +#include "afx.h" +#else +#include "mfcwx/win32.h" +#endif diff --git a/port/mfcwx/src/afxcore.cpp b/port/mfcwx/src/afxcore.cpp new file mode 100644 index 000000000..80f86ced7 --- /dev/null +++ b/port/mfcwx/src/afxcore.cpp @@ -0,0 +1,669 @@ +#include "afxwin.h" +#include "afxole.h" +#include "runtime.h" + +#include +#include + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// Runtime classes + +namespace { + +CRuntimeClass* g_firstClass = nullptr; + +long long DaysFromCivil(long long y, unsigned m, unsigned d) { + y -= m <= 2; + const long long era = (y >= 0 ? y : y - 399) / 400; + const unsigned yoe = static_cast(y - era * 400); + const unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; + const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; + return era * 146097 + static_cast(doe) - 719468; +} + +void CivilFromDays(long long z, int& y, int& m, int& d) { + z += 719468; + const long long era = (z >= 0 ? z : z - 146096) / 146097; + const unsigned doe = static_cast(z - era * 146097); + const unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; + const long long yy = static_cast(yoe) + era * 400; + const unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); + const unsigned mp = (5 * doy + 2) / 153; + d = static_cast(doy - (153 * mp + 2) / 5 + 1); + m = static_cast(mp < 10 ? mp + 3 : mp - 9); + y = static_cast(yy + (m <= 2)); +} + +const long long kOleEpochDays = DaysFromCivil(1899, 12, 30); + +bool IsLeap(int y) { return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; } + +int DaysInMonth(int y, int m) { + static const int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + return m == 2 && IsLeap(y) ? 29 : days[m - 1]; +} + +std::string LocalizedPiece(const char* buf, size_t n) { + std::string piece(buf, n); + for (unsigned char c : piece) + if (c >= 0x80) { + std::string ansi = Utf8ToAnsi(piece.c_str()); + return ansi.empty() ? piece : ansi; + } + return piece; +} + +std::string Strftime(const char* fmt, const struct tm& tm) { + char buf[512]; + size_t n = strftime(buf, sizeof buf, fmt, &tm); + return LocalizedPiece(buf, n); +} + +// strftime with the Microsoft '#' flag (no leading zeros, long %c/%x forms). +CString FormatTm(const char* fmt, const struct tm& tm) { + std::string out; + for (const char* p = fmt ? fmt : ""; *p; ++p) { + if (*p != '%') { + out += *p; + continue; + } + if (!*++p) + break; + bool alt = false; + if (*p == '#') { + alt = true; + if (!*++p) + break; + } + char spec = *p; + if (spec == '%') { + out += '%'; + continue; + } + if (alt && (spec == 'x' || spec == 'c')) { + out += Strftime("%A, %B ", tm) + std::to_string(tm.tm_mday) + Strftime(", %Y", tm); + if (spec == 'c') + out += Strftime(" %H:%M:%S", tm); + continue; + } + char one[3] = {'%', spec, 0}; + std::string piece = Strftime(one, tm); + if (alt && strchr("dHIjmMSUwWy", spec)) { + size_t z = 0; + while (z + 1 < piece.size() && piece[z] == '0') + ++z; + piece.erase(0, z); + } + out += piece; + } + return CString(out.c_str(), static_cast(out.size())); +} + +bool OleFromParts(int y, int mo, int d, int h, int mi, int s, double& out) { + if (y < 100 || y > 9999 || mo < 1 || mo > 12 || d < 1 || d > DaysInMonth(y, mo) || h < 0 || h > 23 || mi < 0 || + mi > 59 || s < 0 || s > 59) + return false; + long long days = DaysFromCivil(y, static_cast(mo), static_cast(d)) - kOleEpochDays; + double frac = (h * 3600 + mi * 60 + s) / 86400.0; + out = days >= 0 ? static_cast(days) + frac : static_cast(days) - frac; + return true; +} + +void TmFromOle(double dt, struct tm& tm) { + long long dayPart = static_cast(std::trunc(dt)); + double frac = std::fabs(dt - static_cast(dayPart)); + long long secs = std::llround(frac * 86400.0); + if (secs >= 86400) { + secs -= 86400; + ++dayPart; + } + long long days = dayPart + kOleEpochDays; + int y, m, d; + CivilFromDays(days, y, m, d); + memset(&tm, 0, sizeof tm); + tm.tm_year = y - 1900; + tm.tm_mon = m - 1; + tm.tm_mday = d; + tm.tm_hour = static_cast(secs / 3600); + tm.tm_min = static_cast(secs / 60 % 60); + tm.tm_sec = static_cast(secs % 60); + tm.tm_wday = static_cast(((days + 4) % 7 + 7) % 7); + tm.tm_yday = static_cast(days - DaysFromCivil(y, 1, 1)); + tm.tm_isdst = -1; +} + +std::string FileNameOrUnnamed(const CString& name) { return name.IsEmpty() ? "an unnamed file" : name.GetString(); } + +BOOL CopyMessage(const std::string& text, char* buffer, UINT size, PUINT help) { + if (help) + *help = 0; + if (buffer && size) { + size_t n = std::min(text.size(), static_cast(size - 1)); + memcpy(buffer, text.data(), n); + buffer[n] = 0; + } + return TRUE; +} + +std::string Substitute(const char* tmpl, const std::string& name) { + std::string s = tmpl; + size_t pos = s.find("%1"); + if (pos != std::string::npos) + s.replace(pos, 2, name); + return s; +} + +} // namespace + +AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass) { + pNewClass->m_pNextClass = g_firstClass; + g_firstClass = pNewClass; +} + +CObject* CRuntimeClass::CreateObject() { return m_pfnCreateObject ? m_pfnCreateObject() : nullptr; } + +BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const { + for (const CRuntimeClass* c = this; c; c = c->GetBaseClass()) + if (c == pBaseClass) + return TRUE; + return FALSE; +} + +CRuntimeClass* CRuntimeClass::FromName(const char* name) { + if (!name) + return nullptr; + for (CRuntimeClass* c = g_firstClass; c; c = c->m_pNextClass) + if (strcmp(c->m_lpszClassName, name) == 0) + return c; + return nullptr; +} + +CObject* CRuntimeClass::CreateObject(const char* name) { + CRuntimeClass* c = FromName(name); + return c ? c->CreateObject() : nullptr; +} + +CRuntimeClass CObject::classCObject = {"CObject", sizeof(CObject), 0xFFFF, nullptr, nullptr, nullptr}; +static AFX_CLASSINIT _init_CObject(&CObject::classCObject); + +CRuntimeClass* CObject::GetThisClass() { return &classCObject; } + +CRuntimeClass* CObject::GetRuntimeClass() const { return &classCObject; } + +BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const { return GetRuntimeClass()->IsDerivedFrom(pClass); } + +BOOL CObject::IsSerializable() const { return GetRuntimeClass()->m_wSchema != 0xFFFF; } + +void CObject::Serialize(CArchive&) {} + +CDumpContext afxDump; + +void AfxAssertFailedLine(const char* file, int line, const char* expr) { + fprintf(stderr, "mfcwx: assertion failed: %s (%s:%d)\n", expr ? expr : "", file ? file : "?", line); +} + +void AfxDebugBreak() { fprintf(stderr, "mfcwx: AfxDebugBreak()\n"); } + +// --------------------------------------------------------------------------------------------- +// Exceptions + +IMPLEMENT_DYNAMIC(CException, CObject) +IMPLEMENT_DYNAMIC(CSimpleException, CException) +IMPLEMENT_DYNAMIC(CMemoryException, CSimpleException) +IMPLEMENT_DYNAMIC(CNotSupportedException, CSimpleException) +IMPLEMENT_DYNAMIC(CInvalidArgException, CSimpleException) +IMPLEMENT_DYNAMIC(CUserException, CSimpleException) +IMPLEMENT_DYNAMIC(CResourceException, CSimpleException) +IMPLEMENT_DYNAMIC(CArchiveException, CException) +IMPLEMENT_DYNAMIC(CFileException, CException) + +void CException::Delete() { + if (m_bAutoDelete > 0) + delete this; +} + +BOOL CException::GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext) const { + const char* text = nullptr; + if (IsKindOf(RUNTIME_CLASS(CNotSupportedException))) + text = "An unsupported operation was attempted."; + else if (IsKindOf(RUNTIME_CLASS(CInvalidArgException))) + text = "Encountered an improper argument."; + else if (IsKindOf(RUNTIME_CLASS(CResourceException))) + text = "A required resource was unavailable."; + if (text) + return CopyMessage(text, lpszError, nMaxError, pnHelpContext); + if (pnHelpContext) + *pnHelpContext = 0; + if (lpszError && nMaxError) + lpszError[0] = 0; + return FALSE; +} + +int CException::ReportError(UINT nType, UINT nMessageID) { + char msg[1024]; + if (GetErrorMessage(msg, sizeof msg)) + return AfxMessageBox(msg, nType); + if (nMessageID) + return AfxMessageBox(nMessageID, nType); + return AfxMessageBox("No error message is available.", nType); +} + +BOOL CMemoryException::GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext) const { + return CopyMessage("Out of memory.", lpszError, nMaxError, pnHelpContext); +} + +BOOL CArchiveException::GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext) const { + static const char* const texts[] = { + "No error occurred.", + "An unknown error occurred while accessing %1.", + "An attempt was made to write to the reading %1.", + "An attempt was made to access %1 past its end.", + "An attempt was made to read from the writing %1.", + "%1 has a bad format.", + "%1 contained an unexpected object.", + "%1 contains an incorrect schema.", + "The archive buffer of %1 is full.", + }; + int cause = m_cause >= 0 && m_cause <= bufferFull ? m_cause : genericException; + return CopyMessage(Substitute(texts[cause], FileNameOrUnnamed(m_strFileName)), lpszError, nMaxError, pnHelpContext); +} + +BOOL CFileException::GetErrorMessage(char* lpszError, UINT nMaxError, PUINT pnHelpContext) const { + static const char* const texts[] = { + "No error occurred.", + "An unknown error occurred while accessing %1.", + "%1 was not found.", + "%1 contains an invalid path.", + "%1 could not be opened because there are too many open files.", + "Access to %1 was denied.", + "An invalid file handle was associated with %1.", + "%1 could not be removed because it is the current directory.", + "%1 could not be created because the directory is full.", + "Seek failed on %1", + "A hardware I/O error was reported while accessing %1.", + "A sharing violation occurred while accessing %1.", + "A locking violation occurred while accessing %1.", + "Disk full while accessing %1.", + "An attempt was made to access %1 past its end.", + }; + int cause = m_cause >= 0 && m_cause <= endOfFile ? m_cause : genericException; + return CopyMessage(Substitute(texts[cause], FileNameOrUnnamed(m_strFileName)), lpszError, nMaxError, pnHelpContext); +} + +int CFileException::OsErrorToException(LONG lOsError) { + switch (lOsError) { + case 0: + return none; + case 2: + case 6: + case 18: + return fileNotFound; + case 3: + case 15: + case 17: + case 123: + case 206: + return badPath; + case 4: + return tooManyOpenFiles; + case 5: + case 12: + case 19: + case 80: + case 183: + return accessDenied; + case 11: + return invalidFile; + case 16: + case 145: + return removeCurrentDir; + case 20: + case 21: + case 1117: + return hardIO; + case 32: + return sharingViolation; + case 33: + return lockViolation; + case 38: + return endOfFile; + case 39: + case 112: + return diskFull; + case 131: + case 132: + return badSeek; + default: + return genericException; + } +} + +int CFileException::ErrnoToException(int nErrno) { + switch (nErrno) { + case 0: + return none; + case EPERM: + case EACCES: + case EEXIST: + case EISDIR: + case EROFS: + return accessDenied; + case ENOENT: + return fileNotFound; + case EBADF: + return invalidFile; + case EMFILE: + case ENFILE: + return tooManyOpenFiles; + case ENOSPC: + return diskFull; + case ENOTDIR: + case ENAMETOOLONG: + case ELOOP: + return badPath; + case EIO: + return hardIO; + case ESPIPE: + return badSeek; + case EBUSY: + return sharingViolation; + default: + return genericException; + } +} + +void CFileException::ThrowOsError(LONG lOsError, const char* lpszFileName) { + if (lOsError != 0) + throw new CFileException(OsErrorToException(lOsError), lOsError, lpszFileName); +} + +void CFileException::ThrowErrno(int nErrno, const char* lpszFileName) { + if (nErrno != 0) + throw new CFileException(ErrnoToException(nErrno), static_cast(ErrnoToWin32(nErrno)), lpszFileName); +} + +void AfxThrowMemoryException() { throw new CMemoryException; } + +void AfxThrowNotSupportedException() { throw new CNotSupportedException; } + +void AfxThrowInvalidArgException() { throw new CInvalidArgException; } + +void AfxThrowUserException() { throw new CUserException; } + +void AfxThrowResourceException() { throw new CResourceException; } + +void AfxThrowArchiveException(int cause, const char* lpszArchiveName) { + throw new CArchiveException(cause, lpszArchiveName); +} + +void AfxThrowFileException(int cause, LONG lOsError, const char* lpszFileName) { + throw new CFileException(cause, lOsError, lpszFileName); +} + +void AfxAbort() { + fprintf(stderr, "mfcwx: AfxAbort()\n"); + abort(); +} + +// --------------------------------------------------------------------------------------------- +// Collections + +IMPLEMENT_SERIAL(CStringArray, CObject, 0) +IMPLEMENT_SERIAL(CPtrArray, CObject, 0) +IMPLEMENT_SERIAL(CObArray, CObject, 0) +IMPLEMENT_SERIAL(CDWordArray, CObject, 0) +IMPLEMENT_SERIAL(CUIntArray, CObject, 0) +IMPLEMENT_SERIAL(CWordArray, CObject, 0) +IMPLEMENT_SERIAL(CByteArray, CObject, 0) +IMPLEMENT_SERIAL(CStringList, CObject, 0) +IMPLEMENT_SERIAL(CPtrList, CObject, 0) +IMPLEMENT_SERIAL(CObList, CObject, 0) +IMPLEMENT_SERIAL(CMapStringToString, CObject, 0) +IMPLEMENT_SERIAL(CMapStringToPtr, CObject, 0) +IMPLEMENT_SERIAL(CMapStringToOb, CObject, 0) +IMPLEMENT_SERIAL(CMapPtrToPtr, CObject, 0) +IMPLEMENT_SERIAL(CMapPtrToWord, CObject, 0) +IMPLEMENT_SERIAL(CMapWordToPtr, CObject, 0) +IMPLEMENT_SERIAL(CMapWordToOb, CObject, 0) + +// --------------------------------------------------------------------------------------------- +// Time + +CString CTimeSpan::Format(const char* pFormat) const { + std::string out; + char buf[32]; + for (const char* p = pFormat ? pFormat : ""; *p; ++p) { + if (*p != '%' || !p[1]) { + out += *p; + continue; + } + switch (*++p) { + case 'D': + snprintf(buf, sizeof buf, "%lld", static_cast(GetDays())); + out += buf; + break; + case 'H': + snprintf(buf, sizeof buf, "%02ld", static_cast(GetHours())); + out += buf; + break; + case 'M': + snprintf(buf, sizeof buf, "%02ld", static_cast(GetMinutes())); + out += buf; + break; + case 'S': + snprintf(buf, sizeof buf, "%02ld", static_cast(GetSeconds())); + out += buf; + break; + default: + out += *p; + break; + } + } + return CString(out.c_str(), static_cast(out.size())); +} + +CTime::CTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, int nDST) { + struct tm tm; + memset(&tm, 0, sizeof tm); + tm.tm_year = nYear - 1900; + tm.tm_mon = nMonth - 1; + tm.tm_mday = nDay; + tm.tm_hour = nHour; + tm.tm_min = nMin; + tm.tm_sec = nSec; + tm.tm_isdst = nDST; + m_time = mktime(&tm); +} + +CTime::CTime(const SYSTEMTIME& st, int nDST) : m_time(0) { + if (st.wYear >= 1900) + *this = CTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, nDST); +} + +CTime::CTime(const FILETIME& ft, int) : m_time(FileTimeToUnix(ft)) {} + +CTime CTime::GetCurrentTime() { return CTime(time(nullptr)); } + +struct tm* CTime::GetLocalTm(struct tm* ptm) const { + static thread_local struct tm local; + if (!ptm) + ptm = &local; + return localtime_r(&m_time, ptm); +} + +struct tm* CTime::GetGmtTm(struct tm* ptm) const { + static thread_local struct tm gmt; + if (!ptm) + ptm = &gmt; + return gmtime_r(&m_time, ptm); +} + +BOOL CTime::GetAsSystemTime(SYSTEMTIME& st) const { + struct tm tm; + if (!GetLocalTm(&tm)) + return FALSE; + st.wYear = static_cast(tm.tm_year + 1900); + st.wMonth = static_cast(tm.tm_mon + 1); + st.wDayOfWeek = static_cast(tm.tm_wday); + st.wDay = static_cast(tm.tm_mday); + st.wHour = static_cast(tm.tm_hour); + st.wMinute = static_cast(tm.tm_min); + st.wSecond = static_cast(tm.tm_sec); + st.wMilliseconds = 0; + return TRUE; +} + +int CTime::GetYear() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_year + 1900 : 0; +} + +int CTime::GetMonth() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_mon + 1 : 0; +} + +int CTime::GetDay() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_mday : 0; +} + +int CTime::GetHour() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_hour : 0; +} + +int CTime::GetMinute() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_min : 0; +} + +int CTime::GetSecond() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_sec : 0; +} + +int CTime::GetDayOfWeek() const { + struct tm tm; + return GetLocalTm(&tm) ? tm.tm_wday + 1 : 0; +} + +CString CTime::Format(const char* pFormat) const { + struct tm tm; + if (!GetLocalTm(&tm)) + return CString(); + return FormatTm(pFormat, tm); +} + +CString CTime::Format(UINT nFormatID) const { + CString fmt; + fmt.LoadString(nFormatID); + return Format(fmt.GetString()); +} + +CString CTime::FormatGmt(const char* pFormat) const { + struct tm tm; + if (!GetGmtTm(&tm)) + return CString(); + return FormatTm(pFormat, tm); +} + +COleDateTime::COleDateTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec) : m_dt(0), m_status(valid) { + if (!OleFromParts(nYear, nMonth, nDay, nHour, nMin, nSec, m_dt)) { + m_dt = 0; + m_status = invalid; + } +} + +COleDateTime COleDateTime::GetCurrentTime() { + time_t now = time(nullptr); + struct tm tm; + localtime_r(&now, &tm); + return COleDateTime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); +} + +int COleDateTime::GetYear() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_year + 1900; +} + +int COleDateTime::GetMonth() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_mon + 1; +} + +int COleDateTime::GetDay() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_mday; +} + +int COleDateTime::GetHour() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_hour; +} + +int COleDateTime::GetMinute() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_min; +} + +int COleDateTime::GetSecond() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_sec; +} + +int COleDateTime::GetDayOfWeek() const { + if (m_status != valid) + return -1; + struct tm tm; + TmFromOle(m_dt, tm); + return tm.tm_wday + 1; +} + +CString COleDateTime::Format(const char* pFormat) const { + if (m_status == null) + return CString(); + if (m_status != valid) + return CString("Invalid DateTime"); + struct tm tm; + TmFromOle(m_dt, tm); + return FormatTm(pFormat, tm); +} + +CString COleDateTime::Format(DWORD dwFlags, LCID) const { + if (m_status == null) + return CString(); + if (m_status != valid) + return CString("Invalid DateTime"); + struct tm tm; + TmFromOle(m_dt, tm); + bool hasTime = tm.tm_hour || tm.tm_min || tm.tm_sec; + bool hasDate = static_cast(std::trunc(m_dt)) != 0; + bool timeOnly = (dwFlags & 0x2) != 0 || (!hasDate && hasTime); + bool dateOnly = (dwFlags & 0x4) != 0 || !hasTime; + if (timeOnly && !(dwFlags & 0x4)) + return FormatTm("%X", tm); + if (dateOnly) + return FormatTm("%x", tm); + return FormatTm("%x %X", tm); +} diff --git a/port/mfcwx/src/afxfile.cpp b/port/mfcwx/src/afxfile.cpp new file mode 100644 index 000000000..0b9e1a13e --- /dev/null +++ b/port/mfcwx/src/afxfile.cpp @@ -0,0 +1,990 @@ +#include "afx.h" +#include "runtime.h" + +#include +#include +#include + +#include +#include +#include +#include + +#undef fopen +#undef rename +#undef remove + +using namespace mfcwx; + +namespace { + +#ifdef __APPLE__ +inline time_t BirthSeconds(const struct stat& st) { return st.st_birthtimespec.tv_sec; } +#else +inline time_t BirthSeconds(const struct stat& st) { return st.st_ctim.tv_sec; } +#endif + +CString FileNamePart(const CString& path) { + const char* p = path.GetString(); + const char* last = p; + for (const char* q = p; *q; ++q) + if (*q == '\\' || *q == '/' || *q == ':') + last = q + 1; + return CString(last); +} + +CString StripExtension(const CString& name) { + int dot = name.ReverseFind('.'); + return dot > 0 ? name.Left(dot) : name; +} + +void FillStatus(const struct stat& st, const std::string& native, CFileStatus& rStatus) { + rStatus.m_ctime = BirthSeconds(st); + rStatus.m_atime = st.st_atime; + rStatus.m_mtime = st.st_mtime; + rStatus.m_size = static_cast(st.st_size); + BYTE attr = 0; + if (S_ISDIR(st.st_mode)) + attr |= CFile::directory; + else + attr |= CFile::archive; + if (access(native.c_str(), W_OK) != 0) + attr |= CFile::readOnly; + size_t slash = native.rfind('/'); + const char* base = native.c_str() + (slash == std::string::npos ? 0 : slash + 1); + if (base[0] == '.' && strcmp(base, ".") != 0 && strcmp(base, "..") != 0) + attr |= CFile::hidden; + rStatus.m_attribute = attr; +} + +void ThrowArchive(int cause, CFile* file) { + AfxThrowArchiveException(cause, file ? file->GetFilePath().GetString() : nullptr); +} + +constexpr WORD kNullTag = 0; +constexpr WORD kNewClassTag = 0xFFFF; +constexpr WORD kClassTag = 0x8000; +constexpr DWORD kBigClassTag = 0x80000000u; +constexpr WORD kBigObjectTag = 0x7FFF; + +} // namespace + +// --------------------------------------------------------------------------------------------- +// CFile + +IMPLEMENT_DYNAMIC(CFile, CObject) +IMPLEMENT_DYNAMIC(CStdioFile, CFile) +IMPLEMENT_DYNAMIC(CMemFile, CFile) +IMPLEMENT_DYNAMIC(CFileFind, CObject) + +const HANDLE CFile::hFileNull = INVALID_HANDLE_VALUE; + +CFile::CFile() : m_hFile(hFileNull), m_bCloseOnDelete(FALSE), m_fd(-1) {} + +CFile::CFile(HANDLE hFile) : m_hFile(hFile), m_bCloseOnDelete(FALSE), m_fd(FdFromHandle(hFile)) {} + +CFile::CFile(const char* lpszFileName, UINT nOpenFlags) : CFile() { + CFileException e; + if (!Open(lpszFileName, nOpenFlags, &e)) + AfxThrowFileException(e.m_cause, e.m_lOsError, e.m_strFileName); +} + +CFile::~CFile() { + if (m_hFile != hFileNull && m_bCloseOnDelete) + Abort(); +} + +BOOL CFile::Open(const char* lpszFileName, UINT nOpenFlags, CFileException* pError) { + if (m_hFile != hFileNull) + Abort(); + auto fail = [&](int err, int cause) { + if (pError) { + pError->m_cause = cause; + pError->m_lOsError = static_cast(ErrnoToWin32(err)); + pError->m_strFileName = lpszFileName; + } + return FALSE; + }; + if (!lpszFileName || !*lpszFileName) + return fail(ENOENT, CFileException::badPath); + int oflags = O_CLOEXEC; + switch (nOpenFlags & 3) { + case modeWrite: + oflags |= O_WRONLY; + break; + case modeReadWrite: + oflags |= O_RDWR; + break; + default: + oflags |= O_RDONLY; + break; + } + if (nOpenFlags & modeCreate) { + oflags |= O_CREAT; + if (!(nOpenFlags & modeNoTruncate)) + oflags |= O_TRUNC; + } + std::string path = FsPath(lpszFileName); + struct stat st; + if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) + return fail(EACCES, CFileException::accessDenied); + int fd = open(path.c_str(), oflags, 0666); + if (fd < 0) { + int err = errno; + return fail(err, CFileException::ErrnoToException(err)); + } + m_strFileName = FullAppPath(lpszFileName).c_str(); + m_fd = fd; + m_hFile = HandleFromFd(fd, path, true); + m_bCloseOnDelete = TRUE; + return TRUE; +} + +void CFile::Close() { + if (m_hFile != hFileNull) + CloseHandle(m_hFile); + m_hFile = hFileNull; + m_fd = -1; + m_bCloseOnDelete = FALSE; + m_strFileName.Empty(); +} + +void CFile::Abort() { + if (m_hFile != hFileNull) + CloseHandle(m_hFile); + m_hFile = hFileNull; + m_fd = -1; + m_bCloseOnDelete = FALSE; + m_strFileName.Empty(); +} + +UINT CFile::Read(void* lpBuf, UINT nCount) { + if (nCount == 0) + return 0; + if (m_fd < 0) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + char* p = static_cast(lpBuf); + UINT total = 0; + while (total < nCount) { + ssize_t n = read(m_fd, p + total, nCount - total); + if (n < 0 && errno == EINTR) + continue; + if (n < 0) + CFileException::ThrowErrno(errno, m_strFileName); + if (n == 0) + break; + total += static_cast(n); + } + return total; +} + +void CFile::Write(const void* lpBuf, UINT nCount) { + if (nCount == 0) + return; + if (m_fd < 0) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + const char* p = static_cast(lpBuf); + UINT total = 0; + while (total < nCount) { + ssize_t n = write(m_fd, p + total, nCount - total); + if (n < 0 && errno == EINTR) + continue; + if (n <= 0) + CFileException::ThrowErrno(n < 0 ? errno : ENOSPC, m_strFileName); + total += static_cast(n); + } +} + +ULONGLONG CFile::Seek(LONGLONG lOff, UINT nFrom) { + int whence = nFrom == current ? SEEK_CUR : nFrom == end ? SEEK_END : SEEK_SET; + off_t pos = m_fd >= 0 ? lseek(m_fd, static_cast(lOff), whence) : -1; + if (pos < 0) + AfxThrowFileException(CFileException::badSeek, 131, m_strFileName); + return static_cast(pos); +} + +ULONGLONG CFile::GetLength() const { + struct stat st; + if (m_fd < 0 || fstat(m_fd, &st) != 0) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + return static_cast(st.st_size); +} + +void CFile::SetLength(ULONGLONG dwNewLen) { + if (m_fd < 0 || ftruncate(m_fd, static_cast(dwNewLen)) != 0) + CFileException::ThrowErrno(m_fd < 0 ? EBADF : errno, m_strFileName); +} + +ULONGLONG CFile::GetPosition() const { + off_t pos = m_fd >= 0 ? lseek(m_fd, 0, SEEK_CUR) : -1; + if (pos < 0) + AfxThrowFileException(CFileException::badSeek, 131, m_strFileName); + return static_cast(pos); +} + +void CFile::Flush() {} + +CString CFile::GetFileName() const { return FileNamePart(m_strFileName); } + +CString CFile::GetFileTitle() const { return StripExtension(GetFileName()); } + +BOOL CFile::GetStatus(CFileStatus& rStatus) const { + memset(&rStatus, 0, sizeof rStatus); + struct stat st; + if (m_fd < 0 || fstat(m_fd, &st) != 0) + return FALSE; + FillStatus(st, NativePath(m_strFileName), rStatus); + strncpy(rStatus.m_szFullName, m_strFileName.GetString(), sizeof rStatus.m_szFullName - 1); + return TRUE; +} + +BOOL CFile::GetStatus(const char* lpszFileName, CFileStatus& rStatus) { + memset(&rStatus, 0, sizeof rStatus); + if (!lpszFileName || !*lpszFileName) + return FALSE; + std::string path = FsPath(lpszFileName); + struct stat st; + if (stat(path.c_str(), &st) != 0) + return FALSE; + FillStatus(st, path, rStatus); + strncpy(rStatus.m_szFullName, FullAppPath(lpszFileName).c_str(), sizeof rStatus.m_szFullName - 1); + return TRUE; +} + +void CFile::SetStatus(const char* lpszFileName, const CFileStatus& status) { + std::string path = FsPath(lpszFileName); + struct stat st; + if (stat(path.c_str(), &st) != 0) + CFileException::ThrowErrno(errno, lpszFileName); + if (status.m_mtime != 0) { + struct timeval tv[2]; + tv[0].tv_sec = status.m_atime ? status.m_atime : status.m_mtime; + tv[0].tv_usec = 0; + tv[1].tv_sec = status.m_mtime; + tv[1].tv_usec = 0; + if (utimes(path.c_str(), tv) != 0) + CFileException::ThrowErrno(errno, lpszFileName); + } + mode_t mode = st.st_mode & 07777; + mode_t wanted = (status.m_attribute & readOnly) ? mode & ~static_cast(S_IWUSR | S_IWGRP | S_IWOTH) + : mode | S_IWUSR; + if (wanted != mode && chmod(path.c_str(), wanted) != 0) + CFileException::ThrowErrno(errno, lpszFileName); +} + +void CFile::Rename(const char* lpszOldName, const char* lpszNewName) { + if (rename(FsPath(lpszOldName).c_str(), FsPath(lpszNewName).c_str()) != 0) + CFileException::ThrowErrno(errno, lpszOldName); +} + +void CFile::Remove(const char* lpszFileName) { + std::string path = FsPath(lpszFileName); + struct stat st; + if (lstat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) + CFileException::ThrowErrno(EACCES, lpszFileName); + if (unlink(path.c_str()) != 0) + CFileException::ThrowErrno(errno, lpszFileName); +} + +CFile* CFile::Duplicate() const { + if (m_fd < 0) + return nullptr; + int fd = fcntl(m_fd, F_DUPFD_CLOEXEC, 0); + if (fd < 0) + CFileException::ThrowErrno(errno, m_strFileName); + auto* file = new CFile; + file->m_fd = fd; + file->m_hFile = HandleFromFd(fd, NativePath(m_strFileName), true); + file->m_bCloseOnDelete = m_bCloseOnDelete; + file->m_strFileName = m_strFileName; + return file; +} + +// --------------------------------------------------------------------------------------------- +// CStdioFile + +CStdioFile::CStdioFile() : m_pStream(nullptr), m_text(true) {} + +CStdioFile::CStdioFile(FILE* pOpenStream) : m_pStream(pOpenStream), m_text(true) { + if (pOpenStream) { + m_fd = fileno(pOpenStream); + m_hFile = HandleFromFd(m_fd, std::string(), false); + } +} + +CStdioFile::CStdioFile(const char* lpszFileName, UINT nOpenFlags) : CStdioFile() { + CFileException e; + if (!Open(lpszFileName, nOpenFlags, &e)) + AfxThrowFileException(e.m_cause, e.m_lOsError, e.m_strFileName); +} + +CStdioFile::~CStdioFile() { + if (m_pStream && m_bCloseOnDelete) { + Abort(); + } else if (m_hFile != hFileNull) { + CloseHandle(m_hFile); + m_hFile = hFileNull; + } +} + +BOOL CStdioFile::Open(const char* lpszFileName, UINT nOpenFlags, CFileException* pError) { + if (m_pStream) + Abort(); + m_text = !(nOpenFlags & typeBinary); + if (!CFile::Open(lpszFileName, nOpenFlags & ~(typeText | typeBinary), pError)) + return FALSE; + char mode[4]; + int n = 0; + if (nOpenFlags & modeCreate) + mode[n++] = (nOpenFlags & modeNoTruncate) ? 'a' : 'w'; + else if (nOpenFlags & modeWrite) + mode[n++] = 'a'; + else + mode[n++] = 'r'; + if ((mode[0] == 'r' && (nOpenFlags & modeReadWrite)) || (mode[0] != 'r' && !(nOpenFlags & modeWrite))) + mode[n++] = '+'; + mode[n] = 0; + // The stream takes its own descriptor; the kernel file object keeps a non-owning view of it. + int fd = fcntl(m_fd, F_DUPFD_CLOEXEC, 0); + FILE* stream = fd >= 0 ? fdopen(fd, mode) : nullptr; + if (!stream) { + int err = errno; + if (fd >= 0) + close(fd); + CString name = m_strFileName; + CFile::Abort(); + if (pError) { + pError->m_cause = CFileException::ErrnoToException(err); + pError->m_lOsError = static_cast(ErrnoToWin32(err)); + pError->m_strFileName = lpszFileName; + } + return FALSE; + } + std::string native = FsPath(lpszFileName); + CloseHandle(m_hFile); + m_pStream = stream; + m_fd = fd; + m_hFile = HandleFromFd(fd, native, false); + return TRUE; +} + +void CStdioFile::Close() { + int rc = 0; + if (m_pStream) + rc = fclose(m_pStream); + m_pStream = nullptr; + CString name = m_strFileName; + CFile::Abort(); + if (rc != 0) + AfxThrowFileException(CFileException::diskFull, static_cast(ErrnoToWin32(errno)), name); +} + +void CStdioFile::Abort() { + if (m_pStream) + fclose(m_pStream); + m_pStream = nullptr; + CFile::Abort(); +} + +UINT CStdioFile::Read(void* lpBuf, UINT nCount) { + if (nCount == 0) + return 0; + if (!m_pStream) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + size_t n = fread(lpBuf, 1, nCount, m_pStream); + if (n == 0 && ferror(m_pStream)) { + clearerr(m_pStream); + CFileException::ThrowErrno(errno, m_strFileName); + } + return static_cast(n); +} + +void CStdioFile::Write(const void* lpBuf, UINT nCount) { + if (!m_pStream) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + if (nCount && fwrite(lpBuf, 1, nCount, m_pStream) != nCount) + CFileException::ThrowErrno(errno ? errno : ENOSPC, m_strFileName); +} + +ULONGLONG CStdioFile::Seek(LONGLONG lOff, UINT nFrom) { + int whence = nFrom == current ? SEEK_CUR : nFrom == end ? SEEK_END : SEEK_SET; + if (!m_pStream || fseeko(m_pStream, static_cast(lOff), whence) != 0) + AfxThrowFileException(CFileException::badSeek, 131, m_strFileName); + return static_cast(ftello(m_pStream)); +} + +ULONGLONG CStdioFile::GetLength() const { + if (!m_pStream) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + off_t pos = ftello(m_pStream); + fseeko(m_pStream, 0, SEEK_END); + off_t len = ftello(m_pStream); + fseeko(m_pStream, pos, SEEK_SET); + return static_cast(len < 0 ? 0 : len); +} + +ULONGLONG CStdioFile::GetPosition() const { + off_t pos = m_pStream ? ftello(m_pStream) : -1; + if (pos < 0) + AfxThrowFileException(CFileException::badSeek, 131, m_strFileName); + return static_cast(pos); +} + +void CStdioFile::Flush() { + if (m_pStream && fflush(m_pStream) != 0) + AfxThrowFileException(CFileException::diskFull, static_cast(ErrnoToWin32(errno)), m_strFileName); +} + +void CStdioFile::WriteString(const char* lpsz) { + if (!m_pStream) + AfxThrowFileException(CFileException::invalidFile, ERROR_INVALID_HANDLE, m_strFileName); + if (lpsz && fputs(lpsz, m_pStream) == EOF) + AfxThrowFileException(CFileException::diskFull, static_cast(ErrnoToWin32(errno)), m_strFileName); +} + +char* CStdioFile::ReadString(char* lpsz, UINT nMax) { + if (!m_pStream || !lpsz || nMax == 0) + return nullptr; + char* r = fgets(lpsz, static_cast(nMax), m_pStream); + if (!r) { + if (ferror(m_pStream)) { + clearerr(m_pStream); + CFileException::ThrowErrno(errno, m_strFileName); + } + return nullptr; + } + size_t len = strlen(lpsz); + if (m_text && len >= 2 && lpsz[len - 2] == '\r' && lpsz[len - 1] == '\n') { + lpsz[len - 2] = '\n'; + lpsz[len - 1] = 0; + } + return lpsz; +} + +BOOL CStdioFile::ReadString(CString& rString) { + rString.Empty(); + if (!m_pStream) + return FALSE; + std::string line; + bool any = false; + int c; + while ((c = getc(m_pStream)) != EOF) { + any = true; + if (c == '\n') + break; + line += static_cast(c); + } + if (!any) { + if (ferror(m_pStream)) { + clearerr(m_pStream); + CFileException::ThrowErrno(errno, m_strFileName); + } + return FALSE; + } + if (m_text && !line.empty() && line.back() == '\r') + line.pop_back(); + rString = CString(line.data(), static_cast(line.size())); + return TRUE; +} + +// --------------------------------------------------------------------------------------------- +// CMemFile + +CMemFile::CMemFile(UINT nGrowBytes) + : m_lpBuffer(nullptr), m_nBufferSize(0), m_nFileSize(0), m_nPosition(0), m_nGrowBytes(nGrowBytes), + m_bAutoDelete(true) {} + +CMemFile::CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes) : CMemFile(nGrowBytes) { + Attach(lpBuffer, nBufferSize, nGrowBytes); +} + +CMemFile::~CMemFile() { Close(); } + +void CMemFile::Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes) { + Close(); + m_lpBuffer = lpBuffer; + m_nBufferSize = nBufferSize; + m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0; + m_nGrowBytes = nGrowBytes; + m_nPosition = 0; + m_bAutoDelete = false; +} + +BYTE* CMemFile::Detach() { + BYTE* buffer = m_lpBuffer; + m_lpBuffer = nullptr; + m_nBufferSize = 0; + m_nFileSize = 0; + m_nPosition = 0; + return buffer; +} + +void CMemFile::Grow(size_t size) { + if (size <= m_nBufferSize) + return; + if (m_nGrowBytes == 0) + AfxThrowMemoryException(); + size_t n = m_nBufferSize; + while (n < size) + n += m_nGrowBytes; + auto* p = static_cast(realloc(m_lpBuffer, n)); + if (!p) + AfxThrowMemoryException(); + m_lpBuffer = p; + m_nBufferSize = n; +} + +void CMemFile::Close() { + if (m_lpBuffer && m_bAutoDelete) + free(m_lpBuffer); + m_lpBuffer = nullptr; + m_nBufferSize = 0; + m_nFileSize = 0; + m_nPosition = 0; +} + +UINT CMemFile::Read(void* lpBuf, UINT nCount) { + if (m_nPosition >= m_nFileSize || nCount == 0) + return 0; + size_t n = std::min(static_cast(nCount), m_nFileSize - m_nPosition); + memcpy(lpBuf, m_lpBuffer + m_nPosition, n); + m_nPosition += n; + return static_cast(n); +} + +void CMemFile::Write(const void* lpBuf, UINT nCount) { + if (nCount == 0) + return; + size_t endPos = m_nPosition + nCount; + if (endPos > m_nBufferSize) + Grow(endPos); + if (m_nPosition > m_nFileSize) + memset(m_lpBuffer + m_nFileSize, 0, m_nPosition - m_nFileSize); + memcpy(m_lpBuffer + m_nPosition, lpBuf, nCount); + m_nPosition = endPos; + if (m_nPosition > m_nFileSize) + m_nFileSize = m_nPosition; +} + +ULONGLONG CMemFile::Seek(LONGLONG lOff, UINT nFrom) { + LONGLONG base = nFrom == current ? static_cast(m_nPosition) + : nFrom == end ? static_cast(m_nFileSize) + : 0; + LONGLONG pos = base + lOff; + if (pos < 0) + AfxThrowFileException(CFileException::badSeek, 131, m_strFileName); + m_nPosition = static_cast(pos); + return static_cast(pos); +} + +void CMemFile::SetLength(ULONGLONG dwNewLen) { + size_t len = static_cast(dwNewLen); + if (len > m_nBufferSize) + Grow(len); + if (len > m_nFileSize) + memset(m_lpBuffer + m_nFileSize, 0, len - m_nFileSize); + if (len < m_nPosition) + m_nPosition = len; + m_nFileSize = len; +} + +// --------------------------------------------------------------------------------------------- +// CFileFind + +struct CFileFind::Impl { + CString root; + std::vector entries; + size_t next = 0; + long current = -1; + const WIN32_FIND_DATA* Current() const { return current >= 0 ? &entries[static_cast(current)] : nullptr; } +}; + +CFileFind::CFileFind() : m_impl(nullptr) {} + +CFileFind::~CFileFind() { Close(); } + +BOOL CFileFind::FindFile(const char* pstrName, DWORD) { + Close(); + const char* pattern = pstrName && *pstrName ? pstrName : "*.*"; + WIN32_FIND_DATA fd; + HANDLE h = ::FindFirstFileA(pattern, &fd); + if (h == INVALID_HANDLE_VALUE) + return FALSE; + m_impl = new Impl; + do + m_impl->entries.push_back(fd); + while (::FindNextFileA(h, &fd)); + ::FindClose(h); + std::string full = FullAppPath(pattern); + size_t sep = full.rfind('\\'); + m_impl->root = sep == std::string::npos ? CString("\\") : CString(full.substr(0, sep + 1).c_str()); + SetLastError(0); + return TRUE; +} + +BOOL CFileFind::FindNextFile() { + if (!m_impl || m_impl->next >= m_impl->entries.size()) + return FALSE; + m_impl->current = static_cast(m_impl->next++); + return m_impl->next < m_impl->entries.size(); +} + +void CFileFind::Close() { + delete m_impl; + m_impl = nullptr; +} + +ULONGLONG CFileFind::GetLength() const { + const WIN32_FIND_DATA* fd = m_impl ? m_impl->Current() : nullptr; + return fd ? (static_cast(fd->nFileSizeHigh) << 32) | fd->nFileSizeLow : 0; +} + +CString CFileFind::GetFileName() const { + const WIN32_FIND_DATA* fd = m_impl ? m_impl->Current() : nullptr; + return fd ? CString(fd->cFileName) : CString(); +} + +CString CFileFind::GetFilePath() const { + if (!m_impl || !m_impl->Current()) + return CString(); + CString path = m_impl->root; + if (!path.IsEmpty() && path[path.GetLength() - 1] != '\\' && path[path.GetLength() - 1] != '/') + path += '\\'; + return path + GetFileName(); +} + +CString CFileFind::GetFileTitle() const { return StripExtension(GetFileName()); } + +CString CFileFind::GetFileURL() const { + CString path = GetFilePath(); + if (path.IsEmpty()) + return path; + path.Replace('\\', '/'); + return CString("file://") + path; +} + +CString CFileFind::GetRoot() const { return m_impl ? m_impl->root : CString(); } + +BOOL CFileFind::IsDots() const { + const WIN32_FIND_DATA* fd = m_impl ? m_impl->Current() : nullptr; + return fd && (strcmp(fd->cFileName, ".") == 0 || strcmp(fd->cFileName, "..") == 0); +} + +BOOL CFileFind::IsDirectory() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } + +BOOL CFileFind::IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } + +BOOL CFileFind::MatchesMask(DWORD dwMask) const { + const WIN32_FIND_DATA* fd = m_impl ? m_impl->Current() : nullptr; + return fd && (fd->dwFileAttributes & dwMask) != 0; +} + +// --------------------------------------------------------------------------------------------- +// CArchive + +CArchive::CArchive(CFile* pFile, UINT nMode, int, void*) + : m_pDocument(nullptr), m_pFile(pFile), m_nMode(nMode), m_nObjectSchema(static_cast(-1)) {} + +CArchive::~CArchive() { + if (m_pFile && !(m_nMode & bNoFlushOnDelete)) + Close(); +} + +BOOL CArchive::IsBufferEmpty() const { + if (!IsLoading() || !m_pFile) + return TRUE; + return m_pFile->GetPosition() >= m_pFile->GetLength(); +} + +void CArchive::Close() { + if (m_pFile && IsStoring()) + m_pFile->Flush(); + m_pFile = nullptr; +} + +UINT CArchive::Read(void* lpBuf, UINT nMax) { + if (!m_pFile || nMax == 0) + return 0; + if (IsStoring()) + ThrowArchive(CArchiveException::writeOnly, m_pFile); + return m_pFile->Read(lpBuf, nMax); +} + +void CArchive::Write(const void* lpBuf, UINT nMax) { + if (!m_pFile || nMax == 0) + return; + if (IsLoading()) + ThrowArchive(CArchiveException::readOnly, m_pFile); + m_pFile->Write(lpBuf, nMax); +} + +namespace { + +template +T ReadValue(CArchive& ar, CFile* file) { + T v{}; + if (ar.Read(&v, sizeof v) != sizeof v) + ThrowArchive(CArchiveException::endOfFile, file); + return v; +} + +} // namespace + +CArchive& CArchive::operator<<(const CString& s) { + DWORD len = static_cast(s.GetLength()); + if (len < 255) { + *this << static_cast(len); + } else if (len < 0xFFFE) { + *this << static_cast(0xFF); + *this << static_cast(len); + } else { + *this << static_cast(0xFF); + *this << static_cast(0xFFFF); + *this << len; + } + Write(s.GetString(), len); + return *this; +} + +CArchive& CArchive::operator>>(CString& s) { + size_t charSize = 1; + // MFC length prefix: BYTE, 0xFF + WORD, 0xFF 0xFFFF + DWORD; 0xFF 0xFFFE marks a UTF-16 string. + auto readLength = [&]() -> ULONGLONG { + BYTE b = ReadValue(*this, m_pFile); + if (b < 0xFF) + return b; + WORD w = ReadValue(*this, m_pFile); + if (w == 0xFFFE) { + charSize = 2; + b = ReadValue(*this, m_pFile); + if (b < 0xFF) + return b; + w = ReadValue(*this, m_pFile); + } + if (w < 0xFFFF) + return w; + DWORD d = ReadValue(*this, m_pFile); + return d < 0xFFFFFFFFu ? d : ReadValue(*this, m_pFile); + }; + ULONGLONG len = readLength(); + if (len > 0x7FFFFFFFULL / charSize) + ThrowArchive(CArchiveException::badIndex, m_pFile); + std::string bytes(static_cast(len * charSize), '\0'); + if (!bytes.empty() && Read(&bytes[0], static_cast(bytes.size())) != bytes.size()) + ThrowArchive(CArchiveException::endOfFile, m_pFile); + if (charSize == 1) { + s = CString(bytes.data(), static_cast(bytes.size())); + return *this; + } + std::string ansi; + for (size_t i = 0; i + 1 < bytes.size(); i += 2) { + uint32_t cp = static_cast(bytes[i]) | (static_cast(bytes[i + 1]) << 8); + if (cp >= 0xD800 && cp < 0xDC00 && i + 3 < bytes.size()) { + uint32_t lo = static_cast(bytes[i + 2]) | (static_cast(bytes[i + 3]) << 8); + if (lo >= 0xDC00 && lo < 0xE000) { + cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00); + i += 2; + } + } + char ch; + UnicodeToAnsi(static_cast(cp), ch); + ansi.push_back(ch); + } + s = CString(ansi.data(), static_cast(ansi.size())); + return *this; +} + +BOOL CArchive::ReadString(CString& rString) { + rString.Empty(); + std::string line; + bool any = false; + char ch; + while (Read(&ch, 1) == 1) { + any = true; + if (ch == '\n') + break; + line += ch; + } + if (!any) + return FALSE; + if (!line.empty() && line.back() == '\r') + line.pop_back(); + rString = CString(line.data(), static_cast(line.size())); + return TRUE; +} + +char* CArchive::ReadString(char* lpsz, UINT nMax) { + if (!lpsz) + return nullptr; + UINT nRead = 0; + char ch; + while (nRead < nMax) { + if (Read(&ch, 1) != 1) { + if (nRead == 0) + return nullptr; + break; + } + if (ch == '\n' || ch == '\r') { + if (ch == '\r') + Read(&ch, 1); + break; + } + lpsz[nRead++] = ch; + } + lpsz[nRead] = 0; + return lpsz; +} + +void CArchive::WriteString(const char* lpsz) { + if (lpsz) + Write(lpsz, static_cast(strlen(lpsz))); +} + +UINT CArchive::ReadCount() { + WORD w = ReadValue(*this, m_pFile); + if (w != 0xFFFF) + return w; + DWORD d = ReadValue(*this, m_pFile); + if (d != 0xFFFFFFFFu) + return d; + return static_cast(ReadValue(*this, m_pFile)); +} + +void CArchive::WriteCount(UINT dwCount) { + if (dwCount < 0xFFFF) { + *this << static_cast(dwCount); + } else { + *this << static_cast(0xFFFF); + *this << static_cast(dwCount); + } +} + +void CArchive::WriteClass(const CRuntimeClass* pClassRef) { + auto it = m_storeClasses.find(pClassRef); + if (it != m_storeClasses.end()) { + if (it->second < kBigObjectTag) { + *this << static_cast(kClassTag | it->second); + } else { + *this << kBigObjectTag; + *this << static_cast(kBigClassTag | it->second); + } + return; + } + *this << kNewClassTag; + WORD len = static_cast(strlen(pClassRef->m_lpszClassName)); + *this << static_cast(pClassRef->m_wSchema); + *this << len; + Write(pClassRef->m_lpszClassName, len); + DWORD index = static_cast(1 + m_storeClasses.size() + m_storeObjects.size()); + m_storeClasses[pClassRef] = index; +} + +void CArchive::WriteObject(const CObject* pOb) { + if (!pOb) { + *this << kNullTag; + return; + } + auto it = m_storeObjects.find(pOb); + if (it != m_storeObjects.end()) { + if (it->second < kBigObjectTag) { + *this << static_cast(it->second); + } else { + *this << kBigObjectTag; + *this << static_cast(it->second); + } + return; + } + WriteClass(pOb->GetRuntimeClass()); + DWORD index = static_cast(1 + m_storeClasses.size() + m_storeObjects.size()); + m_storeObjects[pOb] = index; + const_cast(pOb)->Serialize(*this); +} + +CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested, UINT* pSchema, DWORD* pObTag) { + WORD wTag = ReadValue(*this, m_pFile); + DWORD obTag; + if (wTag == kBigObjectTag) + obTag = ReadValue(*this, m_pFile); + else + obTag = (static_cast(wTag & kClassTag) << 16) | (wTag & ~kClassTag); + if (!(obTag & kBigClassTag)) { + if (!pObTag) + ThrowArchive(CArchiveException::badIndex, m_pFile); + *pObTag = obTag; + return nullptr; + } + if (m_loadClasses.empty()) { + m_loadClasses.push_back(nullptr); + m_loadObjects.push_back(nullptr); + } + CRuntimeClass* pClass; + UINT schema; + if (wTag == kNewClassTag) { + WORD w = ReadValue(*this, m_pFile); + WORD len = ReadValue(*this, m_pFile); + char name[64]; + if (len >= sizeof name || Read(name, len) != len) + ThrowArchive(CArchiveException::badClass, m_pFile); + name[len] = 0; + pClass = CRuntimeClass::FromName(name); + if (!pClass) + ThrowArchive(CArchiveException::badClass, m_pFile); + schema = w; + if ((pClass->m_wSchema & ~VERSIONABLE_SCHEMA) != schema && !(pClass->m_wSchema & VERSIONABLE_SCHEMA)) + ThrowArchive(CArchiveException::badSchema, m_pFile); + m_loadClasses.push_back(pClass); + m_loadObjects.push_back(nullptr); + } else { + DWORD index = obTag & ~kBigClassTag; + if (index == 0 || index >= m_loadClasses.size() || !m_loadClasses[index]) + ThrowArchive(CArchiveException::badIndex, m_pFile); + pClass = const_cast(m_loadClasses[index]); + schema = pClass->m_wSchema & ~VERSIONABLE_SCHEMA; + } + if (pClassRefRequested && !pClass->IsDerivedFrom(pClassRefRequested)) + ThrowArchive(CArchiveException::badClass, m_pFile); + if (pSchema) + *pSchema = schema; + else + m_nObjectSchema = schema; + if (pObTag) + *pObTag = obTag; + return pClass; +} + +CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested) { + UINT schema = 0; + DWORD obTag = 0; + CRuntimeClass* pClass = ReadClass(pClassRefRequested, &schema, &obTag); + if (m_loadObjects.empty()) { + m_loadClasses.push_back(nullptr); + m_loadObjects.push_back(nullptr); + } + if (!pClass) { + if (obTag == 0) + return nullptr; + if (obTag >= m_loadObjects.size() || !m_loadObjects[obTag]) + ThrowArchive(CArchiveException::badIndex, m_pFile); + CObject* pOb = m_loadObjects[obTag]; + if (pClassRefRequested && !pOb->IsKindOf(pClassRefRequested)) + ThrowArchive(CArchiveException::badClass, m_pFile); + return pOb; + } + CObject* pOb = pClass->CreateObject(); + if (!pOb) + AfxThrowMemoryException(); + m_loadClasses.push_back(nullptr); + m_loadObjects.push_back(pOb); + UINT saved = m_nObjectSchema; + m_nObjectSchema = schema; + pOb->Serialize(*this); + m_nObjectSchema = saved; + return pOb; +} + +void CArchive::SerializeClass(const CRuntimeClass* pClassRef) { + if (IsStoring()) + WriteClass(pClassRef); + else + ReadClass(pClassRef, &m_nObjectSchema); +} diff --git a/port/mfcwx/src/afxmt.cpp b/port/mfcwx/src/afxmt.cpp new file mode 100644 index 000000000..95700d2ca --- /dev/null +++ b/port/mfcwx/src/afxmt.cpp @@ -0,0 +1,137 @@ +#include "afxmt.h" + +#include + +IMPLEMENT_DYNAMIC(CSyncObject, CObject) +IMPLEMENT_DYNAMIC(CCriticalSection, CSyncObject) +IMPLEMENT_DYNAMIC(CMutex, CSyncObject) +IMPLEMENT_DYNAMIC(CSemaphore, CSyncObject) +IMPLEMENT_DYNAMIC(CEvent, CSyncObject) + +CSyncObject::CSyncObject(const char*) : m_hObject(nullptr) {} + +CSyncObject::~CSyncObject() { + if (m_hObject) + CloseHandle(m_hObject); + m_hObject = nullptr; +} + +BOOL CSyncObject::Lock(DWORD dwTimeout) { + DWORD r = WaitForSingleObject(m_hObject, dwTimeout); + return r == WAIT_OBJECT_0 || r == WAIT_ABANDONED; +} + +CCriticalSection::CCriticalSection() : CSyncObject(nullptr) { InitializeCriticalSection(&m_sect); } + +CCriticalSection::~CCriticalSection() { DeleteCriticalSection(&m_sect); } + +BOOL CCriticalSection::Lock(DWORD) { + EnterCriticalSection(&m_sect); + return TRUE; +} + +BOOL CCriticalSection::Unlock() { + LeaveCriticalSection(&m_sect); + return TRUE; +} + +CMutex::CMutex(BOOL bInitiallyOwn, const char* lpszName, LPSECURITY_ATTRIBUTES lpsaAttribute) : CSyncObject(lpszName) { + m_hObject = CreateMutexA(lpsaAttribute, bInitiallyOwn, lpszName); + if (!m_hObject) + AfxThrowResourceException(); +} + +BOOL CMutex::Unlock() { return ReleaseMutex(m_hObject); } + +CSemaphore::CSemaphore(LONG lInitialCount, LONG lMaxCount, const char* pstrName, LPSECURITY_ATTRIBUTES lpsaAttributes) + : CSyncObject(pstrName) { + m_hObject = CreateSemaphoreA(lpsaAttributes, lInitialCount, lMaxCount, pstrName); + if (!m_hObject) + AfxThrowResourceException(); +} + +BOOL CSemaphore::Unlock() { return Unlock(1, nullptr); } + +BOOL CSemaphore::Unlock(LONG lCount, LPLONG lprevCount) { return ReleaseSemaphore(m_hObject, lCount, lprevCount); } + +CEvent::CEvent(BOOL bInitiallyOwn, BOOL bManualReset, const char* lpszName, LPSECURITY_ATTRIBUTES lpsaAttribute) + : CSyncObject(lpszName) { + m_hObject = CreateEventA(lpsaAttribute, bManualReset, bInitiallyOwn, lpszName); + if (!m_hObject) + AfxThrowResourceException(); +} + +BOOL CEvent::SetEvent() { return ::SetEvent(m_hObject); } + +BOOL CEvent::PulseEvent() { return ::PulseEvent(m_hObject); } + +BOOL CEvent::ResetEvent() { return ::ResetEvent(m_hObject); } + +CSingleLock::CSingleLock(CSyncObject* pObject, BOOL bInitialLock) : m_pObject(pObject), m_bAcquired(FALSE) { + if (bInitialLock) + Lock(); +} + +CSingleLock::~CSingleLock() { Unlock(); } + +BOOL CSingleLock::Lock(DWORD dwTimeOut) { + m_bAcquired = m_pObject->Lock(dwTimeOut); + return m_bAcquired; +} + +BOOL CSingleLock::Unlock() { + if (m_bAcquired) + m_bAcquired = !m_pObject->Unlock(); + return !m_bAcquired; +} + +BOOL CSingleLock::Unlock(LONG lCount, LPLONG lPrevCount) { + if (m_bAcquired) + m_bAcquired = !m_pObject->Unlock(lCount, lPrevCount); + return !m_bAcquired; +} + +CMultiLock::CMultiLock(CSyncObject* ppObjects[], DWORD dwCount, BOOL bInitialLock) + : m_objects(ppObjects, ppObjects + dwCount), m_locked(dwCount, false) { + if (bInitialLock) + Lock(); +} + +CMultiLock::~CMultiLock() { Unlock(); } + +DWORD CMultiLock::Lock(DWORD dwTimeOut, BOOL bWaitForAll, DWORD) { + std::vector handles; + std::vector owners; + for (size_t i = 0; i < m_objects.size(); ++i) { + if (m_objects[i]->m_hObject) { + handles.push_back(m_objects[i]->m_hObject); + owners.push_back(i); + } else if (bWaitForAll && !m_locked[i]) { + // Critical sections have no kernel handle; they are entered directly. + m_locked[i] = m_objects[i]->Lock(dwTimeOut) != FALSE; + } + } + if (handles.empty()) + return WAIT_OBJECT_0; + DWORD r = WaitForMultipleObjects(static_cast(handles.size()), handles.data(), bWaitForAll, dwTimeOut); + if (r < WAIT_OBJECT_0 + handles.size()) { + if (bWaitForAll) { + for (size_t owner : owners) + m_locked[owner] = true; + } else { + size_t owner = owners[r - WAIT_OBJECT_0]; + m_locked[owner] = true; + return static_cast(WAIT_OBJECT_0 + owner); + } + } + return r; +} + +BOOL CMultiLock::Unlock() { + for (size_t i = 0; i < m_objects.size(); ++i) + if (m_locked[i]) { + m_objects[i]->Unlock(); + m_locked[i] = false; + } + return TRUE; +} diff --git a/port/mfcwx/src/app.cpp b/port/mfcwx/src/app.cpp new file mode 100644 index 000000000..4217b0439 --- /dev/null +++ b/port/mfcwx/src/app.cpp @@ -0,0 +1,700 @@ +#include "windows_impl.h" + +#include "afxdlgs.h" +#include "mfcwx/app.h" +#include "runtime.h" + +#include +#include +#include +#include +#include + +int __argc = 0; +char** __argv = nullptr; + +namespace mfcwx { + +CWinApp*& AppInstance() { + static CWinApp* app = nullptr; + return app; +} + +namespace { + +class MfcWxApp : public wxApp { +public: + bool OnInit() override; + int OnExit() override; + void OnIdle(wxIdleEvent& e); + void OnFatalException() override {} + +private: + LONG m_idleCount = 0; +}; + +std::string ArgsToCommandLine(int argc, wxChar** argv) { + std::string line; + for (int i = 1; i < argc; ++i) { + if (!line.empty()) + line += ' '; + std::string a = FromWx(wxString(argv[i])); + if (a.find(' ') != std::string::npos) + line += "\"" + a + "\""; + else + line += a; + } + return line; +} + +std::string ChooseLanguage() { + std::vector available = AvailableResourceLanguages(); + auto has = [&](const std::string& code) { + return std::find(available.begin(), available.end(), code) != available.end(); + }; + wxString env; + if (wxGetEnv("MFCWX_LANG", &env) && has(std::string(env.utf8_str()))) + return std::string(env.utf8_str()); + HKEY key = nullptr; + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\mfcwx", 0, KEY_READ, &key) == ERROR_SUCCESS) { + char buf[16] = {0}; + DWORD size = sizeof buf - 1, type = 0; + LONG r = RegQueryValueEx(key, "Language", nullptr, &type, reinterpret_cast(buf), &size); + RegCloseKey(key); + if (r == ERROR_SUCCESS && has(buf)) + return buf; + } + const wxLanguageInfo* info = wxLocale::GetLanguageInfo(wxLocale::GetSystemLanguage()); + std::string code = info ? std::string(info->CanonicalName.Left(2).Lower().utf8_str()) : "en"; + if (code == "sr") + code = "rs"; + return has(code) ? code : "en"; +} + +void PrepareEnvironment(int argc, wxChar** argv) { + SetResourceLanguage(ChooseLanguage().c_str()); + std::string temp = TempDirectory(); + std::string tempApp = AppPath(temp.c_str()); + while (!tempApp.empty() && tempApp.back() == '\\') + tempApp.pop_back(); + wxSetEnv("TEMP", ToWx(tempApp.c_str())); + wxSetEnv("TMP", ToWx(tempApp.c_str())); + if (!wxGetEnv("APPDATA", nullptr)) { + wxString home = wxGetHomeDir(); +#ifdef __APPLE__ + wxString appData = home + "/Library/Application Support"; +#else + wxString appData; + if (!wxGetEnv("XDG_DATA_HOME", &appData) || !appData.StartsWith("/")) + appData = home + "/.local/share"; +#endif + wxFileName::Mkdir(appData, 0700, wxPATH_MKDIR_FULL); + wxSetEnv("APPDATA", ToWx(AppPath(FromWx(appData).c_str()).c_str())); + if (!wxGetEnv("USERPROFILE", nullptr)) + wxSetEnv("USERPROFILE", ToWx(AppPath(FromWx(home).c_str()).c_str())); + } + // The Windows code locates its data files next to the program it finds in the command line. + std::string program = AppPath((GetDataDirectory() + "/CrypTool").c_str()); + std::string commandLine = "\"" + program + "\""; + std::string args = ArgsToCommandLine(argc, argv); + if (!args.empty()) + commandLine += " " + args; + SetCommandLineOverride(commandLine.c_str()); +} + +bool MfcWxApp::OnInit() { + wxInitAllImageHandlers(); + SetAppName("CrypTool"); + SetVendorName("CrypTool"); + CWinApp* app = AppInstance(); + if (!app) + return false; + PrepareEnvironment(argc, argv); + static std::vector ansiArgs; + static std::vector argPointers; + for (int i = 0; i < argc; ++i) + ansiArgs.push_back(FromWx(wxString(argv[i]))); + for (std::string& a : ansiArgs) + argPointers.push_back(&a[0]); + argPointers.push_back(nullptr); + __argc = argc; + __argv = argPointers.data(); + static std::string cmdLine = ArgsToCommandLine(argc, argv); + app->m_lpCmdLine = &cmdLine[0]; + app->m_nCmdShow = SW_SHOWNORMAL; + Bind(wxEVT_IDLE, &MfcWxApp::OnIdle, this); + StartSnapshotTimerFromEnvironment(); + if (!app->InitApplication() || !app->InitInstance()) { + app->ExitInstance(); + return false; + } + return app->m_pMainWnd != nullptr || !wxTopLevelWindows.empty(); +} + +int MfcWxApp::OnExit() { + CWinApp* app = AppInstance(); + return app ? app->ExitInstance() : 0; +} + +void MfcWxApp::OnIdle(wxIdleEvent& e) { + e.Skip(); + PurgeTemporaryGdiWrappers(); + CWinApp* app = AppInstance(); + if (app && app->OnIdle(m_idleCount++)) + e.RequestMore(); + else + m_idleCount = 0; +} + +UINT ButtonsFor(UINT type) { return type & MB_TYPEMASK; } + +} // namespace + +int ShowMessageBox(wxWindow* parent, const char* text, const char* caption, UINT nType) { + if (!parent) + parent = MainWxWindow(); + long style = 0; + UINT buttons = ButtonsFor(nType); + switch (buttons) { + case MB_OKCANCEL: + case MB_RETRYCANCEL: + style = wxOK | wxCANCEL; + break; + case MB_YESNO: + style = wxYES_NO; + break; + case MB_YESNOCANCEL: + case MB_ABORTRETRYIGNORE: + case MB_CANCELTRYCONTINUE: + style = wxYES_NO | wxCANCEL; + break; + default: + style = wxOK; + break; + } + switch (nType & MB_ICONMASK) { + case MB_ICONHAND: style |= wxICON_ERROR; break; + case MB_ICONQUESTION: style |= wxICON_QUESTION; break; + case MB_ICONEXCLAMATION: style |= wxICON_WARNING; break; + case MB_ICONASTERISK: style |= wxICON_INFORMATION; break; + default: break; + } + if ((nType & MB_DEFMASK) == MB_DEFBUTTON2) { + if (style & wxYES_NO) + style |= wxNO_DEFAULT; + else if (style & wxCANCEL) + style |= wxCANCEL_DEFAULT; + } + wxString title = caption ? ToWx(caption) : wxString(ToWx(AfxGetAppName())); + wxMessageDialog dlg(parent, ToWx(text ? text : ""), title, style); + if (buttons == MB_RETRYCANCEL) + dlg.SetOKCancelLabels(_("&Retry"), _("Cancel")); + else if (buttons == MB_ABORTRETRYIGNORE) + dlg.SetYesNoCancelLabels(_("&Abort"), _("&Retry"), _("&Ignore")); + else if (buttons == MB_CANCELTRYCONTINUE) + dlg.SetYesNoCancelLabels(_("&Try Again"), _("&Continue"), _("Cancel")); + int r = dlg.ShowModal(); + switch (buttons) { + case MB_OKCANCEL: + return r == wxID_OK ? IDOK : IDCANCEL; + case MB_RETRYCANCEL: + return r == wxID_OK ? IDRETRY : IDCANCEL; + case MB_YESNO: + return r == wxID_YES ? IDYES : IDNO; + case MB_YESNOCANCEL: + return r == wxID_YES ? IDYES : r == wxID_NO ? IDNO : IDCANCEL; + case MB_ABORTRETRYIGNORE: + return r == wxID_YES ? IDABORT : r == wxID_NO ? IDRETRY : IDIGNORE; + case MB_CANCELTRYCONTINUE: + return r == wxID_YES ? IDTRYAGAIN : r == wxID_NO ? IDCONTINUE : IDCANCEL; + default: + return IDOK; + } +} + +BOOL ShowContextHelp(CWnd* pWnd, HELPINFO*) { + if (!pWnd || !pWnd->m_hWnd) + return FALSE; + wxWindow* top = wxGetTopLevelParent(pWnd->GetWx()); + CWnd* p = PermanentWnd(top); + if (p) + p->SendMessage(WM_COMMAND, ID_HELP, 0); + return TRUE; +} + +} // namespace mfcwx + +using namespace mfcwx; + +wxIMPLEMENT_APP_NO_MAIN(MfcWxApp); + +int main(int argc, char** argv) { return wxEntry(argc, argv); } + +// --------------------------------------------------------------------------------------------- +// CWinApp + +IMPLEMENT_DYNAMIC(CWinApp, CWinThread) + +BEGIN_MESSAGE_MAP(CWinApp, CWinThread) + ON_COMMAND_EX_RANGE(ID_FILE_MRU_FILE1, ID_FILE_MRU_FILE16, &CWinApp::OnOpenRecentFile) + ON_UPDATE_COMMAND_UI(ID_FILE_MRU_FILE1, &CWinApp::OnUpdateRecentFileMenu) +END_MESSAGE_MAP() + +CWinApp::CWinApp(const char* lpszAppName) + : m_hInstance(reinterpret_cast(static_cast(0x400000))), m_hPrevInstance(nullptr), + m_lpCmdLine(nullptr), m_nCmdShow(SW_SHOWNORMAL), m_pszAppName(lpszAppName), m_pszRegistryKey(nullptr), + m_pszExeName("CrypTool"), m_pszHelpFilePath(nullptr), m_pszProfileName(nullptr), m_pRecentFileList(nullptr), + m_bHelpMode(FALSE), m_nWaitCursorCount(0), m_hcurWaitCursorRestore(nullptr), m_eHelpType(0) { + AppInstance() = this; +} + +CWinApp::~CWinApp() { + for (CDocTemplate* t : m_templates) + delete t; + m_templates.clear(); + delete m_pRecentFileList; + if (AppInstance() == this) + AppInstance() = nullptr; +} + +BOOL CWinApp::InitApplication() { return TRUE; } +BOOL CWinApp::InitInstance() { return TRUE; } + +int CWinApp::ExitInstance() { + if (m_pRecentFileList) + m_pRecentFileList->WriteList(); + return 0; +} + +int CWinApp::Run() { return wxTheApp ? wxTheApp->MainLoop() : 0; } + +BOOL CWinApp::OnIdle(LONG lCount) { + if (lCount <= 0) { + if (m_pMainWnd && m_pMainWnd->m_hWnd && m_pMainWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { + auto* frame = static_cast(m_pMainWnd); + std::vector bars = frame->m_listControlBars; + for (CControlBar* bar : bars) + bar->OnUpdateCmdUI(frame, FALSE); + } + for (CDocTemplate* t : m_templates) { + POSITION pos = t->GetFirstDocPosition(); + while (pos) + if (CDocument* d = t->GetNextDoc(pos)) + d->OnIdle(); + } + } + return FALSE; +} + +void CWinApp::AddDocTemplate(CDocTemplate* pTemplate) { m_templates.push_back(pTemplate); } + +POSITION CWinApp::GetFirstDocTemplatePosition() const { + return m_templates.empty() ? nullptr : reinterpret_cast(static_cast(1)); +} + +CDocTemplate* CWinApp::GetNextDocTemplate(POSITION& pos) const { + size_t i = static_cast(reinterpret_cast(pos)) - 1; + CDocTemplate* t = i < m_templates.size() ? m_templates[i] : nullptr; + pos = i + 1 < m_templates.size() ? reinterpret_cast(static_cast(i + 2)) : nullptr; + return t; +} + +CDocument* CWinApp::OpenDocumentFile(const char* lpszFileName) { + CDocTemplate* best = nullptr; + CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt; + CDocument* open = nullptr; + for (CDocTemplate* t : m_templates) { + CDocument* match = nullptr; + CDocTemplate::Confidence c = t->MatchDocType(lpszFileName, match); + if (c > bestMatch) { + bestMatch = c; + best = t; + } + if (c == CDocTemplate::yesAlreadyOpen) { + open = match; + break; + } + } + if (open) { + POSITION pos = open->GetFirstViewPosition(); + if (CView* v = pos ? open->GetNextView(pos) : nullptr) + if (CFrameWnd* f = v->GetParentFrame()) + f->ActivateFrame(); + return open; + } + return best ? best->OpenDocumentFile(lpszFileName) : nullptr; +} + +void CWinApp::AddToRecentFileList(const char* lpszPathName) { + if (m_pRecentFileList) + m_pRecentFileList->Add(lpszPathName); +} + +BOOL CWinApp::SaveAllModified() { + for (CDocTemplate* t : m_templates) + if (!t->SaveAllModified()) + return FALSE; + return TRUE; +} + +void CWinApp::CloseAllDocuments(BOOL bEndSession) { + for (CDocTemplate* t : m_templates) + t->CloseAllDocuments(bEndSession); +} + +int CWinApp::DoMessageBox(const char* lpszPrompt, UINT nType, UINT) { + return ShowMessageBox(nullptr, lpszPrompt, m_pszAppName, nType); +} + +void CWinApp::DoWaitCursor(int nCode) { + OnMain([&] { + if (nCode > 0) { + ++m_nWaitCursorCount; + wxBeginBusyCursor(); + } else if (nCode < 0 && m_nWaitCursorCount > 0) { + --m_nWaitCursorCount; + if (wxIsBusy()) + wxEndBusyCursor(); + } + }); +} + +BOOL CWinApp::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, + CDocTemplate* pTemplate) { + CString filter; + std::vector templates; + if (pTemplate) + templates.push_back(pTemplate); + else + templates = m_templates; + CString defExt; + for (CDocTemplate* t : templates) { + CString name, ext; + if (t->GetDocString(name, CDocTemplate::filterName) && t->GetDocString(ext, CDocTemplate::filterExt) && + !name.IsEmpty() && !ext.IsEmpty()) { + filter += name + "|*" + ext + "|"; + if (defExt.IsEmpty()) + defExt = ext.Mid(1); + } + } + CString all; + if (!all.LoadString(AFX_IDS_ALLFILTER)) + all = "All Files (*.*)"; + filter += all + "|*|"; + CFileDialog dlg(bOpenFileDialog, bOpenFileDialog ? nullptr : defExt.GetString(), fileName, + lFlags | OFN_HIDEREADONLY | (bOpenFileDialog ? OFN_FILEMUSTEXIST : OFN_OVERWRITEPROMPT), filter); + dlg.m_strTitle.LoadString(nIDSTitle); + if (dlg.DoModal() != IDOK) + return FALSE; + fileName = dlg.GetPathName(); + return TRUE; +} + +BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo) { + switch (rCmdInfo.m_nShellCommand) { + case CCommandLineInfo::FileNew: + OnCmdMsg(ID_FILE_NEW, 0, nullptr, nullptr); + return TRUE; + case CCommandLineInfo::FileOpen: + return OpenDocumentFile(rCmdInfo.m_strFileName) != nullptr; + default: + return TRUE; + } +} + +void CWinApp::ParseCommandLine(CCommandLineInfo& rCmdInfo) { + if (!wxTheApp) + return; + for (int i = 1; i < wxTheApp->argc; ++i) { + std::string a = FromWx(wxTheApp->argv[i]); + if (a.compare(0, 4, "-psn") == 0) + continue; + bool flag = !a.empty() && (a[0] == '-' || a[0] == '/') && a.find('.') == std::string::npos; + std::string param = flag ? a.substr(1) : AppPath(wxTheApp->argv[i].utf8_str()); + rCmdInfo.ParseParam(param.c_str(), flag, i == wxTheApp->argc - 1); + } +} + +HCURSOR CWinApp::LoadCursor(const char* lpszResourceName) const { return ::LoadCursor(m_hInstance, lpszResourceName); } +HCURSOR CWinApp::LoadCursor(UINT nIDResource) const { return ::LoadCursor(m_hInstance, MAKEINTRESOURCE(nIDResource)); } +HCURSOR CWinApp::LoadStandardCursor(const char* lpszCursorName) const { return ::LoadCursor(nullptr, lpszCursorName); } +HCURSOR CWinApp::LoadOEMCursor(UINT nIDCursor) const { return ::LoadCursor(nullptr, MAKEINTRESOURCE(nIDCursor)); } +HICON CWinApp::LoadIcon(const char* lpszResourceName) const { return ::LoadIcon(m_hInstance, lpszResourceName); } +HICON CWinApp::LoadIcon(UINT nIDResource) const { return ::LoadIcon(m_hInstance, MAKEINTRESOURCE(nIDResource)); } +HICON CWinApp::LoadStandardIcon(const char* lpszIconName) const { return ::LoadIcon(nullptr, lpszIconName); } +HICON CWinApp::LoadOEMIcon(UINT nIDIcon) const { return ::LoadIcon(nullptr, MAKEINTRESOURCE(nIDIcon)); } + +namespace { + +CString SectionKey(const CWinApp* app, const char* section) { + CString key = "Software\\"; + key += app->m_pszRegistryKey && *app->m_pszRegistryKey ? app->m_pszRegistryKey : "CrypTool"; + key += "\\"; + key += app->m_pszAppName ? app->m_pszAppName : "CrypTool"; + if (section && *section) { + key += "\\"; + key += section; + } + return key; +} + +} // namespace + +UINT CWinApp::GetProfileInt(const char* lpszSection, const char* lpszEntry, int nDefault) { + HKEY key = nullptr; + if (RegOpenKeyEx(HKEY_CURRENT_USER, SectionKey(this, lpszSection), 0, KEY_READ, &key) != ERROR_SUCCESS) + return static_cast(nDefault); + DWORD value = 0, size = sizeof value, type = 0; + LONG r = RegQueryValueEx(key, lpszEntry, nullptr, &type, reinterpret_cast(&value), &size); + RegCloseKey(key); + return r == ERROR_SUCCESS && type == REG_DWORD ? value : static_cast(nDefault); +} + +BOOL CWinApp::WriteProfileInt(const char* lpszSection, const char* lpszEntry, int nValue) { + HKEY key = nullptr; + if (RegCreateKeyEx(HKEY_CURRENT_USER, SectionKey(this, lpszSection), 0, nullptr, 0, KEY_WRITE, nullptr, &key, + nullptr) != ERROR_SUCCESS) + return FALSE; + DWORD v = static_cast(nValue); + LONG r = RegSetValueEx(key, lpszEntry, 0, REG_DWORD, reinterpret_cast(&v), sizeof v); + RegCloseKey(key); + return r == ERROR_SUCCESS; +} + +CString CWinApp::GetProfileString(const char* lpszSection, const char* lpszEntry, const char* lpszDefault) { + HKEY key = nullptr; + CString def = lpszDefault ? lpszDefault : ""; + if (RegOpenKeyEx(HKEY_CURRENT_USER, SectionKey(this, lpszSection), 0, KEY_READ, &key) != ERROR_SUCCESS) + return def; + DWORD size = 0, type = 0; + if (RegQueryValueEx(key, lpszEntry, nullptr, &type, nullptr, &size) != ERROR_SUCCESS || type != REG_SZ) { + RegCloseKey(key); + return def; + } + CString value; + RegQueryValueEx(key, lpszEntry, nullptr, &type, reinterpret_cast(value.GetBuffer(static_cast(size) + 1)), &size); + value.ReleaseBuffer(); + RegCloseKey(key); + return value; +} + +BOOL CWinApp::WriteProfileString(const char* lpszSection, const char* lpszEntry, const char* lpszValue) { + HKEY key = nullptr; + if (RegCreateKeyEx(HKEY_CURRENT_USER, SectionKey(this, lpszSection), 0, nullptr, 0, KEY_WRITE, nullptr, &key, + nullptr) != ERROR_SUCCESS) + return FALSE; + LONG r; + if (!lpszEntry) + r = ERROR_SUCCESS; + else if (!lpszValue) + r = RegDeleteValue(key, lpszEntry); + else + r = RegSetValueEx(key, lpszEntry, 0, REG_SZ, reinterpret_cast(lpszValue), + static_cast(strlen(lpszValue) + 1)); + RegCloseKey(key); + return r == ERROR_SUCCESS; +} + +BOOL CWinApp::GetProfileBinary(const char* lpszSection, const char* lpszEntry, LPBYTE* ppData, UINT* pBytes) { + *ppData = nullptr; + *pBytes = 0; + HKEY key = nullptr; + if (RegOpenKeyEx(HKEY_CURRENT_USER, SectionKey(this, lpszSection), 0, KEY_READ, &key) != ERROR_SUCCESS) + return FALSE; + DWORD size = 0, type = 0; + if (RegQueryValueEx(key, lpszEntry, nullptr, &type, nullptr, &size) != ERROR_SUCCESS) { + RegCloseKey(key); + return FALSE; + } + *ppData = new BYTE[size ? size : 1]; + RegQueryValueEx(key, lpszEntry, nullptr, &type, *ppData, &size); + *pBytes = size; + RegCloseKey(key); + return TRUE; +} + +BOOL CWinApp::WriteProfileBinary(const char* lpszSection, const char* lpszEntry, LPBYTE pData, UINT nBytes) { + HKEY key = nullptr; + if (RegCreateKeyEx(HKEY_CURRENT_USER, SectionKey(this, lpszSection), 0, nullptr, 0, KEY_WRITE, nullptr, &key, + nullptr) != ERROR_SUCCESS) + return FALSE; + LONG r = RegSetValueEx(key, lpszEntry, 0, REG_BINARY, pData, nBytes); + RegCloseKey(key); + return r == ERROR_SUCCESS; +} + +void CWinApp::SetRegistryKey(const char* lpszRegistryKey) { + m_pszRegistryKey = strdup(lpszRegistryKey && *lpszRegistryKey ? lpszRegistryKey : "CrypTool"); +} + +void CWinApp::SetRegistryKey(UINT nIDRegistryKey) { + CString key; + key.LoadString(nIDRegistryKey); + SetRegistryKey(key); +} + +void CWinApp::LoadStdProfileSettings(UINT nMaxMRU) { + if (nMaxMRU && !m_pRecentFileList) { + m_pRecentFileList = new CRecentFileList(0, "Recent File List", "File%d", static_cast(nMaxMRU)); + m_pRecentFileList->ReadList(); + } +} + +void CWinApp::HideApplication() { + if (m_pMainWnd) + m_pMainWnd->ShowWindow(SW_HIDE); +} + +void CWinApp::OnFileNew() { + if (!m_templates.empty()) + m_templates.front()->OpenDocumentFile(nullptr); +} + +void CWinApp::OnFileOpen() { + CString name; + if (DoPromptFileName(name, AFX_IDS_OPENFILE, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, nullptr)) + OpenDocumentFile(name); +} + +void CWinApp::OnFilePrintSetup() {} + +void CWinApp::OnAppExit() { + if (m_pMainWnd) + m_pMainWnd->SendMessage(WM_CLOSE); + else if (wxTheApp) + wxTheApp->ExitMainLoop(); +} + +void CWinApp::OnHelp() { WinHelpInternal(0, HELP_FINDER); } +void CWinApp::OnHelpFinder() { WinHelpInternal(0, HELP_FINDER); } +void CWinApp::OnHelpIndex() { WinHelpInternal(0, HELP_INDEX); } +void CWinApp::OnContextHelp() { WinHelpInternal(0, HELP_FINDER); } +void CWinApp::OnHelpUsing() { WinHelpInternal(0, HELP_HELPONHELP); } + +BOOL CWinApp::OnOpenRecentFile(UINT nID) { + if (!m_pRecentFileList) + return FALSE; + int index = static_cast(nID - ID_FILE_MRU_FILE1); + if (index < 0 || index >= m_pRecentFileList->GetSize()) + return FALSE; + CString path = (*m_pRecentFileList)[index]; + if (path.IsEmpty()) + return FALSE; + if (!OpenDocumentFile(path)) + m_pRecentFileList->Remove(index); + return TRUE; +} + +void CWinApp::OnUpdateRecentFileMenu(CCmdUI* pCmdUI) { + if (m_pRecentFileList) + m_pRecentFileList->UpdateMenu(pCmdUI); + else + pCmdUI->Enable(FALSE); +} + +// --------------------------------------------------------------------------------------------- +// Global helpers + +CWinApp* AFXAPI AfxGetApp() { return AppInstance(); } + +CWnd* AFXAPI AfxGetMainWnd() { + CWinApp* app = AppInstance(); + return app ? app->m_pMainWnd : nullptr; +} + +HINSTANCE AFXAPI AfxGetInstanceHandle() { + CWinApp* app = AppInstance(); + return app ? app->m_hInstance : reinterpret_cast(static_cast(0x400000)); +} + +HINSTANCE AFXAPI AfxGetResourceHandle() { return AfxGetInstanceHandle(); } +void AFXAPI AfxSetResourceHandle(HINSTANCE) {} +HINSTANCE AFXAPI AfxFindResourceHandle(const char*, const char*) { return AfxGetInstanceHandle(); } + +const char* AFXAPI AfxGetAppName() { + CWinApp* app = AppInstance(); + return app && app->m_pszAppName ? app->m_pszAppName : "CrypTool"; +} + +int AFXAPI AfxMessageBox(const char* lpszText, UINT nType, UINT nIDHelp) { + CWinApp* app = AppInstance(); + return OnMain([&]() -> int { + if (app) + return app->DoMessageBox(lpszText, nType, nIDHelp); + return ShowMessageBox(nullptr, lpszText, nullptr, nType); + }); +} + +int AFXAPI AfxMessageBox(UINT nIDPrompt, UINT nType, UINT nIDHelp) { + CString text; + text.LoadString(nIDPrompt); + return AfxMessageBox(text, nType, nIDHelp == static_cast(-1) ? nIDPrompt : nIDHelp); +} + +void AFXAPI AfxFormatString1(CString& rString, UINT nIDS, const char* lpsz1) { + rString.LoadString(nIDS); + rString.Replace("%1", lpsz1 ? lpsz1 : ""); +} + +void AFXAPI AfxFormatString2(CString& rString, UINT nIDS, const char* lpsz1, const char* lpsz2) { + rString.LoadString(nIDS); + CString result; + const char* p = rString; + while (*p) { + if (p[0] == '%' && (p[1] == '1' || p[1] == '2')) { + result += p[1] == '1' ? (lpsz1 ? lpsz1 : "") : (lpsz2 ? lpsz2 : ""); + p += 2; + } else { + result += *p++; + } + } + rString = result; +} + +BOOL AFXAPI AfxExtractSubString(CString& rString, const char* lpszFullString, int iSubString, char chSep) { + rString.Empty(); + if (!lpszFullString) + return FALSE; + while (iSubString--) { + lpszFullString = strchr(lpszFullString, chSep); + if (!lpszFullString) + return FALSE; + ++lpszFullString; + } + const char* end = strchr(lpszFullString, chSep); + int len = end ? static_cast(end - lpszFullString) : static_cast(strlen(lpszFullString)); + rString = CString(lpszFullString, len); + return TRUE; +} + +const char* AFXAPI AfxRegisterWndClass(UINT, HCURSOR, HBRUSH, HICON) { return "AfxWnd"; } +BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass) { return RegisterClass(lpWndClass) != 0; } +BOOL AFXAPI AfxInitRichEdit() { return TRUE; } +BOOL AFXAPI AfxInitRichEdit2() { return TRUE; } +BOOL AFXAPI AfxOleInit() { return TRUE; } +void AFXAPI AfxEnableControlContainer() {} +BOOL AFXAPI AfxSocketInit() { return TRUE; } +void AFXAPI AfxInitCommonControls() {} +BOOL AFXAPI AfxCheckMemory() { return TRUE; } + +void AFXAPI AfxGetModuleShortFileName(HINSTANCE, CString& strShortName) { + char buf[_MAX_PATH]; + GetModuleFileName(nullptr, buf, sizeof buf); + strShortName = buf; +} + +LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND, UINT nMsg, WPARAM wParam, LPARAM lParam) { + return pWnd ? pWnd->WindowProc(nMsg, wParam, lParam) : 0; +} + +CWaitCursor::CWaitCursor() { + if (CWinApp* app = AfxGetApp()) + app->DoWaitCursor(1); +} + +CWaitCursor::~CWaitCursor() { + if (CWinApp* app = AfxGetApp()) + app->DoWaitCursor(-1); +} + +BOOL CWinApp::OnDDECommand(LPTSTR) { return FALSE; } diff --git a/port/mfcwx/src/bridge.h b/port/mfcwx/src/bridge.h new file mode 100644 index 000000000..8911be22b --- /dev/null +++ b/port/mfcwx/src/bridge.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "afxwin.h" +#include "mfcwx/codepage.h" + +namespace mfcwx { + +wxString ToWx(const char* s, int length = -1); +inline wxString ToWx(const CString& s) { return ToWx(s.GetString(), s.GetLength()); } +std::string FromWx(const wxString& s); +inline CString CStr(const wxString& s) { std::string a = FromWx(s); return CString(a.data(), static_cast(a.size())); } +inline wxString NativePathWx(const char* path) { return wxString::FromUTF8(NativePath(path)); } + +} // namespace mfcwx diff --git a/port/mfcwx/src/cmdtarget.cpp b/port/mfcwx/src/cmdtarget.cpp new file mode 100644 index 000000000..501b20546 --- /dev/null +++ b/port/mfcwx/src/cmdtarget.cpp @@ -0,0 +1,154 @@ +#include "internal.h" + +// --------------------------------------------------------------------------------------------- +// CCmdTarget and message map lookup + +CRuntimeClass CCmdTarget::classCCmdTarget = {"CCmdTarget", sizeof(CCmdTarget), 0xFFFF, nullptr, + &CObject::GetThisClass, nullptr}; +static AFX_CLASSINIT _init_CCmdTarget(&CCmdTarget::classCCmdTarget); +CRuntimeClass* CCmdTarget::GetThisClass() { return &CCmdTarget::classCCmdTarget; } +CRuntimeClass* CCmdTarget::GetRuntimeClass() const { return &CCmdTarget::classCCmdTarget; } + +const AFX_MSGMAP* CCmdTarget::GetThisMessageMap() { + static const AFX_MSGMAP_ENTRY entries[] = {{0, 0, 0, 0, AfxSig_end, nullptr}}; + static const AFX_MSGMAP map = {nullptr, &entries[0]}; + return ↦ +} + +const AFX_MSGMAP* CCmdTarget::GetMessageMap() const { return GetThisMessageMap(); } + +const AFX_MSGMAP_ENTRY* CCmdTarget::FindMessageEntry(UINT nMessage, UINT nCode, UINT nID) const { + for (const AFX_MSGMAP* map = GetMessageMap(); map; map = map->pfnGetBaseMap ? map->pfnGetBaseMap() : nullptr) { + for (const AFX_MSGMAP_ENTRY* e = map->lpEntries; e->nSig != AfxSig_end; ++e) { + if (e->nMessage == 0xC000) { + if (nMessage >= 0xC000 && *reinterpret_cast(e->nSig) == nMessage) + return e; + continue; + } + if (e->nMessage != nMessage || e->nCode != nCode) + continue; + if (nMessage == WM_COMMAND || nMessage == WM_NOTIFY) { + if (nID >= e->nID && nID <= e->nLastID) + return e; + } else { + return e; + } + } + if (map->pfnGetBaseMap == nullptr || map->pfnGetBaseMap() == map) + break; + } + return nullptr; +} + +struct AFX_NOTIFY { + LRESULT* pResult; + NMHDR* pNMHDR; +}; + +BOOL CCmdTarget::DispatchCommand(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { + UINT message = WM_COMMAND; + UINT code = static_cast(nCode); + if (static_cast(HIWORD(static_cast(nCode))) == WM_NOTIFY && nCode != static_cast(CN_UPDATE_COMMAND_UI)) { + message = WM_NOTIFY; + code = static_cast(static_cast(LOWORD(static_cast(nCode)))); + } + const AFX_MSGMAP_ENTRY* e = FindMessageEntry(message, code, nID); + if (!e && message == WM_NOTIFY) + e = FindMessageEntry(message, static_cast(LOWORD(static_cast(nCode))), nID); + if (!e) + return FALSE; + if (pHandlerInfo) { + pHandlerInfo->pTarget = this; + pHandlerInfo->pmf = e->pfn; + return TRUE; + } + switch (e->nSig) { + case AfxSigCmd_v: + (this->*e->pfn)(); + return TRUE; + case AfxSigCmd_b: + return (this->*reinterpret_cast(e->pfn))(); + case AfxSigCmd_RANGE: + (this->*reinterpret_cast(e->pfn))(nID); + return TRUE; + case AfxSigCmd_EX: + return (this->*reinterpret_cast(e->pfn))(nID); + case AfxSigCmdUI: { + auto* pCmdUI = static_cast(pExtra); + pCmdUI->m_bContinueRouting = FALSE; + (this->*reinterpret_cast(e->pfn))(pCmdUI); + return !pCmdUI->m_bContinueRouting; + } + case AfxSigNotify_v: { + auto* notify = static_cast(pExtra); + (this->*reinterpret_cast(e->pfn))(notify->pNMHDR, notify->pResult); + return TRUE; + } + case AfxSigNotify_b: { + auto* notify = static_cast(pExtra); + return (this->*reinterpret_cast(e->pfn))(notify->pNMHDR, + notify->pResult); + } + case AfxSigNotify_RANGE: { + auto* notify = static_cast(pExtra); + (this->*reinterpret_cast(e->pfn))(nID, notify->pNMHDR, + notify->pResult); + return TRUE; + } + case AfxSigNotify_EX: { + auto* notify = static_cast(pExtra); + return (this->*reinterpret_cast(e->pfn))( + nID, notify->pNMHDR, notify->pResult); + } + default: + return FALSE; + } +} + +BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { + return DispatchCommand(nID, nCode, pExtra, pHandlerInfo); +} + +void CCmdTarget::BeginWaitCursor() { wxBeginBusyCursor(); } +void CCmdTarget::EndWaitCursor() { + if (wxIsBusy()) + wxEndBusyCursor(); +} +void CCmdTarget::RestoreWaitCursor() {} + +// --------------------------------------------------------------------------------------------- +// CCmdUI + +CCmdUI::CCmdUI() + : m_nID(0), m_nIndex(0), m_pMenu(nullptr), m_pSubMenu(nullptr), m_pParentMenu(nullptr), m_pOther(nullptr), + m_bEnableChanged(FALSE), m_bContinueRouting(FALSE), m_nIndexMax(0), m_enabled(true), m_check(0), + m_checkSet(false), m_textSet(false) {} + +void CCmdUI::Enable(BOOL bOn) { + m_enabled = bOn != FALSE; + m_bEnableChanged = TRUE; +} + +void CCmdUI::SetCheck(int nCheck) { + m_check = nCheck; + m_checkSet = true; +} + +void CCmdUI::SetRadio(BOOL bOn) { SetCheck(bOn ? 1 : 0); } + +void CCmdUI::SetText(const char* lpszText) { + m_text = lpszText; + m_textSet = true; +} + +BOOL CCmdUI::DoUpdate(CCmdTarget* pTarget, BOOL bDisableIfNoHndler) { + m_bEnableChanged = FALSE; + BOOL handled = pTarget->OnCmdMsg(m_nID, static_cast(CN_UPDATE_COMMAND_UI), this, nullptr); + if (bDisableIfNoHndler && !m_bEnableChanged) { + AFX_CMDHANDLERINFO info; + info.pTarget = nullptr; + BOOL hasHandler = pTarget->OnCmdMsg(m_nID, CN_COMMAND, this, &info); + Enable(hasHandler); + } + return handled; +} diff --git a/port/mfcwx/src/codepage.cpp b/port/mfcwx/src/codepage.cpp new file mode 100644 index 000000000..bc54273de --- /dev/null +++ b/port/mfcwx/src/codepage.cpp @@ -0,0 +1,188 @@ +#include "bridge.h" + +#include +#include +#include +#include +#include +#include + +namespace mfcwx { + +extern const uint16_t kCp1250High[128]; +extern const uint16_t kCp1251High[128]; +extern const uint16_t kCp1252High[128]; +extern const uint16_t kCp1253High[128]; +extern const uint16_t kCp1254High[128]; +extern const uint16_t kCp1257High[128]; + +namespace { + +struct CodePage { + int cp; + const uint16_t* high; + std::unordered_map reverse; +}; + +CodePage* MakeCodePage(int cp, const uint16_t* high) { + auto* page = new CodePage{cp, high, {}}; + for (int i = 0; i < 128; ++i) + page->reverse.emplace(static_cast(high[i]), static_cast(0x80 + i)); + return page; +} + +CodePage* LookupCodePage(int cp) { + static CodePage* const pages[] = { + MakeCodePage(1250, kCp1250High), MakeCodePage(1251, kCp1251High), MakeCodePage(1252, kCp1252High), + MakeCodePage(1253, kCp1253High), MakeCodePage(1254, kCp1254High), MakeCodePage(1257, kCp1257High), + }; + for (CodePage* page : pages) + if (page->cp == cp) + return page; + return pages[2]; +} + +std::atomic g_page{nullptr}; + +CodePage* Current() { + CodePage* page = g_page.load(std::memory_order_acquire); + if (!page) { + page = LookupCodePage(1252); + g_page.store(page, std::memory_order_release); + } + return page; +} + +} // namespace + +void SetAnsiCodePage(int cp) { g_page.store(LookupCodePage(cp), std::memory_order_release); } + +int GetAnsiCodePage() { return Current()->cp; } + +wchar_t AnsiToUnicode(unsigned char ch) { + if (ch < 0x80) + return ch; + return static_cast(Current()->high[ch - 0x80]); +} + +bool UnicodeToAnsi(wchar_t ch, char& out) { + if (static_cast(ch) < 0x80) { + out = static_cast(ch); + return true; + } + const auto& reverse = Current()->reverse; + auto it = reverse.find(ch); + if (it == reverse.end()) { + out = '?'; + return false; + } + out = it->second; + return true; +} + +wxString ToWx(const char* s, int length) { + if (!s) + return wxString(); + if (length < 0) + length = static_cast(strlen(s)); + std::wstring w; + w.reserve(length); + for (int i = 0; i < length; ++i) + w.push_back(AnsiToUnicode(static_cast(s[i]))); + return wxString(w); +} + +std::string FromWx(const wxString& s) { + std::string out; + out.reserve(s.length()); + for (wxString::const_iterator it = s.begin(); it != s.end(); ++it) { + char ch; + UnicodeToAnsi(static_cast((*it).GetValue()), ch); + out.push_back(ch); + } + return out; +} + +std::string AnsiToUtf8(const char* s, int length) { return std::string(ToWx(s, length).utf8_str()); } + +std::string AppPath(const char* nativePath) { + if (!nativePath) + return std::string(); + std::string p = Utf8ToAnsi(nativePath); + for (char& ch : p) + if (ch == '/') + ch = '\\'; + return p; +} + +std::string Utf8ToAnsi(const char* utf8) { + if (!utf8) + return std::string(); + return FromWx(wxString::FromUTF8(utf8)); +} + +namespace { + +bool Exists(const std::string& p) { + struct stat st; + return stat(p.c_str(), &st) == 0; +} + +// Windows file names are case-insensitive; find the spelling used on disk, component by component. +std::string ResolveCase(const std::string& path) { + if (path.empty() || Exists(path)) + return path; + std::string resolved = path[0] == '/' ? "/" : ""; + size_t pos = path[0] == '/' ? 1 : 0; + while (pos <= path.size()) { + size_t next = path.find('/', pos); + std::string part = path.substr(pos, next == std::string::npos ? std::string::npos : next - pos); + pos = next == std::string::npos ? path.size() + 1 : next + 1; + if (part.empty()) + continue; + std::string candidate = resolved + part; + if (!Exists(candidate)) { + DIR* dir = opendir(resolved.empty() ? "." : resolved.c_str()); + if (!dir) + return path; + std::string match; + while (dirent* e = readdir(dir)) + if (strcasecmp(e->d_name, part.c_str()) == 0) { + match = e->d_name; + break; + } + closedir(dir); + if (match.empty()) + return path; + candidate = resolved + match; + } + resolved = candidate; + if (pos <= path.size()) + resolved += '/'; + } + return resolved; +} + +} // namespace + +std::string NativePath(const char* path) { + if (!path) + return std::string(); + std::string p(path); + for (char& ch : p) + if (ch == '\\') + ch = '/'; + if (p.size() >= 2 && p[1] == ':' && ((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z'))) + p.erase(0, 2); + bool ascii = true; + for (unsigned char ch : p) + if (ch >= 0x80) { + ascii = false; + break; + } + if (!ascii) + p = std::string(ToWx(p.c_str()).utf8_str()); + return ResolveCase(p); +} + +} // namespace mfcwx diff --git a/port/mfcwx/src/codepage_tables.cpp b/port/mfcwx/src/codepage_tables.cpp new file mode 100644 index 000000000..fd4a161a5 --- /dev/null +++ b/port/mfcwx/src/codepage_tables.cpp @@ -0,0 +1,128 @@ +// Generated from Python codecs: upper half (0x80-0xFF) of Windows code pages. +#include + +namespace mfcwx { + +// Namespace-scope const arrays have internal linkage unless declared extern. +extern const uint16_t kCp1250High[128]; +extern const uint16_t kCp1251High[128]; +extern const uint16_t kCp1252High[128]; +extern const uint16_t kCp1253High[128]; +extern const uint16_t kCp1254High[128]; +extern const uint16_t kCp1257High[128]; + +const uint16_t kCp1250High[128] = { + 0x20AC, 0x0081, 0x201A, 0x0083, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0088, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0098, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9, +}; + +const uint16_t kCp1251High[128] = { + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0098, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, +}; + +const uint16_t kCp1252High[128] = { + 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F, + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, +}; + +const uint16_t kCp1253High[128] = { + 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0088, 0x2030, 0x008A, 0x2039, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0098, 0x2122, 0x009A, 0x203A, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x00D2, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x00FF, +}; + +const uint16_t kCp1254High[128] = { + 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x008E, 0x008F, + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x009E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF, +}; + +const uint16_t kCp1257High[128] = { + 0x20AC, 0x0081, 0x201A, 0x0083, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0088, 0x2030, 0x008A, 0x2039, 0x008C, 0x00A8, 0x02C7, 0x00B8, + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0098, 0x2122, 0x009A, 0x203A, 0x009C, 0x00AF, 0x02DB, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9, +}; + +} // namespace mfcwx diff --git a/port/mfcwx/src/controls.cpp b/port/mfcwx/src/controls.cpp new file mode 100644 index 000000000..c112bde47 --- /dev/null +++ b/port/mfcwx/src/controls.cpp @@ -0,0 +1,2541 @@ +#include "controls_internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace mfcwx { + +// --------------------------------------------------------------------------------------------- +// Custom-drawn window used for views, owner-drawn controls, unknown window classes and statics +// that the application paints itself. + +class GenericWindow : public wxWindow { +public: + GenericWindow(wxWindow* parent, int id, const wxPoint& pos, const wxSize& size, long style) + : wxWindow(parent, id, pos, size, style | wxFULL_REPAINT_ON_RESIZE) {} + bool AcceptsFocus() const override { + WindowState* st = GetState(const_cast(this)); + return st && (st->style & WS_TABSTOP) != 0 ? wxWindow::AcceptsFocus() : HasFlag(wxWANTS_CHARS); + } + bool AcceptsFocusFromKeyboard() const override { + WindowState* st = GetState(const_cast(this)); + return st && (st->style & WS_TABSTOP) != 0; + } +}; + +namespace { + +struct EditExtra { + int limit = 0; + bool modified = false; + char passwordChar = 0; +}; + +struct RangeExtra { + int minValue = 0; + int maxValue = 100; + int step = 10; + int pos = 0; + bool inverted = false; + int page = 0; + int selStart = 0; + int selEnd = 0; +}; + +struct ButtonExtra { + bool pushed = false; + bool hover = false; + HBITMAP image = nullptr; + HICON icon = nullptr; +}; + +wxString AnsiText(const char* s) { return ToWx(s ? s : ""); } + +bool IsMultilineEdit(const WindowState& st) { + return (st.kind == ControlKind::Edit || st.kind == ControlKind::RichEdit) && (st.style & ES_MULTILINE); +} + +wxTextCtrl* AsText(wxWindow* w) { return wxDynamicCast(w, wxTextCtrl); } + +// Windows multiline edits count "\r\n" as two characters; wx counts one. +long WinToWxPos(wxTextCtrl* t, const WindowState& st, long winPos) { + if (!IsMultilineEdit(st) || winPos <= 0) + return winPos; + wxString v = t->GetValue(); + long wxPos = 0; + long win = 0; + for (wxString::const_iterator it = v.begin(); it != v.end() && win < winPos; ++it) { + win += *it == '\n' ? 2 : 1; + if (win <= winPos) + ++wxPos; + } + return wxPos; +} + +long WxToWinPos(wxTextCtrl* t, const WindowState& st, long wxPos) { + if (!IsMultilineEdit(st) || wxPos <= 0) + return wxPos; + wxString v = t->GetValue(); + long win = 0; + long i = 0; + for (wxString::const_iterator it = v.begin(); it != v.end() && i < wxPos; ++it, ++i) + win += *it == '\n' ? 2 : 1; + return win; +} + +wxString ToEditText(const WindowState& st, const wxString& s) { + if (!IsMultilineEdit(st)) + return s; + wxString r = s; + r.Replace("\r\n", "\n"); + r.Replace("\r", "\n"); + return r; +} + +wxString FromEditText(const WindowState& st, const wxString& s) { + if (!IsMultilineEdit(st)) + return s; + wxString r = s; + r.Replace("\n", "\r\n"); + return r; +} + +wxString StripMnemonicForNoPrefix(const char* text, DWORD style) { + wxString s = AnsiText(text); + if (style & SS_NOPREFIX) + s.Replace("&", "&&"); + return s; +} + +int ControlId(wxWindow* w) { + WindowState* st = GetState(w); + return st ? st->winId : 0; +} + +void WrapStatic(wxWindow* w, WindowState& st) { + auto* text = wxDynamicCast(w, wxStaticText); + if (!text) + return; + DWORD type = st.style & SS_TYPEMASK; + wxString label = (st.style & SS_NOPREFIX) ? wxString(st.text).Clone() : st.text; + if (st.style & SS_NOPREFIX) + label.Replace("&", "&&"); + st.settingText = true; + text->SetLabel(label); + if (type != SS_LEFTNOWORDWRAP && type != SS_SIMPLE && w->GetSize().x > 0) + text->Wrap(w->GetSize().x); + st.settingText = false; +} + +} // namespace + +wxString GetControlText(wxWindow* w) { + WindowState* st = GetState(w); + if (!st) + return w->GetLabel(); + switch (st->kind) { + case ControlKind::Edit: + case ControlKind::RichEdit: + if (auto* t = AsText(w)) + return FromEditText(*st, t->GetValue()); + break; + case ControlKind::ComboBox: + if (auto* c = wxDynamicCast(w, wxComboBox)) + return c->GetValue(); + break; + case ControlKind::ComboList: + if (auto* c = wxDynamicCast(w, wxChoice)) + return c->GetStringSelection(); + break; + case ControlKind::Scintilla: + if (auto* s = wxDynamicCast(w, wxStyledTextCtrl)) + return s->GetText(); + break; + case ControlKind::Static: + case ControlKind::Generic: + case ControlKind::OwnerDrawButton: + case ControlKind::StaticBitmap: + case ControlKind::StaticFrame: + return st->text; + case ControlKind::Dialog: + case ControlKind::Frame: + case ControlKind::MDIChild: + return st->text.empty() ? w->GetLabel() : st->text; + default: + break; + } + return w->GetLabel(); +} + +void SetControlText(wxWindow* w, const wxString& text) { + WindowState* st = GetState(w); + if (!st) { + w->SetLabel(text); + return; + } + switch (st->kind) { + case ControlKind::Edit: + case ControlKind::RichEdit: + if (auto* t = AsText(w)) { + wxString v = ToEditText(*st, text); + if (t->GetValue() != v) + t->SetValue(v); + else + t->SetValue(v); + Extra(*st).modified = false; + } + return; + case ControlKind::ComboBox: + if (auto* c = wxDynamicCast(w, wxComboBox)) { + st->settingText = true; + c->ChangeValue(text); + st->settingText = false; + } + return; + case ControlKind::ComboList: + if (auto* c = wxDynamicCast(w, wxChoice)) + c->SetStringSelection(text); + return; + case ControlKind::Scintilla: + if (auto* s = wxDynamicCast(w, wxStyledTextCtrl)) + s->SetText(text); + return; + case ControlKind::Static: + st->text = text; + WrapStatic(w, *st); + return; + case ControlKind::Generic: + case ControlKind::OwnerDrawButton: + case ControlKind::StaticBitmap: + case ControlKind::StaticFrame: + st->text = text; + w->Refresh(); + return; + case ControlKind::Dialog: + case ControlKind::Frame: + case ControlKind::MDIChild: + st->text = text; + w->SetLabel(text); + return; + default: + w->SetLabel(text); + return; + } +} + +DWORD CurrentStyle(wxWindow* w) { + WindowState* st = GetState(w); + DWORD style = st ? st->style : 0; + style = w->IsShown() ? (style | WS_VISIBLE) : (style & ~WS_VISIBLE); + style = w->IsThisEnabled() ? (style & ~WS_DISABLED) : (style | WS_DISABLED); + if (st && (st->kind == ControlKind::Edit || st->kind == ControlKind::RichEdit)) { + if (auto* t = AsText(w)) + style = t->IsEditable() ? (style & ~ES_READONLY) : (style | ES_READONLY); + } + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) { + if (tlw->IsMaximized()) + style |= WS_MAXIMIZE; + if (tlw->IsIconized()) + style |= WS_MINIMIZE; + } + return style; +} + +void ApplyStyle(wxWindow* w, DWORD oldStyle, DWORD newStyle) { + WindowState& st = EnsureState(w); + st.style = newStyle; + if ((oldStyle ^ newStyle) & WS_VISIBLE) + w->Show((newStyle & WS_VISIBLE) != 0); + if ((oldStyle ^ newStyle) & WS_DISABLED) + w->Enable((newStyle & WS_DISABLED) == 0); + if (st.kind == ControlKind::Edit || st.kind == ControlKind::RichEdit) { + if (auto* t = AsText(w)) { + if ((oldStyle ^ newStyle) & ES_READONLY) + t->SetEditable((newStyle & ES_READONLY) == 0); + } + } + if (st.kind == ControlKind::OwnerDrawButton || st.kind == ControlKind::Generic || st.kind == ControlKind::StaticFrame) + w->Refresh(); +} + +// --------------------------------------------------------------------------------------------- +// Notifications to the parent + +void NotifyParent(wxWindow* control, UINT code) { + wxWindow* parent = LogicalParent(control); + if (!parent || !IsManagedWindow(parent)) + return; + DispatchMessageTo(ToHwnd(parent), WM_COMMAND, MAKEWPARAM(ControlId(control), code), + reinterpret_cast(ToHwnd(control))); +} + +LRESULT NotifyParentNM(wxWindow* control, NMHDR* hdr) { + wxWindow* parent = LogicalParent(control); + if (!parent || !IsManagedWindow(parent)) + return 0; + hdr->hwndFrom = ToHwnd(control); + hdr->idFrom = static_cast(ControlId(control)); + return DispatchMessageTo(ToHwnd(parent), WM_NOTIFY, hdr->idFrom, reinterpret_cast(hdr)); +} + +void NotifyFocusChange(wxWindow* w, WindowState& st, bool gained) { + switch (st.kind) { + case ControlKind::Edit: + case ControlKind::RichEdit: + NotifyParent(w, gained ? EN_SETFOCUS : EN_KILLFOCUS); + break; + case ControlKind::ComboBox: + case ControlKind::ComboList: + NotifyParent(w, gained ? CBN_SETFOCUS : CBN_KILLFOCUS); + break; + case ControlKind::ListBox: + if (st.style & LBS_NOTIFY) + NotifyParent(w, gained ? LBN_SETFOCUS : LBN_KILLFOCUS); + break; + case ControlKind::PushButton: + case ControlKind::CheckBox: + case ControlKind::RadioButton: + case ControlKind::OwnerDrawButton: + if (st.style & BS_NOTIFY) + NotifyParent(w, gained ? BN_SETFOCUS : BN_KILLFOCUS); + if (st.kind == ControlKind::OwnerDrawButton) + w->Refresh(); + break; + case ControlKind::ListView: { + NMHDR hdr; + hdr.code = gained ? NM_SETFOCUS : NM_KILLFOCUS; + NotifyParentNM(w, &hdr); + break; + } + default: + break; + } +} + +bool FilterEditChar(wxWindow* w, WindowState& st, UINT& ch, wxKeyEvent& e) { + if (st.kind != ControlKind::Edit && st.kind != ControlKind::ComboBox) + return false; + if (ch >= 32) { + if ((st.style & ES_NUMBER) && st.kind == ControlKind::Edit && !(ch >= '0' && ch <= '9')) { + wxBell(); + return true; + } + if (st.style & ES_UPPERCASE) + ch = static_cast(toupper(static_cast(ch))); + else if (st.style & ES_LOWERCASE) + ch = static_cast(tolower(static_cast(ch))); + if (st.kind == ControlKind::Edit) { + EditExtra& ex = Extra(st); + auto* t = AsText(w); + if (t && ex.limit > 0) { + long from, to; + t->GetSelection(&from, &to); + long len = static_cast(FromEditText(st, t->GetValue()).length()); + if (len - (to - from) >= ex.limit) { + NotifyParent(w, EN_MAXTEXT); + return true; + } + } + } + if ((st.style & (ES_UPPERCASE | ES_LOWERCASE)) && !HasMessageHandler(st.permanent, WM_CHAR)) { + if (auto* t = AsText(w)) { + char a = static_cast(ch); + t->WriteText(ToWx(&a, 1)); + return true; + } + } + } + (void)e; + return false; +} + +// --------------------------------------------------------------------------------------------- +// Tab control geometry + +int TabHeaderHeight(wxWindow* w) { + WindowState* st = GetState(w); + if (st && Extra(*st).itemSize.y > 0) + return Extra(*st).itemSize.y; + return w->GetCharHeight() + 8; +} + +std::vector TabRects(wxWindow* w) { + std::vector rects; + WindowState* st = GetState(w); + if (!st) + return rects; + TabExtra& tx = Extra(*st); + int tabH = TabHeaderHeight(w); + int x = 2; + for (const auto& item : tx.items) { + int tw = tx.itemSize.x > 0 ? tx.itemSize.x + : w->GetTextExtent(wxStripMenuCodes(item.first, wxStrip_Mnemonics)).x + 16; + rects.emplace_back(x, 0, tw, tabH); + x += tw; + } + return rects; +} + +// --------------------------------------------------------------------------------------------- +// Owner-drawn buttons and statics + +namespace { + +using PaintFn = void (*)(wxWindow*, wxDC&, CDC*); + +std::function PaintBridge(wxWindow* w, PaintFn fn) { + return [w, fn](wxPaintEvent&) { + wxPaintDC dc(w); + CDC* cdc = WrapDC(&dc, w); + fn(w, dc, cdc); + PaintClientDCOverlay(w, dc); + UnwrapDC(cdc); + }; +} + +void SendDrawItem(wxWindow* w, WindowState& st, CDC* cdc, UINT ctlType) { + ButtonExtra& bx = Extra(st); + DRAWITEMSTRUCT dis; + memset(&dis, 0, sizeof dis); + dis.CtlType = ctlType; + dis.CtlID = static_cast(st.winId); + dis.itemID = 0; + dis.itemAction = ODA_DRAWENTIRE; + if (bx.pushed) + dis.itemState |= ODS_SELECTED; + if (!w->IsEnabled()) + dis.itemState |= ODS_DISABLED | ODS_GRAYED; + if (w->HasFocus()) + dis.itemState |= ODS_FOCUS; + dis.hwndItem = ToHwnd(w); + dis.hDC = cdc->m_hDC; + wxSize sz = w->GetClientSize(); + dis.rcItem.right = sz.x; + dis.rcItem.bottom = sz.y; + wxWindow* parent = LogicalParent(w); + if (parent && IsManagedWindow(parent)) + DispatchMessageTo(ToHwnd(parent), WM_DRAWITEM, static_cast(st.winId), reinterpret_cast(&dis)); +} + +void PaintOwnerDrawButton(wxWindow* w, wxDC&, CDC* cdc) { + WindowState* st = GetState(w); + if (!st) + return; + SendDrawItem(w, *st, cdc, ODT_BUTTON); +} + +void PaintStaticFrame(wxWindow* w, wxDC& dc, CDC*) { + WindowState* st = GetState(w); + if (!st) + return; + wxSize sz = w->GetClientSize(); + DWORD type = st->style & SS_TYPEMASK; + wxColour shadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); + wxColour light = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT); + wxColour colour; + switch (type) { + case SS_BLACKRECT: case SS_BLACKFRAME: colour = wxColour(0, 0, 0); break; + case SS_GRAYRECT: case SS_GRAYFRAME: colour = shadow; break; + case SS_WHITERECT: case SS_WHITEFRAME: colour = wxColour(255, 255, 255); break; + default: colour = shadow; break; + } + switch (type) { + case SS_BLACKRECT: + case SS_GRAYRECT: + case SS_WHITERECT: + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(wxBrush(colour)); + dc.DrawRectangle(0, 0, sz.x, sz.y); + break; + case SS_ETCHEDHORZ: + dc.SetPen(wxPen(shadow)); + dc.DrawLine(0, 0, sz.x, 0); + dc.SetPen(wxPen(light)); + dc.DrawLine(0, 1, sz.x, 1); + break; + case SS_ETCHEDVERT: + dc.SetPen(wxPen(shadow)); + dc.DrawLine(0, 0, 0, sz.y); + dc.SetPen(wxPen(light)); + dc.DrawLine(1, 0, 1, sz.y); + break; + case SS_ETCHEDFRAME: + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.SetPen(wxPen(shadow)); + dc.DrawRectangle(0, 0, sz.x - 1, sz.y - 1); + dc.SetPen(wxPen(light)); + dc.DrawRectangle(1, 1, sz.x - 1, sz.y - 1); + break; + default: + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.SetPen(wxPen(colour)); + dc.DrawRectangle(0, 0, sz.x, sz.y); + break; + } +} + +void PaintGenericStatic(wxWindow* w, wxDC& dc, CDC* cdc) { + WindowState* st = GetState(w); + if (!st) + return; + if ((st->style & SS_TYPEMASK) == SS_OWNERDRAW) { + SendDrawItem(w, *st, cdc, ODT_STATIC); + return; + } + wxString text = st->text; + if (!(st->style & SS_NOPREFIX)) + text = wxStripMenuCodes(text, wxStrip_Mnemonics); + dc.SetFont(w->GetFont()); + dc.SetTextForeground(w->GetForegroundColour()); + wxSize sz = w->GetClientSize(); + int align = wxALIGN_LEFT; + if ((st->style & SS_TYPEMASK) == SS_CENTER) + align = wxALIGN_CENTER_HORIZONTAL; + else if ((st->style & SS_TYPEMASK) == SS_RIGHT) + align = wxALIGN_RIGHT; + if (st->style & SS_CENTERIMAGE) + align |= wxALIGN_CENTER_VERTICAL; + dc.DrawLabel(text, wxRect(0, 0, sz.x, sz.y), align); +} + +void BindOwnerDrawButton(wxWindow* w) { + w->Bind(wxEVT_LEFT_DOWN, [w](wxMouseEvent& e) { + WindowState* st = GetState(w); + if (st && w->IsEnabled()) { + Extra(*st).pushed = true; + w->CaptureMouse(); + w->Refresh(); + if (st->style & WS_TABSTOP) + w->SetFocus(); + } + e.Skip(); + }); + w->Bind(wxEVT_LEFT_DCLICK, [w](wxMouseEvent& e) { + WindowState* st = GetState(w); + if (st && w->IsEnabled()) { + Extra(*st).pushed = true; + if (!w->HasCapture()) + w->CaptureMouse(); + w->Refresh(); + } + e.Skip(); + }); + w->Bind(wxEVT_LEFT_UP, [w](wxMouseEvent& e) { + WindowState* st = GetState(w); + if (w->HasCapture()) + w->ReleaseMouse(); + if (st) { + ButtonExtra& bx = Extra(*st); + bool wasPushed = bx.pushed; + bx.pushed = false; + w->Refresh(); + if (wasPushed && wxRect(w->GetClientSize()).Contains(e.GetPosition())) + NotifyParent(w, BN_CLICKED); + } + e.Skip(); + }); + w->Bind(wxEVT_MOUSE_CAPTURE_LOST, [w](wxMouseCaptureLostEvent&) { + WindowState* st = GetState(w); + if (st) { + Extra(*st).pushed = false; + w->Refresh(); + } + }); + w->Bind(wxEVT_KEY_UP, [w](wxKeyEvent& e) { + if (e.GetKeyCode() == WXK_SPACE) + NotifyParent(w, BN_CLICKED); + else + e.Skip(); + }); +} + +void BindStaticNotify(wxWindow* w) { + w->Bind(wxEVT_LEFT_DOWN, [w](wxMouseEvent& e) { + WindowState* st = GetState(w); + if (st && (st->style & SS_NOTIFY)) + NotifyParent(w, STN_CLICKED); + e.Skip(); + }); + w->Bind(wxEVT_LEFT_DCLICK, [w](wxMouseEvent& e) { + WindowState* st = GetState(w); + if (st && (st->style & SS_NOTIFY)) + NotifyParent(w, STN_DBLCLK); + e.Skip(); + }); +} + +// --------------------------------------------------------------------------------------------- +// Tab control (header only, as in Windows) + +void PaintTabs(wxWindow* w, wxDC& dc, CDC*) { + WindowState* st = GetState(w); + if (!st) + return; + TabExtra& tx = Extra(*st); + dc.SetFont(w->GetFont()); + wxSize sz = w->GetClientSize(); + int tabH = TabHeaderHeight(w); + wxColour shadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); + dc.SetPen(wxPen(shadow)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(0, tabH - 1, sz.x, sz.y - tabH + 1); + std::vector rects = TabRects(w); + for (size_t i = 0; i < rects.size() && i < tx.items.size(); ++i) { + wxString label = wxStripMenuCodes(tx.items[i].first, wxStrip_Mnemonics); + bool sel = static_cast(i) == tx.current; + wxRect r = rects[i]; + if (!sel) { + r.y += 2; + r.height -= 2; + } + dc.SetBrush(sel ? wxBrush(w->GetBackgroundColour()) : wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))); + dc.SetPen(wxPen(shadow)); + dc.DrawRectangle(r); + if (sel) { + dc.SetPen(wxPen(w->GetBackgroundColour())); + dc.DrawLine(r.x + 1, r.GetBottom(), r.GetRight(), r.GetBottom()); + } + dc.SetTextForeground(w->GetForegroundColour()); + dc.DrawLabel(label, r, wxALIGN_CENTER); + } +} + +int TabHitTest(wxWindow* w, const wxPoint& p) { + std::vector rects = TabRects(w); + for (size_t i = 0; i < rects.size(); ++i) + if (rects[i].Contains(p)) + return static_cast(i); + return -1; +} + +void BindTabs(wxWindow* w) { + w->Bind(wxEVT_LEFT_DOWN, [w](wxMouseEvent& e) { + int hit = TabHitTest(w, e.GetPosition()); + WindowState* st = GetState(w); + if (hit >= 0 && st && hit != Extra(*st).current) { + NMHDR hdr; + hdr.code = TCN_SELCHANGING; + if (!NotifyParentNM(w, &hdr)) { + Extra(*st).current = hit; + w->Refresh(); + NMHDR hdr2; + hdr2.code = TCN_SELCHANGE; + NotifyParentNM(w, &hdr2); + } + } + e.Skip(); + }); +} + +// --------------------------------------------------------------------------------------------- +// Spin buttons + +RangeExtra& SpinRange(WindowState& st) { return Extra(st); } + +void UpdateSpinBuddy(wxWindow* w, WindowState& st) { + if (!(st.style & UDS_SETBUDDYINT) || !st.buddy || !st.buddy->m_hWnd) + return; + RangeExtra& r = SpinRange(st); + wxString text = wxString::Format("%d", r.pos); + if (!(st.style & UDS_NOTHOUSANDS) && std::abs(r.pos) >= 1000) { + text = wxString::Format("%d", r.pos); + } + SetControlText(st.buddy->GetWx(), text); + (void)w; +} + +int ReadSpinBuddy(WindowState& st) { + RangeExtra& r = SpinRange(st); + if ((st.style & UDS_SETBUDDYINT) && st.buddy && st.buddy->m_hWnd) { + long v; + if (GetControlText(st.buddy->GetWx()).ToLong(&v)) + r.pos = static_cast(v); + } + return r.pos; +} + +void SpinStep(wxWindow* w, int direction) { + WindowState* st = GetState(w); + if (!st) + return; + RangeExtra& r = SpinRange(*st); + int pos = ReadSpinBuddy(*st); + int lo = std::min(r.minValue, r.maxValue); + int hi = std::max(r.minValue, r.maxValue); + int delta = r.minValue > r.maxValue ? -direction : direction; + NMUPDOWN nm; + memset(&nm, 0, sizeof nm); + nm.hdr.code = UDN_DELTAPOS; + nm.iPos = pos; + nm.iDelta = delta; + if (NotifyParentNM(w, &nm.hdr)) + return; + int next = pos + nm.iDelta; + if (next > hi) + next = (st->style & UDS_WRAP) ? lo : hi; + if (next < lo) + next = (st->style & UDS_WRAP) ? hi : lo; + r.pos = next; + UpdateSpinBuddy(w, *st); + wxWindow* parent = LogicalParent(w); + if (parent && IsManagedWindow(parent)) { + UINT msg = (st->style & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL; + DispatchMessageTo(ToHwnd(parent), msg, MAKEWPARAM(SB_THUMBPOSITION, static_cast(next)), + reinterpret_cast(ToHwnd(w))); + DispatchMessageTo(ToHwnd(parent), msg, MAKEWPARAM(SB_ENDSCROLL, static_cast(next)), + reinterpret_cast(ToHwnd(w))); + } +} + +// --------------------------------------------------------------------------------------------- +// Scroll bars and sliders + +UINT ScrollCodeFromEvent(const wxScrollEvent& e) { + wxEventType t = e.GetEventType(); + if (t == wxEVT_SCROLL_LINEUP) + return SB_LINEUP; + if (t == wxEVT_SCROLL_LINEDOWN) + return SB_LINEDOWN; + if (t == wxEVT_SCROLL_PAGEUP) + return SB_PAGEUP; + if (t == wxEVT_SCROLL_PAGEDOWN) + return SB_PAGEDOWN; + if (t == wxEVT_SCROLL_THUMBTRACK) + return SB_THUMBTRACK; + if (t == wxEVT_SCROLL_THUMBRELEASE) + return SB_THUMBPOSITION; + if (t == wxEVT_SCROLL_TOP) + return SB_TOP; + if (t == wxEVT_SCROLL_BOTTOM) + return SB_BOTTOM; + return SB_ENDSCROLL; +} + +void ForwardScroll(wxScrollEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + WindowState* st = GetState(w); + wxWindow* parent = LogicalParent(w); + if (!st || !parent || !IsManagedWindow(parent)) + return; + bool vertical = e.GetOrientation() == wxVERTICAL; + UINT msg = vertical ? WM_VSCROLL : WM_HSCROLL; + UINT code = ScrollCodeFromEvent(e); + int pos = e.GetPosition(); + if (st->kind == ControlKind::Slider) { + RangeExtra& r = Extra(*st); + r.pos = pos; + } else if (st->kind == ControlKind::ScrollBar) { + pos += Extra(*st).minValue; + } + DispatchMessageTo(ToHwnd(parent), msg, MAKEWPARAM(code, static_cast(pos)), reinterpret_cast(ToHwnd(w))); + if (e.GetEventType() == wxEVT_SCROLL_CHANGED || e.GetEventType() == wxEVT_SCROLL_THUMBRELEASE) + DispatchMessageTo(ToHwnd(parent), msg, MAKEWPARAM(SB_ENDSCROLL, static_cast(pos)), + reinterpret_cast(ToHwnd(w))); +} + +} // namespace + +// --------------------------------------------------------------------------------------------- +// Event binding for standard controls + +void BindControlEvents(wxWindow* w, WindowState& st) { + switch (st.kind) { + case ControlKind::PushButton: + w->Bind(wxEVT_BUTTON, [w](wxCommandEvent&) { NotifyParent(w, BN_CLICKED); }); + w->Bind(wxEVT_TOGGLEBUTTON, [w](wxCommandEvent&) { NotifyParent(w, BN_CLICKED); }); + break; + case ControlKind::CheckBox: + w->Bind(wxEVT_CHECKBOX, [w](wxCommandEvent&) { + WindowState* s = GetState(w); + if (s) { + DWORD type = s->style & BS_TYPEMASK; + if (type == BS_CHECKBOX || type == BS_3STATE) { + // Non-automatic check boxes keep their state; the application changes it. + auto* cb = wxDynamicCast(w, wxCheckBox); + if (cb) + cb->Set3StateValue(s->checkState == 2 ? wxCHK_UNDETERMINED + : (s->checkState ? wxCHK_CHECKED : wxCHK_UNCHECKED)); + } else if (auto* cb = wxDynamicCast(w, wxCheckBox)) { + s->checkState = cb->Get3StateValue() == wxCHK_UNDETERMINED ? 2 : (cb->GetValue() ? 1 : 0); + } + } + NotifyParent(w, BN_CLICKED); + }); + w->Bind(wxEVT_TOGGLEBUTTON, [w](wxCommandEvent&) { NotifyParent(w, BN_CLICKED); }); + break; + case ControlKind::RadioButton: + w->Bind(wxEVT_RADIOBUTTON, [w](wxCommandEvent&) { + WindowState* s = GetState(w); + if (s && (s->style & BS_TYPEMASK) == BS_RADIOBUTTON) { + if (auto* rb = wxDynamicCast(w, wxRadioButton)) + if (!s->checkState) + rb->SetValue(false); + } + NotifyParent(w, BN_CLICKED); + }); + break; + case ControlKind::OwnerDrawButton: + st.customPaint = PaintBridge(w, &PaintOwnerDrawButton); + BindOwnerDrawButton(w); + break; + case ControlKind::StaticFrame: + st.customPaint = PaintBridge(w, &PaintStaticFrame); + BindStaticNotify(w); + break; + case ControlKind::Static: + case ControlKind::StaticBitmap: + BindStaticNotify(w); + break; + case ControlKind::Edit: + case ControlKind::RichEdit: + w->Bind(wxEVT_TEXT, [w](wxCommandEvent& e) { + WindowState* s = GetState(w); + if (s) { + Extra(*s).modified = true; + NotifyParent(w, EN_UPDATE); + NotifyParent(w, EN_CHANGE); + } + e.Skip(false); + }); + w->Bind(wxEVT_TEXT_MAXLEN, [w](wxCommandEvent&) { NotifyParent(w, EN_MAXTEXT); }); + break; + case ControlKind::ComboBox: + w->Bind(wxEVT_TEXT, [w](wxCommandEvent&) { + WindowState* s = GetState(w); + if (s && !s->settingText) { + NotifyParent(w, CBN_EDITUPDATE); + NotifyParent(w, CBN_EDITCHANGE); + } + }); + w->Bind(wxEVT_COMBOBOX, [w](wxCommandEvent&) { + NotifyParent(w, CBN_SELCHANGE); + NotifyParent(w, CBN_SELENDOK); + }); + w->Bind(wxEVT_COMBOBOX_DROPDOWN, [w](wxCommandEvent&) { NotifyParent(w, CBN_DROPDOWN); }); + w->Bind(wxEVT_COMBOBOX_CLOSEUP, [w](wxCommandEvent&) { NotifyParent(w, CBN_CLOSEUP); }); + break; + case ControlKind::ComboList: + w->Bind(wxEVT_CHOICE, [w](wxCommandEvent&) { + NotifyParent(w, CBN_SELCHANGE); + NotifyParent(w, CBN_SELENDOK); + NotifyParent(w, CBN_CLOSEUP); + }); + break; + case ControlKind::ListBox: + w->Bind(wxEVT_LISTBOX, [w](wxCommandEvent&) { + WindowState* s = GetState(w); + if (s && (s->style & LBS_NOTIFY)) + NotifyParent(w, LBN_SELCHANGE); + }); + w->Bind(wxEVT_LISTBOX_DCLICK, [w](wxCommandEvent&) { + WindowState* s = GetState(w); + if (s && (s->style & LBS_NOTIFY)) + NotifyParent(w, LBN_DBLCLK); + }); + break; + case ControlKind::ScrollBar: + case ControlKind::Slider: + w->Bind(wxEVT_SCROLL_TOP, &ForwardScroll); + w->Bind(wxEVT_SCROLL_BOTTOM, &ForwardScroll); + w->Bind(wxEVT_SCROLL_LINEUP, &ForwardScroll); + w->Bind(wxEVT_SCROLL_LINEDOWN, &ForwardScroll); + w->Bind(wxEVT_SCROLL_PAGEUP, &ForwardScroll); + w->Bind(wxEVT_SCROLL_PAGEDOWN, &ForwardScroll); + w->Bind(wxEVT_SCROLL_THUMBTRACK, &ForwardScroll); + w->Bind(wxEVT_SCROLL_THUMBRELEASE, &ForwardScroll); + w->Bind(wxEVT_SCROLL_CHANGED, &ForwardScroll); + if (st.kind == ControlKind::Slider) + w->Bind(wxEVT_LEFT_UP, [w](wxMouseEvent& e) { + NMHDR hdr; + hdr.code = NM_RELEASEDCAPTURE; + NotifyParentNM(w, &hdr); + e.Skip(); + }); + break; + case ControlKind::Spin: + w->Bind(wxEVT_SPIN_UP, [w](wxSpinEvent& e) { + SpinStep(w, +1); + e.Veto(); + }); + w->Bind(wxEVT_SPIN_DOWN, [w](wxSpinEvent& e) { + SpinStep(w, -1); + e.Veto(); + }); + break; + case ControlKind::ListView: + BindListViewEvents(w); + break; + case ControlKind::Tab: + st.customPaint = PaintBridge(w, &PaintTabs); + BindTabs(w); + break; + case ControlKind::Scintilla: + BindScintillaEvents(w); + break; + default: + break; + } +} + +// --------------------------------------------------------------------------------------------- +// Creation + +namespace { + +wxFont DialogFont(); + +bool ClassIs(const char* cls, const char* name) { return cls && strcasecmp(cls, name) == 0; } + +long BorderFlags(DWORD style, DWORD exStyle, bool defaultBorder) { + if (exStyle & (WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)) + return wxBORDER_SUNKEN; + if (style & WS_BORDER) + return wxBORDER_SIMPLE; + return defaultBorder ? wxBORDER_DEFAULT : wxBORDER_NONE; +} + +} // namespace + +wxWindow* CreateControl(wxWindow* parent, const char* cls, const char* text, int winId, const wxRect& rect, + DWORD style, DWORD exStyle) { + const int id = ToWxId(winId); + const wxPoint pos = rect.GetPosition(); + const wxSize size = rect.GetSize(); + wxWindow* w = nullptr; + ControlKind kind = ControlKind::Generic; + wxString label = AnsiText(text); + + if (ClassIs(cls, "Button")) { + DWORD type = style & BS_TYPEMASK; + if (type == BS_GROUPBOX) { + w = new wxStaticBox(parent, id, label, pos, size); + kind = ControlKind::GroupBox; + } else if (type == BS_OWNERDRAW) { + w = new GenericWindow(parent, id, pos, size, wxBORDER_NONE); + kind = ControlKind::OwnerDrawButton; + } else if (type == BS_CHECKBOX || type == BS_AUTOCHECKBOX || type == BS_3STATE || type == BS_AUTO3STATE) { + if (style & BS_PUSHLIKE) { + w = new wxToggleButton(parent, id, label, pos, size); + } else { + long f = (type == BS_3STATE || type == BS_AUTO3STATE) ? wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER + : wxCHK_2STATE; + if (style & BS_LEFTTEXT) + f |= wxALIGN_RIGHT; + w = new wxCheckBox(parent, id, label, pos, size, f); + } + kind = ControlKind::CheckBox; + } else if (type == BS_RADIOBUTTON || type == BS_AUTORADIOBUTTON) { + long f = 0; + if (style & WS_GROUP) + f |= wxRB_GROUP; + else { + wxWindowList& siblings = parent->GetChildren(); + for (auto it = siblings.rbegin(); it != siblings.rend(); ++it) { + WindowState* s = GetState(*it); + if (!s) + continue; + if (s->kind == ControlKind::RadioButton) + break; + if (s->style & WS_GROUP) { + f |= wxRB_GROUP; + break; + } + } + } + w = new wxRadioButton(parent, id, label, pos, size, f); + kind = ControlKind::RadioButton; + } else { + long f = 0; + if ((style & BS_CENTER) == BS_LEFT) + f |= wxBU_LEFT; + else if ((style & BS_CENTER) == BS_RIGHT) + f |= wxBU_RIGHT; + if ((style & (BS_BITMAP | BS_ICON)) && label.empty()) + f |= wxBU_EXACTFIT | wxBU_NOTEXT; + w = new wxButton(parent, id, label, pos, size, f); + kind = ControlKind::PushButton; + } + } else if (ClassIs(cls, "Edit") || ClassIs(cls, "RICHEDIT") || ClassIs(cls, "RichEdit20A") || + ClassIs(cls, "RichEdit20W") || ClassIs(cls, "RICHEDIT50W")) { + bool rich = !ClassIs(cls, "Edit"); + long f = BorderFlags(style, exStyle, false); + if ((style & ES_MULTILINE) || rich) { + f |= wxTE_MULTILINE; + if (style & ES_AUTOHSCROLL || style & WS_HSCROLL) + f |= wxTE_DONTWRAP | wxHSCROLL; + else + f |= wxTE_WORDWRAP; + if (!(style & WS_VSCROLL) && !rich) + f |= wxTE_NO_VSCROLL; + } + if (rich) + f |= wxTE_RICH2; + if (style & ES_READONLY) + f |= wxTE_READONLY; + if (style & ES_PASSWORD) + f |= wxTE_PASSWORD; + if ((style & 3) == ES_CENTER) + f |= wxTE_CENTRE; + else if ((style & 3) == ES_RIGHT) + f |= wxTE_RIGHT; + if (style & ES_NOHIDESEL) + f |= wxTE_NOHIDESEL; + w = new wxTextCtrl(parent, id, wxString(), pos, size, f); + kind = rich ? ControlKind::RichEdit : ControlKind::Edit; + if (!label.empty()) { + static_cast(w)->ChangeValue(label); + } + } else if (ClassIs(cls, "Static")) { + DWORD type = style & SS_TYPEMASK; + if (type == SS_BITMAP || type == SS_ICON) { + wxBitmap bmp; + if (type == SS_BITMAP) + bmp = LoadBitmapResource(ResRef::From(text)); + else { + wxIcon icon = LoadIconResource(ResRef::From(text)); + if (icon.IsOk()) + bmp.CopyFromIcon(icon); + } + wxSize s = size; + if (bmp.IsOk() && !(style & SS_REALSIZECONTROL) && !(style & SS_CENTERIMAGE)) + s = bmp.GetSize(); + w = new wxStaticBitmap(parent, id, bmp.IsOk() ? bmp : wxBitmap(1, 1), pos, s); + kind = ControlKind::StaticBitmap; + } else if ((type >= SS_BLACKRECT && type <= SS_WHITEFRAME) || type == SS_ETCHEDHORZ || type == SS_ETCHEDVERT || + type == SS_ETCHEDFRAME) { + w = new GenericWindow(parent, id, pos, size, wxBORDER_NONE); + kind = ControlKind::StaticFrame; + } else if (type == SS_OWNERDRAW || type == SS_USERITEM) { + w = new GenericWindow(parent, id, pos, size, wxBORDER_NONE); + kind = ControlKind::Generic; + EnsureState(w).customPaint = PaintBridge(w, &PaintGenericStatic); + } else { + long f = wxST_NO_AUTORESIZE | BorderFlags(style, exStyle, false); + if (style & SS_SUNKEN) + f |= wxBORDER_SUNKEN; + if (type == SS_CENTER) + f |= wxALIGN_CENTRE_HORIZONTAL; + else if (type == SS_RIGHT) + f |= wxALIGN_RIGHT; + if (style & SS_ENDELLIPSIS) + f |= wxST_ELLIPSIZE_END; + w = new wxStaticText(parent, id, wxString(), pos, size, f); + kind = ControlKind::Static; + } + } else if (ClassIs(cls, "ComboBox")) { + DWORD type = style & 3; + long f = (style & CBS_SORT) ? wxCB_SORT : 0; + if (type == CBS_DROPDOWNLIST) { + w = new wxChoice(parent, id, pos, wxSize(size.x, -1), 0, nullptr, f); + kind = ControlKind::ComboList; + } else { + w = new wxComboBox(parent, id, wxString(), pos, wxSize(size.x, -1), 0, nullptr, f); + kind = ControlKind::ComboBox; + } + } else if (ClassIs(cls, "ListBox")) { + long f = BorderFlags(style, exStyle, true); + if (style & LBS_MULTIPLESEL) + f |= wxLB_MULTIPLE; + else if (style & LBS_EXTENDEDSEL) + f |= wxLB_EXTENDED; + else + f |= wxLB_SINGLE; + if (style & LBS_SORT) + f |= wxLB_SORT; + if (style & WS_HSCROLL) + f |= wxLB_HSCROLL; + if (style & LBS_DISABLENOSCROLL) + f |= wxLB_ALWAYS_SB; + w = new wxListBox(parent, id, pos, size, 0, nullptr, f); + kind = ControlKind::ListBox; + } else if (ClassIs(cls, "ScrollBar")) { + w = new wxScrollBar(parent, id, pos, size, (style & SBS_VERT) ? wxSB_VERTICAL : wxSB_HORIZONTAL); + kind = ControlKind::ScrollBar; + } else if (ClassIs(cls, "msctls_progress32")) { + w = new wxGauge(parent, id, 100, pos, size, (style & PBS_VERTICAL) ? wxGA_VERTICAL : wxGA_HORIZONTAL); + kind = ControlKind::Progress; + } else if (ClassIs(cls, "msctls_trackbar32")) { + long f = (style & TBS_VERT) ? wxSL_VERTICAL : wxSL_HORIZONTAL; + if (style & TBS_AUTOTICKS) + f |= wxSL_AUTOTICKS; + if (style & TBS_BOTH) + f |= wxSL_BOTH; + else if (style & TBS_TOP) + f |= (style & TBS_VERT) ? wxSL_LEFT : wxSL_TOP; + w = new wxSlider(parent, id, 0, 0, 100, pos, size, f); + kind = ControlKind::Slider; + } else if (ClassIs(cls, "msctls_updown32")) { + long f = (style & UDS_HORZ) ? wxSP_HORIZONTAL : wxSP_VERTICAL; + f |= wxSP_ARROW_KEYS; + if (style & UDS_WRAP) + f |= wxSP_WRAP; + w = new wxSpinButton(parent, id, pos, size, f); + static_cast(w)->SetRange(-1000000, 1000000); + kind = ControlKind::Spin; + } else if (ClassIs(cls, "SysListView32")) { + long f = BorderFlags(style, exStyle, true); + switch (style & LVS_TYPEMASK) { + case LVS_REPORT: f |= wxLC_REPORT; break; + case LVS_LIST: f |= wxLC_LIST; break; + case LVS_SMALLICON: f |= wxLC_SMALL_ICON; break; + default: f |= wxLC_ICON; break; + } + if (style & LVS_SINGLESEL) + f |= wxLC_SINGLE_SEL; + if (style & LVS_NOCOLUMNHEADER) + f |= wxLC_NO_HEADER; + if (style & LVS_EDITLABELS) + f |= wxLC_EDIT_LABELS; + if (style & LVS_SORTASCENDING) + f |= wxLC_SORT_ASCENDING; + else if (style & LVS_SORTDESCENDING) + f |= wxLC_SORT_DESCENDING; + w = new wxListCtrl(parent, id, pos, size, f); + kind = ControlKind::ListView; + } else if (ClassIs(cls, "SysTreeView32")) { + long f = BorderFlags(style, exStyle, true) | wxTR_DEFAULT_STYLE; + if (style & TVS_HASLINES) + f |= wxTR_LINES_AT_ROOT; + w = new wxTreeCtrl(parent, id, pos, size, f); + kind = ControlKind::TreeView; + } else if (ClassIs(cls, "SysTabControl32")) { + w = new GenericWindow(parent, id, pos, size, wxBORDER_NONE); + kind = ControlKind::Tab; + } else if (ClassIs(cls, "Scintilla")) { + w = new wxStyledTextCtrl(parent, id, pos, size, BorderFlags(style, exStyle, false)); + kind = ControlKind::Scintilla; + } else { + long f = BorderFlags(style, exStyle, false); + w = new GenericWindow(parent, id, pos, size, f); + kind = ControlKind::Generic; + } + + HookWindow(w, kind, winId, style, exStyle); + WindowState& st = EnsureState(w); + if (kind == ControlKind::Static || kind == ControlKind::Generic || kind == ControlKind::OwnerDrawButton || + kind == ControlKind::StaticFrame || kind == ControlKind::StaticBitmap) { + st.text = label; + if (kind == ControlKind::Static) + WrapStatic(w, st); + } + if (kind == ControlKind::Static || kind == ControlKind::GroupBox) { + // Statics are never in the tab order. + st.style &= ~WS_TABSTOP; + } + if (kind == ControlKind::Slider) { + Extra(st).maxValue = 100; + } + if (style & WS_DISABLED) + w->Disable(); + if (!(style & WS_VISIBLE)) + w->Hide(); + return w; +} + +wxWindow* CreateWindowForClass(CWnd* pWnd, CREATESTRUCT& cs) { + wxWindow* parent = cs.hwndParent ? ToWx(cs.hwndParent) : nullptr; + const char* cls = cs.lpszClass && !IS_INTRESOURCE(cs.lpszClass) ? cs.lpszClass : ""; + DWORD style = static_cast(cs.style); + bool child = (style & WS_CHILD) != 0; + if (!child || !parent) { + long f = wxDEFAULT_FRAME_STYLE; + if (!(style & WS_THICKFRAME)) + f &= ~wxRESIZE_BORDER; + if (!(style & WS_CAPTION)) + f &= ~wxCAPTION; + wxFrame* frame = new wxFrame(parent ? wxGetTopLevelParent(parent) : nullptr, wxID_ANY, AnsiText(cs.lpszName), + cs.x == CW_USEDEFAULT ? wxDefaultPosition : wxPoint(cs.x, cs.y), + cs.cx == CW_USEDEFAULT ? wxDefaultSize : wxSize(cs.cx, cs.cy), + f | (style & WS_POPUP ? wxFRAME_TOOL_WINDOW | wxFRAME_FLOAT_ON_PARENT : 0)); + HookWindow(frame, ControlKind::Frame, 0, style, cs.dwExStyle); + EnsureState(frame).text = AnsiText(cs.lpszName); + return frame; + } + int winId = static_cast(reinterpret_cast(cs.hMenu)); + wxRect rect(cs.x, cs.y, cs.cx, cs.cy); + static const char* const standard[] = {"Button", "Edit", "Static", "ComboBox", "ListBox", "ScrollBar", + "msctls_progress32", "msctls_trackbar32", "msctls_updown32", + "SysListView32", "SysTreeView32", "SysTabControl32", "Scintilla", + "RICHEDIT", "RichEdit20A", "RichEdit20W"}; + for (const char* s : standard) + if (ClassIs(cls, s)) + return CreateControl(parent, cls, cs.lpszName, winId, rect, style, cs.dwExStyle); + long f = BorderFlags(style, cs.dwExStyle, false); + if (style & WS_VSCROLL) + f |= wxVSCROLL; + if (style & WS_HSCROLL) + f |= wxHSCROLL; + if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CView))) + f |= wxWANTS_CHARS; + auto* w = new GenericWindow(parent, ToWxId(winId), rect.GetPosition(), rect.GetSize(), f); + HookWindow(w, ControlKind::Generic, winId, style, cs.dwExStyle); + EnsureState(w).text = AnsiText(cs.lpszName); + if (!(style & WS_VISIBLE)) + w->Hide(); + if (style & WS_DISABLED) + w->Disable(); + return w; +} + +namespace { + +wxWindow* ReplaceWithCheckListBox(wxListBox* lb, WindowState& st) { + auto* c = new wxCheckListBox(lb->GetParent(), lb->GetId(), lb->GetPosition(), lb->GetSize(), 0, nullptr, + lb->GetWindowStyleFlag()); + c->MoveAfterInTabOrder(lb); + c->SetFont(lb->GetFont()); + for (unsigned i = 0; i < lb->GetCount(); ++i) + c->Append(lb->GetString(i), lb->HasClientUntypedData() ? lb->GetClientData(i) : nullptr); + WindowState& cs = EnsureState(c); + HookWindow(c, ControlKind::ListBox, st.winId, st.style, st.exStyle); + cs.font = st.font; + c->Bind(wxEVT_CHECKLISTBOX, [c](wxCommandEvent&) { NotifyParent(c, CLBN_CHKCHANGE); }); + c->Show(lb->IsShown()); + c->Enable(lb->IsThisEnabled()); + lb->Destroy(); + return c; +} + +} // namespace + +wxWindow* PrepareForSubclass(wxWindow* w, CWnd* pWnd) { + WindowState* st = GetState(w); + if (!st || !pWnd) + return w; + if (st->kind == ControlKind::ListBox && pWnd->IsKindOf(RUNTIME_CLASS(CCheckListBox)) && + !wxDynamicCast(w, wxCheckListBox) && wxDynamicCast(w, wxListBox)) + return ReplaceWithCheckListBox(static_cast(w), *st); + bool paints = HasMessageHandler(pWnd, WM_PAINT) || HasMessageHandler(pWnd, WM_ERASEBKGND); + bool nativeStatic = st->kind == ControlKind::Static || st->kind == ControlKind::StaticBitmap; + bool ownerDrawStatic = st->kind == ControlKind::Static && (st->style & SS_TYPEMASK) == SS_OWNERDRAW; + if (!(paints && nativeStatic) && !ownerDrawStatic) + return w; + wxWindow* parent = w->GetParent(); + wxRect rect = w->GetRect(); + auto* g = new GenericWindow(parent, w->GetId(), rect.GetPosition(), rect.GetSize(), wxBORDER_NONE); + g->MoveAfterInTabOrder(w); + g->SetFont(w->GetFont()); + if (w->GetForegroundColour().IsOk()) + g->SetForegroundColour(w->GetForegroundColour()); + WindowState& gs = EnsureState(g); + HookWindow(g, ControlKind::Generic, st->winId, st->style, st->exStyle); + gs.text = st->text; + gs.font = st->font; + if (!HasMessageHandler(pWnd, WM_PAINT)) + gs.customPaint = PaintBridge(g, &PaintGenericStatic); + g->Show(w->IsShown()); + g->Enable(w->IsThisEnabled()); + w->Destroy(); + return g; +} + +// --------------------------------------------------------------------------------------------- +// Control message processing + +namespace { + +int FirstVisibleLine(wxTextCtrl* t) { + wxTextCoord col = 0, row = 0; + if (t->HitTest(wxPoint(2, 2), &col, &row) != wxTE_HT_UNKNOWN && row > 0) + return static_cast(row); + return 0; +} + +LRESULT EditProc(wxTextCtrl* t, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + EditExtra& ex = Extra(st); + switch (msg) { + case EM_GETSEL: { + long from, to; + t->GetSelection(&from, &to); + from = WxToWinPos(t, st, from); + to = WxToWinPos(t, st, to); + if (wParam) + *reinterpret_cast(wParam) = static_cast(from); + if (lParam) + *reinterpret_cast(lParam) = static_cast(to); + return MAKELRESULT(from, to); + } + case EM_SETSEL: { + long from = static_cast(static_cast(wParam)); + long to = static_cast(static_cast(lParam)); + long len = t->GetLastPosition(); + if (from < 0) { + t->SetInsertionPoint(t->GetInsertionPoint()); + t->SelectNone(); + return 0; + } + from = WinToWxPos(t, st, from); + to = to < 0 ? len : WinToWxPos(t, st, to); + t->SetSelection(std::min(from, len), std::min(to, len)); + return 0; + } + case EM_EXSETSEL: { + auto* cr = reinterpret_cast(lParam); + long len = t->GetLastPosition(); + long to = cr->cpMax < 0 ? len : WinToWxPos(t, st, cr->cpMax); + t->SetSelection(WinToWxPos(t, st, cr->cpMin), std::min(to, len)); + return 0; + } + case EM_EXGETSEL: { + long from, to; + t->GetSelection(&from, &to); + auto* cr = reinterpret_cast(lParam); + cr->cpMin = WxToWinPos(t, st, from); + cr->cpMax = WxToWinPos(t, st, to); + return 0; + } + case EM_REPLACESEL: + t->WriteText(ToEditText(st, AnsiText(reinterpret_cast(lParam)))); + return 0; + case EM_GETMODIFY: + return ex.modified || t->IsModified(); + case EM_SETMODIFY: + ex.modified = wParam != 0; + if (!wParam) + t->DiscardEdits(); + else + t->MarkDirty(); + return 0; + case EM_GETLINECOUNT: + return std::max(1, t->GetNumberOfLines()); + case EM_LINEINDEX: { + int line = static_cast(static_cast(wParam)); + if (line < 0) { + long x, y; + t->PositionToXY(t->GetInsertionPoint(), &x, &y); + line = static_cast(y); + } + if (line >= t->GetNumberOfLines()) + return -1; + return WxToWinPos(t, st, t->XYToPosition(0, line)); + } + case EM_LINELENGTH: { + long x, y; + long pos = static_cast(wParam) < 0 ? t->GetInsertionPoint() : WinToWxPos(t, st, static_cast(wParam)); + if (!t->PositionToXY(pos, &x, &y)) + return 0; + return t->GetLineLength(y); + } + case EM_LINEFROMCHAR: + case EM_EXLINEFROMCHAR: { + long pos = static_cast(wParam) < 0 ? t->GetInsertionPoint() : WinToWxPos(t, st, static_cast(msg == EM_EXLINEFROMCHAR ? lParam : static_cast(wParam))); + long x, y; + if (!t->PositionToXY(pos, &x, &y)) + return std::max(0, t->GetNumberOfLines() - 1); + return y; + } + case EM_GETLINE: { + int line = static_cast(wParam); + char* buf = reinterpret_cast(lParam); + WORD max = *reinterpret_cast(buf); + if (line >= t->GetNumberOfLines()) + return 0; + std::string a = FromWx(t->GetLineText(line)); + size_t n = std::min(a.size(), max); + memcpy(buf, a.data(), n); + return static_cast(n); + } + case EM_LIMITTEXT: + ex.limit = static_cast(wParam); + if (!(st.style & ES_MULTILINE)) + t->SetMaxLength(static_cast(wParam)); + return 0; + case EM_GETLIMITTEXT: + return ex.limit > 0 ? ex.limit : 30000; + case EM_EXLIMITTEXT: + ex.limit = static_cast(lParam); + return 0; + case EM_CANUNDO: + return t->CanUndo(); + case EM_UNDO: + case WM_UNDO: + t->Undo(); + return TRUE; + case EM_REDO: + t->Redo(); + return TRUE; + case EM_CANREDO: + return t->CanRedo(); + case EM_EMPTYUNDOBUFFER: + return 0; + case EM_SETREADONLY: + t->SetEditable(wParam == 0); + if (wParam) + st.style |= ES_READONLY; + else + st.style &= ~ES_READONLY; + return TRUE; + case EM_SETPASSWORDCHAR: + ex.passwordChar = static_cast(wParam); + return 0; + case EM_GETPASSWORDCHAR: + return static_cast(ex.passwordChar); + case EM_GETFIRSTVISIBLELINE: + return FirstVisibleLine(t); + case EM_SCROLLCARET: + t->ShowPosition(t->GetInsertionPoint()); + return TRUE; + case EM_LINESCROLL: { + int lines = static_cast(lParam); + if (lines && IsMultilineEdit(st)) { + int count = std::max(1, t->GetNumberOfLines()); + int target = std::max(0, std::min(count - 1, FirstVisibleLine(t) + lines)); + t->ShowPosition(t->GetLastPosition()); + t->ShowPosition(t->XYToPosition(0, target)); + } + return TRUE; + } + case EM_CANPASTE: + return t->CanPaste(); + case EM_SELECTIONTYPE: { + long from, to; + t->GetSelection(&from, &to); + return from == to ? 0 : 1; + } + case EM_GETTEXTLENGTHEX: + return static_cast(FromWx(FromEditText(st, t->GetValue())).size()); + case EM_SETTABSTOPS: + case EM_SETMARGINS: + case EM_SETRECT: + case EM_SETRECTNP: + case EM_SETEVENTMASK: + case EM_SETOPTIONS: + case EM_SETTARGETDEVICE: + case EM_AUTOURLDETECT: + case EM_SETUNDOLIMIT: + case EM_HIDESELECTION: + return 0; + case EM_GETEVENTMASK: + return 0; + case EM_GETRECT: { + auto* r = reinterpret_cast(lParam); + wxSize sz = t->GetClientSize(); + r->left = r->top = 0; + r->right = sz.x; + r->bottom = sz.y; + return 0; + } + case EM_POSFROMCHAR: { + bool rich = st.kind == ControlKind::RichEdit && wParam > 0xFFFF; + long pos = WinToWxPos(t, st, static_cast(rich ? lParam : static_cast(wParam))); + wxPoint p = t->PositionToCoords(pos); + if (p == wxDefaultPosition) + p = wxPoint(0, 0); + if (rich) { + if (auto* pt = reinterpret_cast(wParam)) { + pt->x = p.x; + pt->y = p.y; + } + return 0; + } + return MAKELRESULT(p.x, p.y); + } + case EM_CHARFROMPOS: { + long pos = 0; + wxTextCoord col, row; + if (t->HitTest(wxPoint(LOWORD(lParam), HIWORD(lParam)), &col, &row) != wxTE_HT_UNKNOWN) + pos = t->XYToPosition(col, row); + return MAKELRESULT(WxToWinPos(t, st, pos), 0); + } + case EM_SETBKGNDCOLOR: + if (!wParam) { + t->SetBackgroundColour(ToWxColour(static_cast(lParam))); + t->Refresh(); + } + return 0; + case EM_GETSELTEXT: { + std::string a = FromWx(FromEditText(st, t->GetStringSelection())); + strcpy(reinterpret_cast(lParam), a.c_str()); + return static_cast(a.size()); + } + case EM_GETTEXTRANGE: { + auto* tr = reinterpret_cast(lParam); + wxString v = FromEditText(st, t->GetValue()); + long to = tr->chrg.cpMax < 0 ? static_cast(v.length()) : tr->chrg.cpMax; + std::string a = FromWx(v.Mid(tr->chrg.cpMin, to - tr->chrg.cpMin)); + strcpy(tr->lpstrText, a.c_str()); + return static_cast(a.size()); + } + case EM_SETCHARFORMAT: { + auto* cf = reinterpret_cast(lParam); + wxTextAttr attr; + if (cf->dwMask & CFM_COLOR) + attr.SetTextColour((cf->dwEffects & CFE_AUTOCOLOR) ? t->GetForegroundColour() : ToWxColour(cf->crTextColor)); + if (cf->dwMask & CFM_BOLD) + attr.SetFontWeight((cf->dwEffects & CFE_BOLD) ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL); + if (cf->dwMask & CFM_ITALIC) + attr.SetFontStyle((cf->dwEffects & CFE_ITALIC) ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL); + if (cf->dwMask & CFM_UNDERLINE) + attr.SetFontUnderlined((cf->dwEffects & CFE_UNDERLINE) != 0); + if ((cf->dwMask & CFM_SIZE) && cf->yHeight > 0) + attr.SetFontPointSize(cf->yHeight / 20); + if ((cf->dwMask & CFM_FACE) && cf->szFaceName[0]) + attr.SetFontFaceName(AnsiText(cf->szFaceName)); + if (wParam & SCF_SELECTION) { + long from, to; + t->GetSelection(&from, &to); + t->SetStyle(from, to, attr); + } else { + t->SetDefaultStyle(attr); + if (wParam & SCF_ALL) + t->SetStyle(0, t->GetLastPosition(), attr); + } + return TRUE; + } + case EM_GETCHARFORMAT: { + auto* cf = reinterpret_cast(lParam); + cf->dwMask = CFM_COLOR | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_FACE | CFM_SIZE; + wxFont f = t->GetFont(); + cf->dwEffects = (f.GetWeight() >= wxFONTWEIGHT_BOLD ? CFE_BOLD : 0) | + (f.GetStyle() == wxFONTSTYLE_ITALIC ? CFE_ITALIC : 0) | (f.GetUnderlined() ? CFE_UNDERLINE : 0); + cf->yHeight = f.GetPointSize() * 20; + cf->crTextColor = FromWxColour(t->GetForegroundColour()); + std::string face = FromWx(f.GetFaceName()); + strncpy(cf->szFaceName, face.c_str(), sizeof cf->szFaceName - 1); + cf->szFaceName[sizeof cf->szFaceName - 1] = 0; + return cf->dwMask; + } + case EM_SETPARAFORMAT: + case EM_GETPARAFORMAT: + return TRUE; + case EM_STREAMIN: { + auto* es = reinterpret_cast(lParam); + std::string data; + BYTE buf[4096]; + for (;;) { + LONG got = 0; + if (es->pfnCallback(es->dwCookie, buf, sizeof buf, &got) != 0 || got <= 0) + break; + data.append(reinterpret_cast(buf), static_cast(got)); + } + if (wParam & SF_RTF) { + if (!(wParam & SFF_SELECTION)) + t->Clear(); + InsertRtf(t, IsMultilineEdit(st), data); + return static_cast(data.size()); + } + wxString v = ToEditText(st, ToWx(data.data(), static_cast(data.size()))); + if (wParam & SFF_SELECTION) + t->WriteText(v); + else + t->SetValue(v); + return static_cast(data.size()); + } + case EM_STREAMOUT: { + auto* es = reinterpret_cast(lParam); + std::string a = FromWx(FromEditText(st, (wParam & SFF_SELECTION) ? t->GetStringSelection() : t->GetValue())); + size_t off = 0; + while (off < a.size()) { + LONG done = 0; + LONG chunk = static_cast(std::min(a.size() - off, 4096)); + if (es->pfnCallback(es->dwCookie, reinterpret_cast(&a[off]), chunk, &done) != 0 || done <= 0) + break; + off += static_cast(done); + } + return static_cast(off); + } + case EM_FINDTEXTEX: { + auto* ft = reinterpret_cast(lParam); + wxString v = FromEditText(st, t->GetValue()); + wxString needle = AnsiText(ft->lpstrText); + long start = ft->chrg.cpMin; + int pos = v.Mid(static_cast(start)).Find(needle); + if (pos == wxNOT_FOUND) + return -1; + ft->chrgText.cpMin = start + pos; + ft->chrgText.cpMax = start + pos + static_cast(needle.length()); + return ft->chrgText.cpMin; + } + case WM_CUT: + t->Cut(); + return 0; + case WM_COPY: + t->Copy(); + return 0; + case WM_PASTE: + t->Paste(); + return 0; + case WM_CLEAR: { + long from, to; + t->GetSelection(&from, &to); + if (from != to) + t->Remove(from, to); + return 0; + } + case WM_CHAR: { + UINT ch = static_cast(wParam); + if (!t->IsEditable() && ch >= 32) + return 0; + long from, to; + t->GetSelection(&from, &to); + switch (ch) { + case 1: + t->SelectAll(); + return 0; + case 3: + t->Copy(); + return 0; + case 22: + if (t->IsEditable()) + t->Paste(); + return 0; + case 24: + if (t->IsEditable()) + t->Cut(); + return 0; + case 26: + if (t->IsEditable()) + t->Undo(); + return 0; + case 8: + if (!t->IsEditable()) + return 0; + if (from != to) + t->Remove(from, to); + else if (from > 0) + t->Remove(from - 1, from); + return 0; + case 13: + if (st.style & ES_MULTILINE) + t->WriteText("\n"); + return 0; + case 9: + if ((st.style & ES_MULTILINE) && (st.style & ES_WANTRETURN)) + t->WriteText("\t"); + return 0; + default: + if (ch < 32 || ch == 127) + return 0; + break; + } + if (ex.limit > 0) { + long len = static_cast(FromEditText(st, t->GetValue()).length()); + if (len - (to - from) >= ex.limit) { + NotifyParent(t, EN_MAXTEXT); + return 0; + } + } + char a = static_cast(ch); + t->WriteText(ToWx(&a, 1)); + return 0; + } + case WM_KEYDOWN: { + UINT vk = static_cast(wParam); + long from, to; + t->GetSelection(&from, &to); + CurrentMessage* cm = GetCurrentMessageSlot(); + if (cm && cm->event && cm->msg.message == WM_KEYDOWN && cm->msg.wParam == wParam) { + cm->defaultCalled = true; + return 0; + } + if (vk == VK_DELETE && t->IsEditable()) { + if (from != to) + t->Remove(from, to); + else if (from < t->GetLastPosition()) + t->Remove(from, from + 1); + } else if (vk == VK_LEFT && from > 0) { + t->SetInsertionPoint(from - 1); + } else if (vk == VK_RIGHT && to < t->GetLastPosition()) { + t->SetInsertionPoint(to + 1); + } else if (vk == VK_HOME) { + t->SetInsertionPoint(0); + } else if (vk == VK_END) { + t->SetInsertionPointEnd(); + } + return 0; + } + case WM_GETDLGCODE: + return DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS | ((st.style & ES_WANTRETURN) ? DLGC_WANTMESSAGE : 0); + default: + handled = false; + return 0; + } +} + +int ItemCount(wxItemContainerImmutable* c) { return static_cast(c->GetCount()); } + +LRESULT ComboProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + auto* items = dynamic_cast(w); + auto* combo = wxDynamicCast(w, wxComboBox); + if (!items) { + handled = false; + return 0; + } + switch (msg) { + case CB_ADDSTRING: { + int n = items->Append(AnsiText(reinterpret_cast(lParam))); + return n; + } + case CB_INSERTSTRING: { + int index = static_cast(wParam); + wxString s = AnsiText(reinterpret_cast(lParam)); + if (index < 0 || index >= ItemCount(items)) + return items->Append(s); + return items->Insert(s, static_cast(index)); + } + case CB_DELETESTRING: { + int index = static_cast(wParam); + if (index < 0 || index >= ItemCount(items)) + return CB_ERR; + items->Delete(static_cast(index)); + return ItemCount(items); + } + case CB_RESETCONTENT: + items->Clear(); + if (combo) + combo->ChangeValue(wxString()); + return CB_OKAY; + case CB_GETCOUNT: + return ItemCount(items); + case CB_GETCURSEL: { + int sel = items->GetSelection(); + return sel == wxNOT_FOUND ? CB_ERR : sel; + } + case CB_SETCURSEL: { + int index = static_cast(wParam); + if (index < 0 || index >= ItemCount(items)) { + items->SetSelection(wxNOT_FOUND); + if (combo) + combo->ChangeValue(wxString()); + return CB_ERR; + } + items->SetSelection(index); + return index; + } + case CB_GETLBTEXT: { + int index = static_cast(wParam); + if (index < 0 || index >= ItemCount(items)) + return CB_ERR; + std::string a = FromWx(items->GetString(static_cast(index))); + strcpy(reinterpret_cast(lParam), a.c_str()); + return static_cast(a.size()); + } + case CB_GETLBTEXTLEN: { + int index = static_cast(wParam); + if (index < 0 || index >= ItemCount(items)) + return CB_ERR; + return static_cast(FromWx(items->GetString(static_cast(index))).size()); + } + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: { + wxString s = AnsiText(reinterpret_cast(lParam)); + int n = ItemCount(items); + int start = static_cast(wParam); + for (int k = 0; k < n; ++k) { + int i = (start + 1 + k + n) % n; + if (start < 0) + i = k; + wxString item = items->GetString(static_cast(i)); + bool match = msg == CB_FINDSTRINGEXACT ? item.CmpNoCase(s) == 0 : item.Lower().StartsWith(s.Lower()); + if (match) { + if (msg == CB_SELECTSTRING) + items->SetSelection(i); + return i; + } + } + return CB_ERR; + } + case CB_GETITEMDATA: { + int index = static_cast(wParam); + if (index < 0 || index >= ItemCount(items)) + return CB_ERR; + return reinterpret_cast(items->GetClientData(static_cast(index))); + } + case CB_SETITEMDATA: { + int index = static_cast(wParam); + if (index < 0 || index >= ItemCount(items)) + return CB_ERR; + items->SetClientData(static_cast(index), reinterpret_cast(lParam)); + return CB_OKAY; + } + case CB_GETEDITSEL: + if (combo) { + long from, to; + combo->GetSelection(&from, &to); + return MAKELRESULT(from, to); + } + return 0; + case CB_SETEDITSEL: + if (combo) + combo->SetSelection(static_cast(LOWORD(lParam)), static_cast(HIWORD(lParam))); + return TRUE; + case CB_LIMITTEXT: + if (combo) + combo->SetMaxLength(static_cast(wParam)); + return TRUE; + case CB_SHOWDROPDOWN: + if (combo) { + if (wParam) + combo->Popup(); + else + combo->Dismiss(); + } + return TRUE; + case CB_GETDROPPEDSTATE: + return FALSE; + case CB_GETDROPPEDCONTROLRECT: { + auto* r = reinterpret_cast(lParam); + if (r) { + wxRect sr = w->GetScreenRect(); + int visible = std::max(1, std::min(ItemCount(items), 30)); + r->left = sr.x; + r->top = sr.y; + r->right = sr.x + sr.width; + r->bottom = sr.y + sr.height + visible * (w->GetCharHeight() + 2) + 2; + } + return CB_OKAY; + } + case CB_SETITEMHEIGHT: + case CB_SETEXTENDEDUI: + case CB_SETDROPPEDWIDTH: + case CB_SETHORIZONTALEXTENT: + case CB_INITSTORAGE: + return CB_OKAY; + case CB_GETITEMHEIGHT: + return w->GetCharHeight() + 2; + case WM_CUT: + if (combo) + combo->Cut(); + return 0; + case WM_COPY: + if (combo) + combo->Copy(); + return 0; + case WM_PASTE: + if (combo) + combo->Paste(); + return 0; + case WM_CLEAR: + if (combo) { + long from, to; + combo->GetSelection(&from, &to); + if (from != to) + combo->Remove(from, to); + } + return 0; + case WM_CHAR: + if (combo) { + UINT ch = static_cast(wParam); + if (ch == 8) { + long from, to; + combo->GetSelection(&from, &to); + if (from != to) + combo->Remove(from, to); + else if (from > 0) + combo->Remove(from - 1, from); + } else if (ch >= 32) { + char a = static_cast(ch); + combo->WriteText(ToWx(&a, 1)); + } + } + return 0; + default: + handled = false; + return 0; + } + (void)st; +} + +LRESULT ListBoxProc(wxListBox* lb, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + int n = static_cast(lb->GetCount()); + int index = static_cast(wParam); + switch (msg) { + case LB_ADDSTRING: + return lb->Append(AnsiText(reinterpret_cast(lParam))); + case LB_INSERTSTRING: + if (index < 0 || index >= n) + return lb->Append(AnsiText(reinterpret_cast(lParam))); + return lb->Insert(AnsiText(reinterpret_cast(lParam)), static_cast(index)); + case LB_DELETESTRING: + if (index < 0 || index >= n) + return LB_ERR; + lb->Delete(static_cast(index)); + return n - 1; + case LB_RESETCONTENT: + lb->Clear(); + return 0; + case LB_GETCOUNT: + return n; + case LB_GETCURSEL: { + if (lb->HasMultipleSelection()) { + wxArrayInt sel; + lb->GetSelections(sel); + return sel.empty() ? LB_ERR : sel[0]; + } + int s = lb->GetSelection(); + return s == wxNOT_FOUND ? LB_ERR : s; + } + case LB_SETCURSEL: + if (index < 0 || index >= n) { + lb->SetSelection(wxNOT_FOUND); + return index < 0 ? 0 : LB_ERR; + } + lb->SetSelection(index); + return index; + case LB_GETSEL: + return index >= 0 && index < n && lb->IsSelected(index) ? 1 : 0; + case LB_SETSEL: { + int item = static_cast(lParam); + if (item == -1) { + for (int i = 0; i < n; ++i) + wParam ? lb->SetSelection(i) : lb->Deselect(i); + return 0; + } + if (item < 0 || item >= n) + return LB_ERR; + if (wParam) + lb->SetSelection(item); + else + lb->Deselect(item); + return 0; + } + case LB_GETSELCOUNT: { + wxArrayInt sel; + return lb->GetSelections(sel); + } + case LB_GETSELITEMS: { + wxArrayInt sel; + lb->GetSelections(sel); + int* out = reinterpret_cast(lParam); + int count = std::min(static_cast(sel.size()), index); + for (int i = 0; i < count; ++i) + out[i] = sel[static_cast(i)]; + return count; + } + case LB_SELITEMRANGE: + case LB_SELITEMRANGEEX: { + int first = LOWORD(lParam); + int last = HIWORD(lParam); + bool select = wParam != 0; + if (msg == LB_SELITEMRANGEEX) { + first = static_cast(wParam); + last = static_cast(lParam); + select = first <= last; + if (first > last) + std::swap(first, last); + } + for (int i = std::max(0, first); i <= std::min(last, n - 1); ++i) + select ? lb->SetSelection(i) : lb->Deselect(i); + return 0; + } + case LB_GETTEXT: { + if (index < 0 || index >= n) + return LB_ERR; + std::string a = FromWx(lb->GetString(static_cast(index))); + strcpy(reinterpret_cast(lParam), a.c_str()); + return static_cast(a.size()); + } + case LB_GETTEXTLEN: + if (index < 0 || index >= n) + return LB_ERR; + return static_cast(FromWx(lb->GetString(static_cast(index))).size()); + case LB_FINDSTRING: + case LB_FINDSTRINGEXACT: + case LB_SELECTSTRING: { + wxString s = AnsiText(reinterpret_cast(lParam)); + for (int k = 0; k < n; ++k) { + int i = index < 0 ? k : (index + 1 + k) % n; + wxString item = lb->GetString(static_cast(i)); + bool match = msg == LB_FINDSTRINGEXACT ? item.CmpNoCase(s) == 0 : item.Lower().StartsWith(s.Lower()); + if (match) { + if (msg == LB_SELECTSTRING) + lb->SetSelection(i); + return i; + } + } + return LB_ERR; + } + case LB_GETITEMDATA: + if (index < 0 || index >= n) + return LB_ERR; + return reinterpret_cast(lb->GetClientData(static_cast(index))); + case LB_SETITEMDATA: + if (index < 0 || index >= n) + return LB_ERR; + lb->SetClientData(static_cast(index), reinterpret_cast(lParam)); + return 0; + case LB_GETTOPINDEX: + return 0; + case LB_SETTOPINDEX: + if (index >= 0 && index < n) + lb->SetFirstItem(index); + return 0; + case LB_GETCARETINDEX: { + int s = lb->GetSelection(); + return s == wxNOT_FOUND ? 0 : s; + } + case LB_SETCARETINDEX: + return 0; + case LB_GETITEMRECT: { + auto* r = reinterpret_cast(lParam); + int h = lb->GetCharHeight() + 2; + r->left = 0; + r->right = lb->GetClientSize().x; + r->top = index * h; + r->bottom = r->top + h; + return 0; + } + case LB_GETITEMHEIGHT: + return lb->GetCharHeight() + 2; + case LB_SETTABSTOPS: + case LB_SETITEMHEIGHT: + case LB_SETHORIZONTALEXTENT: + case LB_SETCOLUMNWIDTH: + case LB_SETANCHORINDEX: + return 0; + case LB_GETHORIZONTALEXTENT: + return 0; + default: + handled = false; + return 0; + } + (void)st; +} + +LRESULT ButtonProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + switch (msg) { + case BM_GETCHECK: + if (auto* cb = wxDynamicCast(w, wxCheckBox)) + return cb->Get3StateValue() == wxCHK_UNDETERMINED ? BST_INDETERMINATE : (cb->GetValue() ? BST_CHECKED : BST_UNCHECKED); + if (auto* rb = wxDynamicCast(w, wxRadioButton)) + return rb->GetValue() ? BST_CHECKED : BST_UNCHECKED; + if (auto* tb = wxDynamicCast(w, wxToggleButton)) + return tb->GetValue() ? BST_CHECKED : BST_UNCHECKED; + return st.checkState; + case BM_SETCHECK: + st.checkState = static_cast(wParam); + if (auto* cb = wxDynamicCast(w, wxCheckBox)) { + if (cb->Is3State()) + cb->Set3StateValue(wParam == BST_INDETERMINATE ? wxCHK_UNDETERMINED + : (wParam == BST_CHECKED ? wxCHK_CHECKED : wxCHK_UNCHECKED)); + else + cb->SetValue(wParam == BST_CHECKED); + } else if (auto* rb = wxDynamicCast(w, wxRadioButton)) { + if (wParam == BST_CHECKED) + rb->SetValue(true); + else if (rb->GetValue()) { + // wx cannot uncheck the only checked radio button of a group directly. + rb->SetValue(false); + } + } else if (auto* tb = wxDynamicCast(w, wxToggleButton)) { + tb->SetValue(wParam == BST_CHECKED); + } else { + w->Refresh(); + } + return 0; + case BM_GETSTATE: { + LRESULT state = SendMessage(ToHwnd(w), BM_GETCHECK, 0, 0); + if (st.kind == ControlKind::OwnerDrawButton && Extra(st).pushed) + state |= BST_PUSHED; + if (w->HasFocus()) + state |= BST_FOCUS; + return state; + } + case BM_SETSTATE: + if (st.kind == ControlKind::OwnerDrawButton) { + Extra(st).pushed = wParam != 0; + w->Refresh(); + } + return 0; + case BM_SETSTYLE: { + DWORD old = st.style; + st.style = (st.style & ~0xFFFFu) | static_cast(wParam & 0xFFFF); + if ((old & BS_TYPEMASK) != (st.style & BS_TYPEMASK) && (st.style & BS_TYPEMASK) == BS_DEFPUSHBUTTON) { + if (auto* b = wxDynamicCast(w, wxButton)) + b->SetDefault(); + } + if (lParam) + w->Refresh(); + return 0; + } + case BM_CLICK: + NotifyParent(w, BN_CLICKED); + return 0; + case BM_SETIMAGE: { + ButtonExtra& bx = Extra(st); + LRESULT old = 0; + if (wParam == IMAGE_BITMAP) { + old = reinterpret_cast(bx.image); + bx.image = reinterpret_cast(lParam); + wxBitmap* bmp = BitmapFromHandle(bx.image); + if (auto* b = wxDynamicCast(w, wxButton)) { + if (bmp && bmp->IsOk()) + b->SetBitmap(*bmp); + } + } else if (wParam == IMAGE_ICON) { + old = reinterpret_cast(bx.icon); + bx.icon = reinterpret_cast(lParam); + if (auto* b = wxDynamicCast(w, wxButton)) { + wxIcon* icon = reinterpret_cast(bx.icon); + if (icon && icon->IsOk()) + b->SetBitmap(*icon); + } + } + w->Refresh(); + return old; + } + case BM_GETIMAGE: { + ButtonExtra& bx = Extra(st); + return wParam == IMAGE_ICON ? reinterpret_cast(bx.icon) : reinterpret_cast(bx.image); + } + case WM_GETDLGCODE: + if (st.kind == ControlKind::RadioButton) + return DLGC_BUTTON | DLGC_RADIOBUTTON; + return DLGC_BUTTON | ((st.style & BS_TYPEMASK) == BS_DEFPUSHBUTTON ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON); + default: + handled = false; + return 0; + } +} + +LRESULT StaticProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + switch (msg) { + case STM_SETIMAGE: + case STM_SETICON: { + LRESULT old = reinterpret_cast(st.image); + st.image = reinterpret_cast(lParam); + auto* sb = wxDynamicCast(w, wxStaticBitmap); + if (sb) { + if (msg == STM_SETICON || wParam == IMAGE_ICON) { + wxIcon* icon = reinterpret_cast(lParam); + if (icon && icon->IsOk()) + sb->SetIcon(*icon); + } else { + wxBitmap* bmp = BitmapFromHandle(reinterpret_cast(lParam)); + if (bmp && bmp->IsOk()) { + sb->SetBitmap(*bmp); + if (!(st.style & SS_REALSIZECONTROL) && !(st.style & SS_CENTERIMAGE)) + sb->SetSize(bmp->GetSize()); + } + } + } else { + w->Refresh(); + } + return old; + } + case STM_GETIMAGE: + case STM_GETICON: + return reinterpret_cast(st.image); + case WM_GETDLGCODE: + return DLGC_STATIC; + default: + handled = false; + return 0; + } +} + +LRESULT RangeProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + RangeExtra& r = Extra(st); + auto* gauge = wxDynamicCast(w, wxGauge); + auto* slider = wxDynamicCast(w, wxSlider); + auto applyGauge = [&] { + if (!gauge) + return; + int range = std::max(1, r.maxValue - r.minValue); + gauge->SetRange(range); + gauge->SetValue(std::max(0, std::min(range, r.pos - r.minValue))); + }; + if (st.kind == ControlKind::Progress) { + switch (msg) { + case PBM_SETRANGE: { + LRESULT old = MAKELRESULT(r.minValue, r.maxValue); + r.minValue = LOWORD(lParam); + r.maxValue = HIWORD(lParam); + applyGauge(); + return old; + } + case PBM_SETRANGE32: { + LRESULT old = MAKELRESULT(r.minValue, r.maxValue); + r.minValue = static_cast(wParam); + r.maxValue = static_cast(lParam); + applyGauge(); + return old; + } + case PBM_GETRANGE: { + auto* range = reinterpret_cast(lParam); + if (range) { + range[0] = r.minValue; + range[1] = r.maxValue; + } + return wParam ? r.minValue : r.maxValue; + } + case PBM_SETPOS: { + int old = r.pos; + r.pos = static_cast(wParam); + applyGauge(); + return old; + } + case PBM_DELTAPOS: { + int old = r.pos; + r.pos += static_cast(wParam); + applyGauge(); + return old; + } + case PBM_SETSTEP: { + int old = r.step; + r.step = static_cast(wParam); + return old; + } + case PBM_STEPIT: { + int old = r.pos; + r.pos += r.step; + if (r.pos > r.maxValue) + r.pos = r.minValue + (r.pos - r.maxValue); + applyGauge(); + return old; + } + case PBM_GETPOS: + return r.pos; + case PBM_SETBARCOLOR: + case PBM_SETBKCOLOR: + return CLR_DEFAULT; + case PBM_SETMARQUEE: + if (gauge && wParam) + gauge->Pulse(); + return TRUE; + default: + break; + } + } + if (st.kind == ControlKind::Slider) { + switch (msg) { + case TBM_GETPOS: + return slider ? slider->GetValue() : r.pos; + case TBM_SETPOS: + r.pos = static_cast(lParam); + if (slider) + slider->SetValue(r.pos); + return 0; + case TBM_SETRANGE: + r.minValue = LOWORD(lParam); + r.maxValue = HIWORD(lParam); + if (slider) + slider->SetRange(r.minValue, std::max(r.minValue, r.maxValue)); + return 0; + case TBM_SETRANGEMIN: + r.minValue = static_cast(lParam); + if (slider) + slider->SetRange(r.minValue, std::max(r.minValue, r.maxValue)); + return 0; + case TBM_SETRANGEMAX: + r.maxValue = static_cast(lParam); + if (slider) + slider->SetRange(r.minValue, std::max(r.minValue, r.maxValue)); + return 0; + case TBM_GETRANGEMIN: + return slider ? slider->GetMin() : r.minValue; + case TBM_GETRANGEMAX: + return slider ? slider->GetMax() : r.maxValue; + case TBM_SETTICFREQ: + if (slider) + slider->SetTickFreq(std::max(1, static_cast(wParam))); + return 0; + case TBM_SETPAGESIZE: { + int old = slider ? slider->GetPageSize() : 0; + if (slider) + slider->SetPageSize(static_cast(lParam)); + return old; + } + case TBM_GETPAGESIZE: + return slider ? slider->GetPageSize() : 0; + case TBM_SETLINESIZE: { + int old = slider ? slider->GetLineSize() : 0; + if (slider) + slider->SetLineSize(static_cast(lParam)); + return old; + } + case TBM_GETLINESIZE: + return slider ? slider->GetLineSize() : 1; + case TBM_SETTIC: + if (slider) + slider->SetTick(static_cast(lParam)); + return TRUE; + case TBM_CLEARTICS: + if (slider) + slider->ClearTicks(); + return 0; + case TBM_GETNUMTICS: + return 2; + case TBM_SETSEL: + r.selStart = static_cast(LOWORD(lParam)); + r.selEnd = static_cast(HIWORD(lParam)); + return 0; + case TBM_SETSELSTART: + r.selStart = static_cast(lParam); + return 0; + case TBM_SETSELEND: + r.selEnd = static_cast(lParam); + return 0; + case TBM_CLEARSEL: + r.selStart = r.selEnd = 0; + return 0; + case TBM_GETSELSTART: + return r.selStart; + case TBM_GETSELEND: + return r.selEnd; + default: + break; + } + } + if (st.kind == ControlKind::Spin) { + switch (msg) { + case UDM_SETRANGE: + r.maxValue = static_cast(LOWORD(lParam)); + r.minValue = static_cast(HIWORD(lParam)); + return 0; + case UDM_SETRANGE32: + r.minValue = static_cast(wParam); + r.maxValue = static_cast(lParam); + return 0; + case UDM_GETRANGE: + return MAKELRESULT(r.maxValue, r.minValue); + case UDM_GETRANGE32: + if (wParam) + *reinterpret_cast(wParam) = r.minValue; + if (lParam) + *reinterpret_cast(lParam) = r.maxValue; + return 0; + case UDM_SETPOS: + case UDM_SETPOS32: { + int old = r.pos; + r.pos = msg == UDM_SETPOS ? static_cast(LOWORD(lParam)) : static_cast(lParam); + UpdateSpinBuddy(w, st); + return old; + } + case UDM_GETPOS: + return MAKELRESULT(ReadSpinBuddy(st), 0); + case UDM_GETPOS32: + if (lParam) + *reinterpret_cast(lParam) = FALSE; + return ReadSpinBuddy(st); + case UDM_SETBUDDY: { + CWnd* old = st.buddy; + st.buddy = CWnd::FromHandle(reinterpret_cast(wParam)); + return reinterpret_cast(old ? old->m_hWnd : nullptr); + } + case UDM_GETBUDDY: + return reinterpret_cast(st.buddy ? st.buddy->m_hWnd : nullptr); + case UDM_SETBASE: + case UDM_SETACCEL: + return TRUE; + case UDM_GETBASE: + return 10; + default: + break; + } + } + if (st.kind == ControlKind::ScrollBar) { + switch (msg) { + case SBM_SETPOS: + if (auto* sb = wxDynamicCast(w, wxScrollBar)) { + int old = sb->GetThumbPosition(); + sb->SetThumbPosition(static_cast(wParam) - r.minValue); + return old + r.minValue; + } + return 0; + case SBM_GETPOS: + if (auto* sb = wxDynamicCast(w, wxScrollBar)) + return sb->GetThumbPosition() + r.minValue; + return 0; + case SBM_SETRANGE: + case SBM_SETRANGEREDRAW: + if (auto* sb = wxDynamicCast(w, wxScrollBar)) { + r.minValue = static_cast(wParam); + r.maxValue = static_cast(lParam); + int thumb = std::max(1, r.page); + int pageSize = r.page > 0 ? r.page : std::max(1, (r.maxValue - r.minValue) / 10); + sb->SetScrollbar(sb->GetThumbPosition(), thumb, std::max(thumb, r.maxValue - r.minValue + 1), pageSize); + } + return 0; + case SBM_SETSCROLLINFO: { + auto* si = reinterpret_cast(lParam); + auto* sb = wxDynamicCast(w, wxScrollBar); + if (!si || !sb) + return 0; + int pos = sb->GetThumbPosition() + r.minValue; + if (si->fMask & SIF_RANGE) { + r.minValue = si->nMin; + r.maxValue = si->nMax; + } + if (si->fMask & SIF_PAGE) + r.page = static_cast(si->nPage); + if (si->fMask & SIF_POS) + pos = si->nPos; + int thumb = std::max(1, r.page); + int range = std::max(thumb, r.maxValue - r.minValue + 1); + pos = std::max(0, std::min(pos - r.minValue, range - thumb)); + sb->SetScrollbar(pos, thumb, range, r.page > 0 ? r.page : std::max(1, range / 10), wParam != 0); + return pos + r.minValue; + } + case SBM_GETSCROLLINFO: { + auto* si = reinterpret_cast(lParam); + auto* sb = wxDynamicCast(w, wxScrollBar); + if (!si || !sb) + return FALSE; + if (si->fMask & SIF_RANGE) { + si->nMin = r.minValue; + si->nMax = r.maxValue; + } + if (si->fMask & SIF_PAGE) + si->nPage = static_cast(std::max(0, r.page)); + if (si->fMask & SIF_POS) + si->nPos = sb->GetThumbPosition() + r.minValue; + if (si->fMask & SIF_TRACKPOS) + si->nTrackPos = sb->GetThumbPosition() + r.minValue; + return TRUE; + } + case SBM_GETRANGE: + if (wParam) + *reinterpret_cast(wParam) = r.minValue; + if (lParam) + *reinterpret_cast(lParam) = r.maxValue; + return 0; + default: + break; + } + } + handled = false; + return 0; +} + +LRESULT TabProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + TabExtra& tx = Extra(st); + (void)wParam; + (void)lParam; + switch (msg) { + case WM_GETDLGCODE: + return DLGC_WANTARROWS; + default: + handled = false; + break; + } + (void)w; + (void)tx; + return 0; +} + +} // namespace + +LRESULT ControlWindowProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + switch (st.kind) { + case ControlKind::Edit: + case ControlKind::RichEdit: + if (auto* t = AsText(w)) + return EditProc(t, st, msg, wParam, lParam, handled); + break; + case ControlKind::ComboBox: + case ControlKind::ComboList: + return ComboProc(w, st, msg, wParam, lParam, handled); + case ControlKind::ListBox: + if (auto* lb = wxDynamicCast(w, wxListBox)) + return ListBoxProc(lb, st, msg, wParam, lParam, handled); + break; + case ControlKind::PushButton: + case ControlKind::CheckBox: + case ControlKind::RadioButton: + case ControlKind::OwnerDrawButton: + case ControlKind::GroupBox: + return ButtonProc(w, st, msg, wParam, lParam, handled); + case ControlKind::Static: + case ControlKind::StaticBitmap: + case ControlKind::StaticFrame: + return StaticProc(w, st, msg, wParam, lParam, handled); + case ControlKind::Progress: + case ControlKind::Slider: + case ControlKind::Spin: + case ControlKind::ScrollBar: + return RangeProc(w, st, msg, wParam, lParam, handled); + case ControlKind::Tab: + return TabProc(w, st, msg, wParam, lParam, handled); + case ControlKind::ListView: + return ListViewProc(w, st, msg, wParam, lParam, handled); + case ControlKind::Scintilla: + return ScintillaWindowProc(w, msg, wParam, lParam, handled); + default: + break; + } + handled = false; + return 0; +} + +// --------------------------------------------------------------------------------------------- +// WM_CTLCOLOR emulation + +void ApplyCtlColor(wxWindow* control) { + WindowState* st = GetState(control); + wxWindow* parent = LogicalParent(control); + if (!st || !parent || !IsManagedWindow(parent) || !PermanentWnd(parent)) + return; + UINT msg = WM_CTLCOLORSTATIC; + switch (st->kind) { + case ControlKind::Edit: + case ControlKind::RichEdit: + case ControlKind::ComboBox: + msg = (st->style & ES_READONLY) || !control->IsEnabled() ? WM_CTLCOLORSTATIC : WM_CTLCOLOREDIT; + break; + case ControlKind::ListBox: + case ControlKind::ComboList: + msg = WM_CTLCOLORLISTBOX; + break; + case ControlKind::PushButton: + case ControlKind::OwnerDrawButton: + msg = WM_CTLCOLORBTN; + break; + case ControlKind::Static: + case ControlKind::StaticBitmap: + case ControlKind::CheckBox: + case ControlKind::RadioButton: + case ControlKind::GroupBox: + msg = WM_CTLCOLORSTATIC; + break; + default: + return; + } + CWnd* parentWnd = PermanentWnd(parent); + if (!HasMessageHandler(parentWnd, WM_CTLCOLOR) && !HasMessageHandler(st->permanent, WM_CTLCOLOR + WM_REFLECT_BASE)) + return; + wxBitmap scratch(1, 1); + wxMemoryDC mdc(scratch); + CDC* cdc = WrapDC(&mdc, control); + COLORREF defaultText = 0xFFFFFFFF; + cdc->SetTextColor(defaultText); + LRESULT r = DispatchMessageTo(ToHwnd(parent), msg, reinterpret_cast(cdc->m_hDC), + reinterpret_cast(ToHwnd(control))); + COLORREF text = cdc->GetTextColor(); + COLORREF bk = cdc->GetBkColor(); + int bkMode = cdc->GetBkMode(); + UnwrapDC(cdc); + if (text != defaultText) + control->SetForegroundColour(ToWxColour(text)); + if (r) { + wxBrush brush = BrushFromHandle(reinterpret_cast(r)); + if (brush.IsOk() && brush.GetStyle() != wxBRUSHSTYLE_TRANSPARENT) + control->SetBackgroundColour(brush.GetColour()); + else if (bkMode == OPAQUE) + control->SetBackgroundColour(ToWxColour(bk)); + } + control->Refresh(); +} + +} // namespace mfcwx diff --git a/port/mfcwx/src/controls_internal.h b/port/mfcwx/src/controls_internal.h new file mode 100644 index 000000000..4941cb8f1 --- /dev/null +++ b/port/mfcwx/src/controls_internal.h @@ -0,0 +1,42 @@ +#pragma once + +// Control internals shared by controls.cpp, listctrl.cpp and ctrlclasses.cpp. + +#include "windows_impl.h" + +#include +#include +#include + +class wxTextCtrl; + +namespace mfcwx { + +// Kind-specific data of a control, kept in WindowState::extra. Each control kind uses one type. +template +T& Extra(WindowState& st) { + if (!st.extra) { + st.extra = new T(); + st.deleteExtra = [&st] { delete static_cast(st.extra); st.extra = nullptr; }; + } + return *static_cast(st.extra); +} + +struct TabExtra { + std::vector> items; + int current = -1; + wxSize itemSize; +}; + +// controls.cpp: tab header geometry in client coordinates. +int TabHeaderHeight(wxWindow* w); +std::vector TabRects(wxWindow* w); + +// listctrl.cpp +void BindListViewEvents(wxWindow* w); +LRESULT ListViewProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled); + +// ctrlclasses.cpp: inserts RTF (ANSI code page) at the selection of a rich edit control. +void InsertRtf(wxTextCtrl* t, bool multiline, const std::string& rtf); + +} // namespace mfcwx diff --git a/port/mfcwx/src/crt.cpp b/port/mfcwx/src/crt.cpp new file mode 100644 index 000000000..e9353cd5f --- /dev/null +++ b/port/mfcwx/src/crt.cpp @@ -0,0 +1,850 @@ +#include "afx.h" +#include "process.h" +#include "runtime.h" + +#include +#include +#include +#include + +#include +#include +#include +#ifdef __APPLE__ +#include +#else +#include +#endif + +#undef fopen +#undef rename +#undef remove + +using namespace mfcwx; + +namespace { + +char* FormatUnsigned(unsigned long long v, char* buf, int radix, bool negative) { + if (!buf) + return buf; + if (radix < 2 || radix > 36) { + buf[0] = 0; + errno = EINVAL; + return buf; + } + char tmp[72]; + int n = 0; + do { + int d = static_cast(v % static_cast(radix)); + tmp[n++] = static_cast(d < 10 ? '0' + d : 'a' + d - 10); + v /= static_cast(radix); + } while (v); + char* p = buf; + if (negative) + *p++ = '-'; + while (n) + *p++ = tmp[--n]; + *p = 0; + return buf; +} + +char* FormatSigned(long long value, char* buf, int radix, unsigned long long unsignedValue) { + if (radix == 10 && value < 0) + return FormatUnsigned(0ULL - static_cast(value), buf, 10, true); + return FormatUnsigned(unsignedValue, buf, radix, false); +} + +// MSVC's long is 32 bits: negative values print as 32-bit two's complement in non-decimal radixes. +unsigned long long LongBits(long value) { + if (value < 0 && value >= INT32_MIN) + return static_cast(value); + return static_cast(value); +} + +int CopyChecked(const std::string& s, char* buf, size_t size) { + if (!buf || size == 0) + return EINVAL; + if (s.size() + 1 > size) { + buf[0] = 0; + return ERANGE; + } + memcpy(buf, s.c_str(), s.size() + 1); + return 0; +} + +thread_local char t_cvtBuffer[400]; + +int FilterFopenMode(const char* mode, char* out, size_t size) { + size_t o = 0; + for (const char* p = mode ? mode : "r"; *p && *p != ',' && o + 1 < size; ++p) + if (strchr("rwa+bx", *p)) + out[o++] = *p; + out[o] = 0; + return static_cast(o); +} + +void FillFindData(const WIN32_FIND_DATA& fd, struct _finddata_t* data) { + memset(data, 0, sizeof *data); + data->attrib = fd.dwFileAttributes & (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH); + data->time_create = FileTimeToUnix(fd.ftCreationTime); + data->time_access = FileTimeToUnix(fd.ftLastAccessTime); + data->time_write = FileTimeToUnix(fd.ftLastWriteTime); + data->size = (static_cast(fd.nFileSizeHigh) << 32) | fd.nFileSizeLow; + strncpy(data->name, fd.cFileName, sizeof data->name - 1); +} + +} // namespace + +int mfcwx_open(const char* name, int flags, ...) { + mode_t mode = 0666; + if (flags & O_CREAT) { + va_list ap; + va_start(ap, flags); + int requested = va_arg(ap, int); + va_end(ap); + if (requested & ~(S_IRUSR | S_IWUSR)) + mode = static_cast(requested); + else if (!(requested & S_IWUSR)) + mode = 0444; + } + return open(FsPath(name).c_str(), flags, mode); +} + +int mfcwx_unlink(const char* name) { return unlink(FsPath(name).c_str()); } + +int mfcwx_rmdir(const char* name) { return rmdir(FsPath(name).c_str()); } + +int mfcwx_chdir(const char* name) { return chdir(FsPath(name).c_str()); } + +int mfcwx_access(const char* name, int mode) { return access(FsPath(name).c_str(), mode & 6); } + +int mfcwx_chmod(const char* name, int mode) { + std::string path = FsPath(name); + struct stat st; + if (stat(path.c_str(), &st) != 0) + return -1; + mode_t m = st.st_mode & 07777; + if (mode & S_IWUSR) + m |= S_IWUSR; + else + m &= ~static_cast(S_IWUSR | S_IWGRP | S_IWOTH); + return chmod(path.c_str(), m); +} + +int mfcwx_rename(const char* from, const char* to) { return rename(FsPath(from).c_str(), FsPath(to).c_str()); } + +FILE* mfcwx_fopen(const char* name, const char* mode) { + if (!name) { + errno = EINVAL; + return nullptr; + } + char m[16]; + FilterFopenMode(mode, m, sizeof m); + return fopen(FsPath(name).c_str(), m); +} + +size_t mfcwx_msize(void* p) { +#ifdef __APPLE__ + return p ? malloc_size(p) : 0; +#else + return p ? malloc_usable_size(p) : 0; +#endif +} + +unsigned int mfcwx_rotl(unsigned int v, int s) { + s &= 31; + return s ? (v << s) | (v >> (32 - s)) : v; +} + +unsigned int mfcwx_rotr(unsigned int v, int s) { + s &= 31; + return s ? (v >> s) | (v << (32 - s)) : v; +} + +void mfcwx_normalize_path(char* path) { + if (!path) + return; + for (char* p = path; *p; ++p) + if (*p == '\\') + *p = '/'; + if (path[0] && path[1] == ':' && isalpha(static_cast(path[0]))) + memmove(path, path + 2, strlen(path + 2) + 1); +} + +char* mfcwx_getcwd(char* buf, int size) { + char native[PATH_MAX]; + if (!getcwd(native, sizeof native)) + return nullptr; + std::string app = AppPath(native); + if (!buf) { + size_t bytes = std::max(static_cast(size > 0 ? size : 0), app.size() + 1); + buf = static_cast(malloc(bytes)); + if (!buf) { + errno = ENOMEM; + return nullptr; + } + } else if (size <= 0 || app.size() + 1 > static_cast(size)) { + errno = ERANGE; + return nullptr; + } + memcpy(buf, app.c_str(), app.size() + 1); + return buf; +} + +int _mkdir(const char* path) { return mkdir(FsPath(path).c_str(), 0777); } + +char* _strupr(char* s) { + for (char* p = s; p && *p; ++p) + if (*p >= 'a' && *p <= 'z') + *p = static_cast(*p - 'a' + 'A'); + return s; +} + +char* _strlwr(char* s) { + for (char* p = s; p && *p; ++p) + if (*p >= 'A' && *p <= 'Z') + *p = static_cast(*p - 'A' + 'a'); + return s; +} + +char* _strrev(char* s) { + if (s) + std::reverse(s, s + strlen(s)); + return s; +} + +char* strupr(char* s) { return _strupr(s); } + +char* strlwr(char* s) { return _strlwr(s); } + +char* strrev(char* s) { return _strrev(s); } + +char* _strset(char* s, int c) { + for (char* p = s; p && *p; ++p) + *p = static_cast(c); + return s; +} + +char* _strnset(char* s, int c, size_t n) { + for (char* p = s; p && *p && n; ++p, --n) + *p = static_cast(c); + return s; +} + +char* _itoa(int value, char* buf, int radix) { return FormatSigned(value, buf, radix, static_cast(value)); } + +char* _ltoa(long value, char* buf, int radix) { return FormatSigned(value, buf, radix, LongBits(value)); } + +char* _ultoa(unsigned long value, char* buf, int radix) { return FormatUnsigned(value, buf, radix, false); } + +char* _i64toa(long long value, char* buf, int radix) { + return FormatSigned(value, buf, radix, static_cast(value)); +} + +char* _ui64toa(unsigned long long value, char* buf, int radix) { return FormatUnsigned(value, buf, radix, false); } + +char* itoa(int value, char* buf, int radix) { return _itoa(value, buf, radix); } + +char* ltoa(long value, char* buf, int radix) { return _ltoa(value, buf, radix); } + +char* ultoa(unsigned long value, char* buf, int radix) { return _ultoa(value, buf, radix); } + +char* _gcvt(double value, int digits, char* buf) { + if (!buf) + return buf; + if (digits < 1) + digits = 1; + char tmp[400]; + snprintf(tmp, sizeof tmp, "%.*g", digits, value); + std::string s = tmp; + if (std::isfinite(value) && s.find('.') == std::string::npos) { + size_t e = s.find('e'); + if (e == std::string::npos) + s += '.'; + else + s.insert(e, "."); + } + strcpy(buf, s.c_str()); + return buf; +} + +char* gcvt(double value, int digits, char* buf) { return _gcvt(value, digits, buf); } + +char* _ecvt(double value, int digits, int* dec, int* sign) { + char* out = t_cvtBuffer; + int dummyDec, dummySign; + if (!dec) + dec = &dummyDec; + if (!sign) + sign = &dummySign; + *sign = std::signbit(value) ? 1 : 0; + value = std::fabs(value); + if (digits > 340) + digits = 340; + if (!std::isfinite(value)) { + strcpy(out, std::isnan(value) ? "1#QNAN" : "1#INF"); + *dec = 1; + return out; + } + if (digits <= 0) { + out[0] = 0; + *dec = value == 0 ? 0 : static_cast(std::floor(std::log10(value))) + 1; + return out; + } + if (value == 0) { + memset(out, '0', static_cast(digits)); + out[digits] = 0; + *dec = 0; + return out; + } + char tmp[400]; + snprintf(tmp, sizeof tmp, "%.*e", digits - 1, value); + int o = 0; + const char* p = tmp; + for (; *p && *p != 'e'; ++p) + if (*p != '.') + out[o++] = *p; + out[o] = 0; + *dec = (*p == 'e' ? atoi(p + 1) : 0) + 1; + return out; +} + +char* _fcvt(double value, int digits, int* dec, int* sign) { + char* out = t_cvtBuffer; + int dummyDec, dummySign; + if (!dec) + dec = &dummyDec; + if (!sign) + sign = &dummySign; + *sign = std::signbit(value) ? 1 : 0; + value = std::fabs(value); + if (digits < 0) + digits = 0; + if (!std::isfinite(value)) { + strcpy(out, std::isnan(value) ? "1#QNAN" : "1#INF"); + *dec = 1; + return out; + } + char tmp[400]; + if (value >= 1e300) { + snprintf(tmp, sizeof tmp, "%.0f", value); + digits = 0; + } else { + snprintf(tmp, sizeof tmp, "%.*f", std::min(digits, 60), value); + } + std::string s = tmp; + size_t point = s.find('.'); + std::string intPart = s.substr(0, point); + std::string frac = point == std::string::npos ? std::string() : s.substr(point + 1); + std::string all = intPart + frac; + int d = static_cast(intPart.size()); + size_t lead = 0; + while (lead < all.size() && all[lead] == '0') + ++lead; + if (lead == all.size()) { + std::string zeros(static_cast(std::min(digits, 60)), '0'); + strcpy(out, zeros.c_str()); + *dec = 0; + return out; + } + all.erase(0, lead); + d -= static_cast(lead); + strncpy(out, all.c_str(), sizeof t_cvtBuffer - 1); + out[sizeof t_cvtBuffer - 1] = 0; + *dec = d; + return out; +} + +long _filelength(int fd) { + struct stat st; + return fstat(fd, &st) == 0 ? static_cast(st.st_size) : -1L; +} + +long filelength(int fd) { return _filelength(fd); } + +long long _filelengthi64(int fd) { + struct stat st; + return fstat(fd, &st) == 0 ? static_cast(st.st_size) : -1LL; +} + +int _chsize(int fd, long size) { return ftruncate(fd, size); } + +int _eof(int fd) { + struct stat st; + off_t pos = lseek(fd, 0, SEEK_CUR); + if (pos < 0 || fstat(fd, &st) != 0) + return -1; + return pos >= st.st_size ? 1 : 0; +} + +int _setmode(int fd, int) { return fcntl(fd, F_GETFL) == -1 ? -1 : 0x8000; } + +void _splitpath(const char* path, char* drive, char* dir, char* fname, char* ext) { + std::string p = path ? path : ""; + std::string d, rest; + if (p.size() >= 2 && p[1] == ':') { + d = p.substr(0, 2); + p.erase(0, 2); + } + size_t sep = p.find_last_of("\\/"); + std::string directory = sep == std::string::npos ? std::string() : p.substr(0, sep + 1); + rest = sep == std::string::npos ? p : p.substr(sep + 1); + size_t dot = rest.rfind('.'); + std::string name = dot == std::string::npos ? rest : rest.substr(0, dot); + std::string extension = dot == std::string::npos ? std::string() : rest.substr(dot); + auto put = [](char* out, const std::string& s, size_t max) { + if (!out) + return; + size_t n = std::min(s.size(), max - 1); + memcpy(out, s.data(), n); + out[n] = 0; + }; + put(drive, d, _MAX_DRIVE); + put(dir, directory, _MAX_DIR); + put(fname, name, _MAX_FNAME); + put(ext, extension, _MAX_EXT); +} + +void _makepath(char* path, const char* drive, const char* dir, const char* fname, const char* ext) { + if (!path) + return; + std::string out; + if (drive && *drive) { + out += drive[0]; + out += ':'; + } + if (dir && *dir) { + out += dir; + if (out.back() != '\\' && out.back() != '/') + out += '\\'; + } + if (fname) + out += fname; + if (ext && *ext) { + if (ext[0] != '.') + out += '.'; + out += ext; + } + size_t n = std::min(out.size(), static_cast(_MAX_PATH - 1)); + memcpy(path, out.data(), n); + path[n] = 0; +} + +char* _fullpath(char* abs, const char* rel, size_t size) { + std::string full = FullAppPath(rel && *rel ? rel : "."); + if (rel && *rel) { + char last = rel[strlen(rel) - 1]; + if ((last == '\\' || last == '/') && full.back() != '\\') + full += '\\'; + } + if (!abs) { + abs = static_cast(malloc(std::max(static_cast(_MAX_PATH), full.size() + 1))); + if (!abs) { + errno = ENOMEM; + return nullptr; + } + } else if (full.size() + 1 > size) { + errno = ERANGE; + return nullptr; + } + memcpy(abs, full.c_str(), full.size() + 1); + return abs; +} + +int _getdrive(void) { return 3; } + +int _chdrive(int drive) { return drive >= 1 && drive <= 26 ? 0 : -1; } + +char* _mktemp(char* templ) { + if (!templ) + return nullptr; + size_t len = strlen(templ); + if (len < 6 || strcmp(templ + len - 6, "XXXXXX") != 0) { + errno = EINVAL; + return nullptr; + } + char* x = templ + len - 6; + char digits[8]; + snprintf(digits, sizeof digits, "%05u", static_cast(getpid() % 100000)); + for (char c = 'a'; c <= 'z'; ++c) { + x[0] = c; + memcpy(x + 1, digits, 5); + if (access(FsPath(templ).c_str(), F_OK) != 0) + return templ; + } + memcpy(x, "XXXXXX", 6); + errno = EEXIST; + return nullptr; +} + +char* _tempnam(const char* dir, const char* prefix) { + std::string base; + struct stat st; + if (dir && *dir && stat(FsPath(dir).c_str(), &st) == 0 && S_ISDIR(st.st_mode)) + base = dir; + else + base = AppPath(TempDirectory().c_str()); + while (base.size() > 1 && (base.back() == '\\' || base.back() == '/')) + base.pop_back(); + static std::atomic counter{1}; + for (int attempt = 0; attempt < 100000; ++attempt) { + unsigned n = counter.fetch_add(1); + std::string name = base + "\\" + (prefix ? prefix : "") + std::to_string(n); + if (access(FsPath(name.c_str()).c_str(), F_OK) != 0) + return strdup(name.c_str()); + } + errno = EEXIST; + return nullptr; +} + +int _vsnprintf_s(char* buf, size_t size, size_t count, const char* fmt, va_list args) { + if (!buf || size == 0 || !fmt) { + errno = EINVAL; + return -1; + } + char translated[4096]; + fmt = AfxTranslateFormat(fmt, translated, sizeof translated); + va_list copy; + va_copy(copy, args); + int n = vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + if (n < 0) { + buf[0] = 0; + return -1; + } + size_t needed = static_cast(n); + if (count == static_cast(-1)) { + vsnprintf(buf, size, fmt, args); + return needed >= size ? -1 : n; + } + size_t limit = std::min(count, size - 1); + if (needed <= limit) { + vsnprintf(buf, size, fmt, args); + return n; + } + if (count < size) { + std::string tmp(needed + 1, '\0'); + vsnprintf(&tmp[0], tmp.size(), fmt, args); + memcpy(buf, tmp.data(), count); + buf[count] = 0; + return -1; + } + buf[0] = 0; + errno = ERANGE; + return -1; +} + +int vsprintf_s(char* buf, size_t size, const char* fmt, va_list args) { + if (!buf || size == 0 || !fmt) { + errno = EINVAL; + return -1; + } + char translated[4096]; + fmt = AfxTranslateFormat(fmt, translated, sizeof translated); + int n = vsnprintf(buf, size, fmt, args); + if (n < 0 || static_cast(n) >= size) { + buf[0] = 0; + errno = ERANGE; + return -1; + } + return n; +} + +int sprintf_s(char* buf, size_t size, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + int n = vsprintf_s(buf, size, fmt, args); + va_end(args); + return n; +} + +int _snprintf_s(char* buf, size_t size, size_t count, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + int n = _vsnprintf_s(buf, size, count, fmt, args); + va_end(args); + return n; +} + +int strcpy_s(char* dst, size_t size, const char* src) { + if (!dst || size == 0) + return EINVAL; + if (!src) { + dst[0] = 0; + return EINVAL; + } + return CopyChecked(src, dst, size); +} + +int strncpy_s(char* dst, size_t size, const char* src, size_t count) { + if (!dst || size == 0) + return EINVAL; + if (!src) { + dst[0] = 0; + return count ? EINVAL : 0; + } + size_t len = strlen(src); + if (count == static_cast(-1)) { + size_t n = std::min(len, size - 1); + memcpy(dst, src, n); + dst[n] = 0; + return n < len ? 80 : 0; + } + size_t n = std::min(len, count); + if (n >= size) { + dst[0] = 0; + return ERANGE; + } + memcpy(dst, src, n); + dst[n] = 0; + return 0; +} + +int strcat_s(char* dst, size_t size, const char* src) { + if (!dst || size == 0) + return EINVAL; + size_t len = strnlen(dst, size); + if (len == size || !src) { + dst[0] = 0; + return EINVAL; + } + if (len + strlen(src) >= size) { + dst[0] = 0; + return ERANGE; + } + strcpy(dst + len, src); + return 0; +} + +int strncat_s(char* dst, size_t size, const char* src, size_t count) { + if (!dst || size == 0) + return EINVAL; + size_t len = strnlen(dst, size); + if (len == size || (!src && count)) { + dst[0] = 0; + return EINVAL; + } + size_t add = src ? strlen(src) : 0; + if (count != static_cast(-1)) + add = std::min(add, count); + bool truncated = false; + if (len + add >= size) { + if (count != static_cast(-1)) { + dst[0] = 0; + return ERANGE; + } + add = size - 1 - len; + truncated = true; + } + memcpy(dst + len, src, add); + dst[len + add] = 0; + return truncated ? 80 : 0; +} + +char* strtok_s(char* s, const char* delim, char** ctx) { return strtok_r(s, delim, ctx); } + +int _strupr_s(char* s, size_t size) { + if (!s || strnlen(s, size) == size) + return EINVAL; + _strupr(s); + return 0; +} + +int _strlwr_s(char* s, size_t size) { + if (!s || strnlen(s, size) == size) + return EINVAL; + _strlwr(s); + return 0; +} + +int _itoa_s(int value, char* buf, size_t size, int radix) { + char tmp[72]; + _itoa(value, tmp, radix); + return CopyChecked(tmp, buf, size); +} + +int _ltoa_s(long value, char* buf, size_t size, int radix) { + char tmp[72]; + _ltoa(value, tmp, radix); + return CopyChecked(tmp, buf, size); +} + +int _i64toa_s(long long value, char* buf, size_t size, int radix) { + char tmp[72]; + _i64toa(value, tmp, radix); + return CopyChecked(tmp, buf, size); +} + +int fopen_s(FILE** f, const char* name, const char* mode) { + if (!f) + return EINVAL; + *f = mfcwx_fopen(name, mode); + return *f ? 0 : errno; +} + +int memcpy_s(void* dst, size_t dstSize, const void* src, size_t count) { + if (count == 0) + return 0; + if (!dst) + return EINVAL; + if (!src || count > dstSize) { + memset(dst, 0, dstSize); + return src ? ERANGE : EINVAL; + } + memcpy(dst, src, count); + return 0; +} + +int memmove_s(void* dst, size_t dstSize, const void* src, size_t count) { + if (count == 0) + return 0; + if (!dst || !src) + return EINVAL; + if (count > dstSize) + return ERANGE; + memmove(dst, src, count); + return 0; +} + +int localtime_s(struct tm* out, const time_t* t) { + if (!out || !t) + return EINVAL; + return localtime_r(t, out) ? 0 : EINVAL; +} + +int gmtime_s(struct tm* out, const time_t* t) { + if (!out || !t) + return EINVAL; + return gmtime_r(t, out) ? 0 : EINVAL; +} + +int asctime_s(char* buf, size_t size, const struct tm* t) { + if (!buf || !t) + return EINVAL; + char tmp[64]; + if (!asctime_r(t, tmp)) + return EINVAL; + return CopyChecked(tmp, buf, size); +} + +int ctime_s(char* buf, size_t size, const time_t* t) { + if (!buf || !t) + return EINVAL; + struct tm tm; + if (!localtime_r(t, &tm)) + return EINVAL; + return asctime_s(buf, size, &tm); +} + +int _dupenv_s(char** buf, size_t* len, const char* name) { + if (!buf || !name) + return EINVAL; + const char* v = getenv(name); + if (!v) { + *buf = nullptr; + if (len) + *len = 0; + return 0; + } + *buf = strdup(v); + if (len) + *len = strlen(v) + 1; + return *buf ? 0 : ENOMEM; +} + +char* _strdate(char* buf) { + time_t now = time(nullptr); + struct tm tm; + localtime_r(&now, &tm); + strftime(buf, 9, "%m/%d/%y", &tm); + return buf; +} + +char* _strtime(char* buf) { + time_t now = time(nullptr); + struct tm tm; + localtime_r(&now, &tm); + strftime(buf, 9, "%H:%M:%S", &tm); + return buf; +} + +void _tzset(void) { tzset(); } + +intptr_t _findfirst(const char* pattern, struct _finddata_t* data) { + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFileA(pattern, &fd); + if (h == INVALID_HANDLE_VALUE) { + errno = ENOENT; + return -1; + } + if (data) + FillFindData(fd, data); + return reinterpret_cast(h); +} + +int _findnext(intptr_t handle, struct _finddata_t* data) { + WIN32_FIND_DATA fd; + if (!FindNextFileA(reinterpret_cast(handle), &fd)) { + errno = ENOENT; + return -1; + } + if (data) + FillFindData(fd, data); + return 0; +} + +int _findclose(intptr_t handle) { + if (!FindClose(reinterpret_cast(handle))) { + errno = ENOENT; + return -1; + } + return 0; +} + +int mfcwx_memicmp(const void* a, const void* b, size_t n) { + const unsigned char* p = static_cast(a); + const unsigned char* q = static_cast(b); + for (size_t i = 0; i < n; ++i) { + int d = tolower(p[i]) - tolower(q[i]); + if (d) + return d; + } + return 0; +} + +intptr_t _spawnl(int mode, const char* cmdname, const char* arg0, ...) { + if (!cmdname) { + errno = EINVAL; + return -1; + } + // Like the Microsoft CRT, the arguments are joined with spaces into one command line. + std::string cmd = arg0 ? arg0 : cmdname; + va_list ap; + va_start(ap, arg0); + if (arg0) + for (const char* a = va_arg(ap, const char*); a; a = va_arg(ap, const char*)) + cmd += std::string(" ") + a; + va_end(ap); + STARTUPINFO si; + memset(&si, 0, sizeof si); + si.cb = sizeof si; + PROCESS_INFORMATION pi; + if (!CreateProcessA(cmdname, &cmd[0], nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi)) { + errno = GetLastError() == ERROR_FILE_NOT_FOUND ? ENOENT : ENOEXEC; + return -1; + } + CloseHandle(pi.hThread); + if (mode == _P_WAIT) { + DWORD code = 0; + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &code); + CloseHandle(pi.hProcess); + return static_cast(code); + } + if (mode == _P_OVERLAY) + exit(0); + if (mode == _P_NOWAIT || mode == _P_NOWAITO) + return reinterpret_cast(pi.hProcess); + CloseHandle(pi.hProcess); + return 0; +} diff --git a/port/mfcwx/src/cstring.cpp b/port/mfcwx/src/cstring.cpp new file mode 100644 index 000000000..9051fdfc0 --- /dev/null +++ b/port/mfcwx/src/cstring.cpp @@ -0,0 +1,701 @@ +#include "mfcwx/cstring.h" +#include "bridge.h" + +#include +#include +#include +#include + +namespace mfcwx { +bool LoadResourceString(UINT id, std::string& out); +} + +namespace { + +char g_empty[1] = {0}; + +bool IsAsciiSpace(char ch) { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f'; } + +std::string WideToAnsi(const wchar_t* s) { + std::string out; + if (!s) + return out; + for (; *s; ++s) { + char ch; + mfcwx::UnicodeToAnsi(*s, ch); + out.push_back(ch); + } + return out; +} + +} // namespace + +const char* AfxTranslateFormat(const char* fmt, char* buffer, size_t size) { + if (!fmt || !strchr(fmt, 'I')) + return fmt; + size_t o = 0; + for (const char* p = fmt; *p && o + 4 < size;) { + if (*p != '%') { + buffer[o++] = *p++; + continue; + } + buffer[o++] = *p++; + if (*p == '%') { + buffer[o++] = *p++; + continue; + } + while (*p && strchr("-+ #0123456789.*", *p) && o + 4 < size) + buffer[o++] = *p++; + if (p[0] == 'I' && p[1] == '6' && p[2] == '4') { + buffer[o++] = 'l'; + buffer[o++] = 'l'; + p += 3; + } else if (p[0] == 'I' && p[1] == '3' && p[2] == '2') { + p += 3; + } else if (p[0] == 'I' && strchr("diouxX", p[1])) { + buffer[o++] = 'z'; + p += 1; + } + } + buffer[o] = 0; + return buffer; +} + +CString::CString() noexcept : m_p(g_empty), m_len(0), m_cap(0) {} + +CString::CString(const CString& s) : CString() { Assign(s.m_p, s.m_len); } + +CString::CString(CString&& s) noexcept : m_p(s.m_p), m_len(s.m_len), m_cap(s.m_cap) { + s.m_p = g_empty; + s.m_len = 0; + s.m_cap = 0; +} + +CString::CString(const char* s) : CString() { + if (s && IS_INTRESOURCE(s)) + LoadString(static_cast(reinterpret_cast(s))); + else if (s) + Assign(s, static_cast(strlen(s))); +} + +CString::CString(const unsigned char* s) : CString(reinterpret_cast(s)) {} + +CString::CString(const char* s, int length) : CString() { + if (s && length > 0) + Assign(s, length); +} + +CString::CString(char ch, int repeat) : CString() { + if (repeat > 0) { + Reserve(repeat); + memset(m_p, ch, repeat); + m_len = repeat; + m_p[m_len] = 0; + } +} + +CString::CString(const wchar_t* s) : CString() { + std::string a = WideToAnsi(s); + Assign(a.data(), static_cast(a.size())); +} + +CString::~CString() { + if (m_p != g_empty) + free(m_p); +} + +CString& CString::operator=(const CString& s) { + if (this != &s) + Assign(s.m_p, s.m_len); + return *this; +} + +CString& CString::operator=(CString&& s) noexcept { + if (this != &s) { + CString tmp(std::move(s)); + swap(*this, tmp); + } + return *this; +} + +CString& CString::operator=(const char* s) { + if (!s) { + Empty(); + return *this; + } + if (s >= m_p && s <= m_p + m_len) { + CString copy(s); + swap(*this, copy); + return *this; + } + Assign(s, static_cast(strlen(s))); + return *this; +} + +CString& CString::operator=(const unsigned char* s) { return *this = reinterpret_cast(s); } + +CString& CString::operator=(const wchar_t* s) { + std::string a = WideToAnsi(s); + Assign(a.data(), static_cast(a.size())); + return *this; +} + +CString& CString::operator=(char ch) { + Assign(&ch, 1); + return *this; +} + +void CString::Reserve(int capacity) { + if (capacity <= m_cap) + return; + int newCap = std::max(capacity, m_cap + m_cap / 2); + if (newCap < 15) + newCap = 15; + char* p = static_cast(malloc(static_cast(newCap) + 1)); + memcpy(p, m_p, static_cast(m_len) + 1); + if (m_p != g_empty) + free(m_p); + m_p = p; + m_cap = newCap; +} + +void CString::Assign(const char* s, int length) { + if (length <= 0) { + Empty(); + return; + } + if (s >= m_p && s < m_p + m_cap + 1) { + std::string copy(s, static_cast(length)); + Reserve(length); + memcpy(m_p, copy.data(), static_cast(length)); + } else { + Reserve(length); + memcpy(m_p, s, static_cast(length)); + } + m_len = length; + m_p[m_len] = 0; +} + +void CString::Empty() { + if (m_p != g_empty) + free(m_p); + m_p = g_empty; + m_len = 0; + m_cap = 0; +} + +char* CString::GetBuffer() { + Reserve(m_len); + if (m_p == g_empty) + Reserve(1); + return m_p; +} + +char* CString::GetBuffer(int minLength) { + Reserve(std::max(minLength, 1)); + return m_p; +} + +char* CString::GetBufferSetLength(int length) { + Reserve(std::max(length, 1)); + m_len = std::max(length, 0); + m_p[m_len] = 0; + return m_p; +} + +void CString::ReleaseBuffer(int newLength) { + if (m_p == g_empty) + return; + if (newLength < 0) + newLength = static_cast(strnlen(m_p, static_cast(m_cap) + 1)); + if (newLength > m_cap) + newLength = m_cap; + m_len = newLength; + m_p[m_len] = 0; +} + +void CString::Truncate(int length) { + if (length < m_len && length >= 0) { + m_len = length; + m_p[m_len] = 0; + } +} + +void CString::SetString(const char* s) { *this = s; } + +void CString::SetString(const char* s, int length) { + if (!s) + Empty(); + else + Assign(s, length); +} + +void CString::Append(const char* s, int length) { + if (!s || length <= 0) + return; + if (s >= m_p && s < m_p + m_cap + 1) { + std::string copy(s, static_cast(length)); + Append(copy.data(), length); + return; + } + Reserve(m_len + length); + memcpy(m_p + m_len, s, static_cast(length)); + m_len += length; + m_p[m_len] = 0; +} + +void CString::Append(const char* s) { + if (s) + Append(s, static_cast(strlen(s))); +} + +CString& CString::operator+=(const CString& s) { + Append(s.m_p, s.m_len); + return *this; +} + +CString& CString::operator+=(const char* s) { + Append(s); + return *this; +} + +CString& CString::operator+=(char ch) { + Append(&ch, 1); + return *this; +} + +CString& CString::operator+=(const wchar_t* s) { + std::string a = WideToAnsi(s); + Append(a.data(), static_cast(a.size())); + return *this; +} + +int CString::Compare(const char* s) const { return strcmp(m_p, s ? s : ""); } + +int CString::CompareNoCase(const char* s) const { return strcasecmp(m_p, s ? s : ""); } + +CString CString::Mid(int first) const { return Mid(first, m_len - first); } + +CString CString::Mid(int first, int count) const { + if (first < 0) + first = 0; + if (count < 0) + count = 0; + if (first > m_len) + first = m_len; + if (first + count > m_len) + count = m_len - first; + return CString(m_p + first, count); +} + +CString CString::Left(int count) const { + if (count < 0) + count = 0; + return CString(m_p, std::min(count, m_len)); +} + +CString CString::Right(int count) const { + if (count < 0) + count = 0; + count = std::min(count, m_len); + return CString(m_p + m_len - count, count); +} + +CString CString::SpanIncluding(const char* charSet) const { + return Left(static_cast(strspn(m_p, charSet ? charSet : ""))); +} + +CString CString::SpanExcluding(const char* charSet) const { + return Left(static_cast(strcspn(m_p, charSet ? charSet : ""))); +} + +CString CString::Tokenize(const char* tokens, int& start) const { + if (start < 0 || start >= m_len || !tokens) { + start = -1; + return CString(); + } + const char* p = m_p + start; + p += strspn(p, tokens); + if (*p == 0) { + start = -1; + return CString(); + } + int len = static_cast(strcspn(p, tokens)); + CString result(p, len); + start = static_cast(p - m_p) + len + 1; + return result; +} + +CString& CString::MakeUpper() { + for (int i = 0; i < m_len; ++i) + if (m_p[i] >= 'a' && m_p[i] <= 'z') + m_p[i] = static_cast(m_p[i] - 'a' + 'A'); + return *this; +} + +CString& CString::MakeLower() { + for (int i = 0; i < m_len; ++i) + if (m_p[i] >= 'A' && m_p[i] <= 'Z') + m_p[i] = static_cast(m_p[i] - 'A' + 'a'); + return *this; +} + +CString& CString::MakeReverse() { + std::reverse(m_p, m_p + m_len); + return *this; +} + +int CString::Replace(char oldCh, char newCh) { + int count = 0; + for (int i = 0; i < m_len; ++i) + if (m_p[i] == oldCh) { + m_p[i] = newCh; + ++count; + } + return count; +} + +int CString::Replace(const char* oldStr, const char* newStr) { + if (!oldStr || !*oldStr) + return 0; + if (!newStr) + newStr = ""; + std::string src(m_p, static_cast(m_len)); + std::string result; + size_t oldLen = strlen(oldStr); + size_t pos = 0; + int count = 0; + for (;;) { + size_t hit = src.find(oldStr, pos, oldLen); + if (hit == std::string::npos) + break; + result.append(src, pos, hit - pos); + result.append(newStr); + pos = hit + oldLen; + ++count; + } + if (count) { + result.append(src, pos, std::string::npos); + Assign(result.data(), static_cast(result.size())); + } + return count; +} + +int CString::Remove(char ch) { + int o = 0; + for (int i = 0; i < m_len; ++i) + if (m_p[i] != ch) + m_p[o++] = m_p[i]; + int removed = m_len - o; + m_len = o; + if (m_p != g_empty) + m_p[m_len] = 0; + return removed; +} + +int CString::Insert(int index, char ch) { + char buf[2] = {ch, 0}; + return Insert(index, buf); +} + +int CString::Insert(int index, const char* s) { + if (index < 0) + index = 0; + if (index > m_len) + index = m_len; + int add = s ? static_cast(strlen(s)) : 0; + if (add) { + std::string copy(s, static_cast(add)); + Reserve(m_len + add); + memmove(m_p + index + add, m_p + index, static_cast(m_len - index) + 1); + memcpy(m_p + index, copy.data(), static_cast(add)); + m_len += add; + } + return m_len; +} + +int CString::Delete(int index, int count) { + if (index < 0) + index = 0; + if (count > 0 && index < m_len) { + count = std::min(count, m_len - index); + memmove(m_p + index, m_p + index + count, static_cast(m_len - index - count) + 1); + m_len -= count; + } + return m_len; +} + +CString& CString::TrimLeft() { + int i = 0; + while (i < m_len && IsAsciiSpace(m_p[i])) + ++i; + Delete(0, i); + return *this; +} + +CString& CString::TrimLeft(char target) { + int i = 0; + while (i < m_len && m_p[i] == target) + ++i; + Delete(0, i); + return *this; +} + +CString& CString::TrimLeft(const char* targets) { + if (!targets) + return *this; + int i = 0; + while (i < m_len && strchr(targets, m_p[i])) + ++i; + Delete(0, i); + return *this; +} + +CString& CString::TrimRight() { + int i = m_len; + while (i > 0 && IsAsciiSpace(m_p[i - 1])) + --i; + Truncate(i); + return *this; +} + +CString& CString::TrimRight(char target) { + int i = m_len; + while (i > 0 && m_p[i - 1] == target) + --i; + Truncate(i); + return *this; +} + +CString& CString::TrimRight(const char* targets) { + if (!targets) + return *this; + int i = m_len; + while (i > 0 && strchr(targets, m_p[i - 1])) + --i; + Truncate(i); + return *this; +} + +int CString::Find(char ch, int start) const { + if (start < 0) + start = 0; + for (int i = start; i < m_len; ++i) + if (m_p[i] == ch) + return i; + return -1; +} + +int CString::Find(const char* sub, int start) const { + if (!sub || start < 0 || start > m_len) + return -1; + const char* hit = strstr(m_p + start, sub); + return hit ? static_cast(hit - m_p) : -1; +} + +int CString::ReverseFind(char ch) const { + for (int i = m_len - 1; i >= 0; --i) + if (m_p[i] == ch) + return i; + return -1; +} + +int CString::FindOneOf(const char* charSet) const { + if (!charSet) + return -1; + for (int i = 0; i < m_len; ++i) + if (strchr(charSet, m_p[i])) + return i; + return -1; +} + +void CString::FormatV(const char* fmt, va_list args) { + char translated[4096]; + fmt = AfxTranslateFormat(fmt, translated, sizeof translated); + va_list copy; + va_copy(copy, args); + int n = vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + if (n <= 0) { + Empty(); + return; + } + std::string buf(static_cast(n) + 1, '\0'); + vsnprintf(&buf[0], buf.size(), fmt, args); + Assign(buf.data(), n); +} + +void CString::AppendFormatV(const char* fmt, va_list args) { + CString tmp; + tmp.FormatV(fmt, args); + *this += tmp; +} + +void CString::Format(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + FormatV(fmt, args); + va_end(args); +} + +void CString::Format(UINT formatId, ...) { + CString fmt; + fmt.LoadString(formatId); + va_list args; + va_start(args, formatId); + FormatV(fmt, args); + va_end(args); +} + +void CString::AppendFormat(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + AppendFormatV(fmt, args); + va_end(args); +} + +void CString::AppendFormat(UINT formatId, ...) { + CString fmt; + fmt.LoadString(formatId); + va_list args; + va_start(args, formatId); + AppendFormatV(fmt, args); + va_end(args); +} + +static void FormatMessageImpl(CString& out, const char* fmt, va_list args) { + // %1..%99 insert arguments, optionally typed as %1!d!; arguments default to strings. + const char* argv[100] = {}; + std::string result; + std::string typeSpec[100]; + int maxArg = 0; + for (const char* p = fmt; *p; ++p) { + if (*p == '%' && p[1] >= '1' && p[1] <= '9') { + int n = p[1] - '0'; + const char* q = p + 2; + if (*q >= '0' && *q <= '9') + n = n * 10 + (*q++ - '0'); + if (*q == '!') { + const char* e = strchr(q + 1, '!'); + if (e) + typeSpec[n] = std::string(q + 1, e); + } + maxArg = std::max(maxArg, n); + } + } + long long values[100] = {}; + for (int i = 1; i <= maxArg; ++i) { + if (typeSpec[i].empty() || typeSpec[i].back() == 's') + argv[i] = va_arg(args, const char*); + else + values[i] = va_arg(args, int); + } + for (const char* p = fmt; *p; ++p) { + if (*p == '%' && p[1] >= '1' && p[1] <= '9') { + int n = p[1] - '0'; + const char* q = p + 2; + if (*q >= '0' && *q <= '9') + n = n * 10 + (*q++ - '0'); + if (*q == '!') { + const char* e = strchr(q + 1, '!'); + if (e) + q = e + 1; + } + if (typeSpec[n].empty() || typeSpec[n].back() == 's') { + result += argv[n] ? argv[n] : ""; + } else { + char buf[64]; + std::string f = "%" + typeSpec[n]; + snprintf(buf, sizeof buf, f.c_str(), static_cast(values[n])); + result += buf; + } + p = q - 1; + } else if (*p == '%' && p[1] == '%') { + result += '%'; + ++p; + } else if (*p == '%' && p[1] == 'n') { + result += '\n'; + ++p; + } else { + result += *p; + } + } + out = result.c_str(); +} + +void CString::FormatMessage(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + FormatMessageImpl(*this, fmt, args); + va_end(args); +} + +void CString::FormatMessage(UINT formatId, ...) { + CString fmt; + fmt.LoadString(formatId); + va_list args; + va_start(args, formatId); + FormatMessageImpl(*this, fmt, args); + va_end(args); +} + +BOOL CString::LoadString(UINT id) { + std::string s; + if (!mfcwx::LoadResourceString(id, s)) { + Empty(); + return FALSE; + } + Assign(s.data(), static_cast(s.size())); + return TRUE; +} + +BSTR CString::AllocSysString() const { + wxString w = mfcwx::ToWx(m_p, m_len); + std::wstring ws = w.ToStdWstring(); + BSTR b = static_cast(malloc((ws.size() + 1) * sizeof(wchar_t))); + wcscpy(b, ws.c_str()); + return b; +} + +BSTR CString::SetSysString(BSTR* bstr) const { + if (*bstr) + free(*bstr); + *bstr = AllocSysString(); + return *bstr; +} + +CString operator+(const CString& a, const CString& b) { + CString r(a); + r += b; + return r; +} + +CString operator+(const CString& a, const char* b) { + CString r(a); + r += b; + return r; +} + +CString operator+(const char* a, const CString& b) { + CString r(a); + r += b; + return r; +} + +CString operator+(const CString& a, char b) { + CString r(a); + r += b; + return r; +} + +CString operator+(char a, const CString& b) { + CString r(a); + r += b; + return r; +} + +CString operator+(const CString& a, const wchar_t* b) { + CString r(a); + r += b; + return r; +} diff --git a/port/mfcwx/src/ctrlclasses.cpp b/port/mfcwx/src/ctrlclasses.cpp new file mode 100644 index 000000000..e4f8d531e --- /dev/null +++ b/port/mfcwx/src/ctrlclasses.cpp @@ -0,0 +1,1526 @@ +#include "controls_internal.h" + +#include "afxcmn.h" +#include "afxext.h" + +#include +#include +#include + +#include +#include +#include +#include + +namespace mfcwx { + +namespace { + +struct RtfFormat { + bool bold = false; + bool italic = false; + bool underline = false; + int color = 0; + int font = -1; + int halfPoints = 0; + bool skip = false; + bool colorTable = false; + bool fontTable = false; +}; + +class RtfWriter { +public: + RtfWriter(wxTextCtrl* t, bool multiline) : m_t(t), m_multiline(multiline), m_default(t->GetDefaultStyle()) {} + ~RtfWriter() { m_t->SetDefaultStyle(m_default); } + + void Parse(const std::string& rtf) { + std::vector stack; + RtfFormat cur; + size_t i = 0; + while (i < rtf.size()) { + char c = rtf[i]; + if (c == '{') { + stack.push_back(cur); + ++i; + } else if (c == '}') { + Flush(); + if (cur.fontTable && m_fontId >= 0) + EndFont(); + if (stack.empty()) + break; + cur = stack.back(); + stack.pop_back(); + ++i; + } else if (c == '\\') { + i = Control(rtf, i + 1, cur); + } else if (c == '\r' || c == '\n') { + ++i; + } else { + Text(cur, c); + ++i; + } + } + Flush(); + } + +private: + size_t Control(const std::string& rtf, size_t i, RtfFormat& cur) { + if (i >= rtf.size()) + return i; + char c = rtf[i]; + if (!isalpha(static_cast(c))) { + switch (c) { + case '\'': { + if (i + 2 < rtf.size()) { + std::string hex = rtf.substr(i + 1, 2); + Text(cur, static_cast(strtol(hex.c_str(), nullptr, 16))); + } + return i + 3; + } + case '*': + cur.skip = true; + return i + 1; + case '~': + Text(cur, static_cast(0xA0)); + return i + 1; + case '_': + Text(cur, '-'); + return i + 1; + case '\r': + case '\n': + Text(cur, '\n'); + return i + 1; + default: + Text(cur, c); + return i + 1; + } + } + size_t start = i; + while (i < rtf.size() && isalpha(static_cast(rtf[i]))) + ++i; + std::string word = rtf.substr(start, i - start); + bool hasParam = false; + long param = 0; + size_t numStart = i; + if (i < rtf.size() && (rtf[i] == '-' || isdigit(static_cast(rtf[i])))) { + ++i; + while (i < rtf.size() && isdigit(static_cast(rtf[i]))) + ++i; + param = strtol(rtf.substr(numStart, i - numStart).c_str(), nullptr, 10); + hasParam = true; + } + if (i < rtf.size() && rtf[i] == ' ') + ++i; + Word(word, hasParam, param, cur); + return i; + } + + void Word(const std::string& w, bool hasParam, long param, RtfFormat& cur) { + bool on = !hasParam || param != 0; + if (cur.colorTable) { + int* component = w == "red" ? &m_r : w == "green" ? &m_g : w == "blue" ? &m_b : nullptr; + if (component) { + *component = static_cast(param); + m_hasColor = true; + } + return; + } + if (cur.fontTable) { + if (w == "f") { + m_fontId = static_cast(param); + m_fontName.clear(); + } + return; + } + if (w == "par" || w == "line") { + Text(cur, '\n'); + } else if (w == "tab") { + Text(cur, '\t'); + } else if (w == "colortbl") { + Flush(); + cur.colorTable = true; + } else if (w == "fonttbl") { + Flush(); + cur.fontTable = true; + } else if (w == "stylesheet" || w == "info" || w == "pict" || w == "header" || w == "footer" || + w == "object" || w == "listtable" || w == "generator") { + Flush(); + cur.skip = true; + } else if (w == "b") { + Flush(); + cur.bold = on; + } else if (w == "i") { + Flush(); + cur.italic = on; + } else if (w == "ul") { + Flush(); + cur.underline = on; + } else if (w == "ulnone") { + Flush(); + cur.underline = false; + } else if (w == "cf") { + Flush(); + cur.color = static_cast(param); + } else if (w == "f") { + Flush(); + cur.font = static_cast(param); + } else if (w == "fs") { + Flush(); + cur.halfPoints = static_cast(param); + } else if (w == "plain") { + Flush(); + cur.bold = cur.italic = cur.underline = false; + cur.color = 0; + cur.halfPoints = 0; + } + } + + void Text(RtfFormat& cur, char c) { + if (cur.skip) + return; + if (cur.colorTable) { + if (c == ';') { + m_colors.push_back(m_hasColor ? wxColour(m_r, m_g, m_b) : wxColour()); + m_r = m_g = m_b = 0; + m_hasColor = false; + } + return; + } + if (cur.fontTable) { + if (c == ';') + EndFont(); + else if (m_fontId >= 0) + m_fontName += c; + return; + } + if (c == '\n' && !m_multiline) + c = ' '; + if (!m_run.empty() && !SameFormat(cur)) + Flush(); + if (m_run.empty()) + m_runFormat = cur; + m_run += c; + } + + void EndFont() { + if (m_fontId >= 0) + m_fonts[m_fontId] = ToWx(m_fontName.c_str()); + m_fontId = -1; + m_fontName.clear(); + } + + bool SameFormat(const RtfFormat& f) const { + return f.bold == m_runFormat.bold && f.italic == m_runFormat.italic && f.underline == m_runFormat.underline && + f.color == m_runFormat.color && f.font == m_runFormat.font && f.halfPoints == m_runFormat.halfPoints; + } + + void Flush() { + if (m_run.empty()) + return; + const RtfFormat& f = m_runFormat; + wxTextAttr attr = m_default; + if (f.color > 0 && f.color < static_cast(m_colors.size()) && m_colors[f.color].IsOk()) + attr.SetTextColour(m_colors[f.color]); + else + attr.SetTextColour(m_default.HasTextColour() ? m_default.GetTextColour() : m_t->GetForegroundColour()); + attr.SetFontWeight(f.bold ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL); + attr.SetFontStyle(f.italic ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL); + attr.SetFontUnderlined(f.underline); + if (f.halfPoints > 0) + attr.SetFontPointSize(std::max(1, f.halfPoints / 2)); + auto face = m_fonts.find(f.font); + if (face != m_fonts.end() && !face->second.empty()) + attr.SetFontFaceName(face->second); + m_t->SetDefaultStyle(attr); + m_t->WriteText(ToWx(m_run.data(), static_cast(m_run.size()))); + m_run.clear(); + } + + wxTextCtrl* m_t; + bool m_multiline; + wxTextAttr m_default; + std::string m_run; + RtfFormat m_runFormat; + std::vector m_colors; + std::map m_fonts; + int m_fontId = -1; + std::string m_fontName; + int m_r = 0; + int m_g = 0; + int m_b = 0; + bool m_hasColor = false; +}; + +} // namespace + +void InsertRtf(wxTextCtrl* t, bool multiline, const std::string& rtf) { + if (!t) + return; + long from, to; + t->GetSelection(&from, &to); + if (from != to) + t->Remove(from, to); + t->SetInsertionPoint(from); + RtfWriter writer(t, multiline); + writer.Parse(rtf); +} + +} // namespace mfcwx + +using namespace mfcwx; + +namespace { + +LRESULT Send(const CWnd* w, UINT msg, WPARAM wParam = 0, LPARAM lParam = 0) { + return ::SendMessage(w->m_hWnd, msg, wParam, lParam); +} + +int CopyText(const wxString& s, char* buf, int cch) { + if (!buf || cch <= 0) + return 0; + std::string a = FromWx(s); + size_t n = std::min(a.size(), static_cast(cch - 1)); + memcpy(buf, a.data(), n); + buf[n] = 0; + return static_cast(n); +} + +TabExtra* TabsOf(const CWnd* w) { + WindowState* st = w->m_hWnd ? GetState(w->GetWx()) : nullptr; + return st && st->kind == ControlKind::Tab ? &Extra(*st) : nullptr; +} + +struct ToolTipExtra { + struct Tool { + HWND hwnd; + UINT_PTR id; + wxString text; + }; + std::vector tools; + bool active = true; + int maxWidth = -1; +}; + +ToolTipExtra* TipsOf(const CWnd* w) { + WindowState* st = w->m_hWnd ? GetState(w->GetWx()) : nullptr; + return st && st->kind == ControlKind::Generic && !st->customPaint ? &Extra(*st) : nullptr; +} + +void ApplyTool(const ToolTipExtra::Tool& tool, bool active) { + wxWindow* w = ToWx(tool.hwnd); + if (!IsManagedWindow(w)) + return; + if (active && !tool.text.empty()) + w->SetToolTip(tool.text); + else + w->UnsetToolTip(); +} + +wxString ResourceText(UINT id) { + std::string s; + return LoadResourceString(id, s) ? ToWx(s.c_str()) : wxString(); +} + +wxString CallbackToolText(HWND hwndTool, HWND tooltip, UINT_PTR id) { + wxWindow* parent = LogicalParent(ToWx(hwndTool)); + if (!parent) + return wxString(); + NMTTDISPINFO di; + memset(&di, 0, sizeof di); + di.hdr.hwndFrom = tooltip; + di.hdr.idFrom = id ? id : reinterpret_cast(hwndTool); + di.hdr.code = TTN_NEEDTEXT; + di.uFlags = id ? 0 : TTF_IDISHWND; + DispatchMessageTo(ToHwnd(parent), WM_NOTIFY, di.hdr.idFrom, reinterpret_cast(&di)); + if (di.lpszText && IS_INTRESOURCE(di.lpszText)) + return ResourceText(static_cast(reinterpret_cast(di.lpszText))); + if (di.lpszText && di.lpszText != LPSTR_TEXTCALLBACK) + return ToWx(di.lpszText); + return ToWx(di.szText); +} + +} // namespace + +IMPLEMENT_DYNAMIC(CStatic, CWnd) +IMPLEMENT_DYNAMIC(CButton, CWnd) +IMPLEMENT_DYNAMIC(CEdit, CWnd) +IMPLEMENT_DYNAMIC(CListBox, CWnd) +IMPLEMENT_DYNAMIC(CCheckListBox, CListBox) +IMPLEMENT_DYNAMIC(CComboBox, CWnd) +IMPLEMENT_DYNAMIC(CScrollBar, CWnd) +IMPLEMENT_DYNAMIC(CProgressCtrl, CWnd) +IMPLEMENT_DYNAMIC(CSliderCtrl, CWnd) +IMPLEMENT_DYNAMIC(CSpinButtonCtrl, CWnd) +IMPLEMENT_DYNAMIC(CTreeCtrl, CWnd) +IMPLEMENT_DYNAMIC(CTabCtrl, CWnd) +IMPLEMENT_DYNAMIC(CToolTipCtrl, CWnd) +IMPLEMENT_DYNAMIC(CRichEditCtrl, CWnd) +IMPLEMENT_DYNAMIC(CBitmapButton, CButton) + +// --------------------------------------------------------------------------------------------- +// CStatic + +BOOL CStatic::Create(const char* lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("Static", lpszText, dwStyle, rect, pParentWnd, nID); +} + +HICON CStatic::SetIcon(HICON hIcon) { + return reinterpret_cast(SendMessage(STM_SETICON, reinterpret_cast(hIcon), 0)); +} + +HICON CStatic::GetIcon() const { return reinterpret_cast(Send(this, STM_GETICON)); } + +HBITMAP CStatic::SetBitmap(HBITMAP hBitmap) { + return reinterpret_cast(SendMessage(STM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast(hBitmap))); +} + +HBITMAP CStatic::GetBitmap() const { return reinterpret_cast(Send(this, STM_GETIMAGE, IMAGE_BITMAP)); } + +HCURSOR CStatic::SetCursor(HCURSOR hCursor) { + return reinterpret_cast(SendMessage(STM_SETIMAGE, IMAGE_CURSOR, reinterpret_cast(hCursor))); +} + +HCURSOR CStatic::GetCursor() { return reinterpret_cast(SendMessage(STM_GETIMAGE, IMAGE_CURSOR)); } + +void CStatic::DrawItem(LPDRAWITEMSTRUCT) {} + +BOOL CStatic::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { + if (CWnd::OnChildNotify(message, wParam, lParam, pResult)) + return TRUE; + if (message != WM_DRAWITEM) + return FALSE; + DrawItem(reinterpret_cast(lParam)); + return TRUE; +} + +// --------------------------------------------------------------------------------------------- +// CButton + +BOOL CButton::Create(const char* lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("Button", lpszCaption, dwStyle, rect, pParentWnd, nID); +} + +UINT CButton::GetState() const { return static_cast(Send(this, BM_GETSTATE)); } +void CButton::SetState(BOOL bHighlight) { SendMessage(BM_SETSTATE, static_cast(bHighlight)); } +int CButton::GetCheck() const { return static_cast(Send(this, BM_GETCHECK)); } +void CButton::SetCheck(int nCheck) { SendMessage(BM_SETCHECK, static_cast(nCheck)); } +UINT CButton::GetButtonStyle() const { return static_cast(GetStyle() & 0xFFFF); } + +void CButton::SetButtonStyle(UINT nStyle, BOOL bRedraw) { + SendMessage(BM_SETSTYLE, static_cast(nStyle), static_cast(bRedraw)); +} + +HICON CButton::SetIcon(HICON hIcon) { + return reinterpret_cast(SendMessage(BM_SETIMAGE, IMAGE_ICON, reinterpret_cast(hIcon))); +} + +HICON CButton::GetIcon() const { return reinterpret_cast(Send(this, BM_GETIMAGE, IMAGE_ICON)); } + +HBITMAP CButton::SetBitmap(HBITMAP hBitmap) { + return reinterpret_cast(SendMessage(BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast(hBitmap))); +} + +HBITMAP CButton::GetBitmap() const { return reinterpret_cast(Send(this, BM_GETIMAGE, IMAGE_BITMAP)); } + +HCURSOR CButton::SetCursor(HCURSOR hCursor) { + return reinterpret_cast(SendMessage(BM_SETIMAGE, IMAGE_CURSOR, reinterpret_cast(hCursor))); +} + +HCURSOR CButton::GetCursor() { return reinterpret_cast(SendMessage(BM_GETIMAGE, IMAGE_CURSOR)); } + +void CButton::DrawItem(LPDRAWITEMSTRUCT) {} + +BOOL CButton::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { + if (CWnd::OnChildNotify(message, wParam, lParam, pResult)) + return TRUE; + if (message != WM_DRAWITEM) + return FALSE; + DrawItem(reinterpret_cast(lParam)); + return TRUE; +} + +// --------------------------------------------------------------------------------------------- +// CEdit + +BOOL CEdit::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("Edit", nullptr, dwStyle, rect, pParentWnd, nID); +} + +BOOL CEdit::CanUndo() const { return static_cast(Send(this, EM_CANUNDO)); } +int CEdit::GetLineCount() const { return static_cast(Send(this, EM_GETLINECOUNT)); } +BOOL CEdit::GetModify() const { return static_cast(Send(this, EM_GETMODIFY)); } +void CEdit::SetModify(BOOL bModified) { SendMessage(EM_SETMODIFY, static_cast(bModified)); } +void CEdit::GetRect(LPRECT lpRect) const { Send(this, EM_GETRECT, 0, reinterpret_cast(lpRect)); } +DWORD CEdit::GetSel() const { return static_cast(Send(this, EM_GETSEL)); } + +void CEdit::GetSel(int& nStartChar, int& nEndChar) const { + DWORD start = 0; + DWORD end = 0; + Send(this, EM_GETSEL, reinterpret_cast(&start), reinterpret_cast(&end)); + nStartChar = static_cast(start); + nEndChar = static_cast(end); +} + +int CEdit::GetLine(int nIndex, char* lpszBuffer) const { + return static_cast(Send(this, EM_GETLINE, static_cast(nIndex), reinterpret_cast(lpszBuffer))); +} + +int CEdit::GetLine(int nIndex, char* lpszBuffer, int nMaxLength) const { + if (!lpszBuffer || nMaxLength < static_cast(sizeof(WORD))) + return 0; + *reinterpret_cast(lpszBuffer) = static_cast(nMaxLength); + return GetLine(nIndex, lpszBuffer); +} + +void CEdit::EmptyUndoBuffer() { SendMessage(EM_EMPTYUNDOBUFFER); } +void CEdit::LimitText(int nChars) { SendMessage(EM_LIMITTEXT, static_cast(nChars)); } +int CEdit::LineFromChar(int nIndex) const { return static_cast(Send(this, EM_LINEFROMCHAR, static_cast(nIndex))); } +int CEdit::LineIndex(int nLine) const { return static_cast(Send(this, EM_LINEINDEX, static_cast(nLine))); } +int CEdit::LineLength(int nLine) const { return static_cast(Send(this, EM_LINELENGTH, static_cast(nLine))); } + +void CEdit::LineScroll(int nLines, int nChars) { + SendMessage(EM_LINESCROLL, static_cast(nChars), static_cast(nLines)); +} + +void CEdit::ReplaceSel(const char* lpszNewText, BOOL bCanUndo) { + SendMessage(EM_REPLACESEL, static_cast(bCanUndo), reinterpret_cast(lpszNewText ? lpszNewText : "")); +} + +void CEdit::SetPasswordChar(char ch) { SendMessage(EM_SETPASSWORDCHAR, static_cast(ch)); } + +void CEdit::SetSel(DWORD dwSelection, BOOL bNoScroll) { + SendMessage(EM_SETSEL, LOWORD(dwSelection), HIWORD(dwSelection)); + if (!bNoScroll) + SendMessage(EM_SCROLLCARET); +} + +void CEdit::SetSel(int nStartChar, int nEndChar, BOOL bNoScroll) { + SendMessage(EM_SETSEL, static_cast(nStartChar), static_cast(nEndChar)); + if (!bNoScroll) + SendMessage(EM_SCROLLCARET); +} + +BOOL CEdit::SetTabStops(int nTabStops, LPINT rgTabStops) { + return static_cast(SendMessage(EM_SETTABSTOPS, static_cast(nTabStops), reinterpret_cast(rgTabStops))); +} + +BOOL CEdit::Undo() { return static_cast(SendMessage(EM_UNDO)); } +void CEdit::Clear() { SendMessage(WM_CLEAR); } +void CEdit::Copy() { SendMessage(WM_COPY); } +void CEdit::Cut() { SendMessage(WM_CUT); } +void CEdit::Paste() { SendMessage(WM_PASTE); } +BOOL CEdit::SetReadOnly(BOOL bReadOnly) { return static_cast(SendMessage(EM_SETREADONLY, static_cast(bReadOnly))); } +int CEdit::GetFirstVisibleLine() const { return static_cast(Send(this, EM_GETFIRSTVISIBLELINE)); } +char CEdit::GetPasswordChar() const { return static_cast(Send(this, EM_GETPASSWORDCHAR)); } +void CEdit::SetLimitText(UINT nMax) { SendMessage(EM_SETLIMITTEXT, static_cast(nMax)); } +UINT CEdit::GetLimitText() const { return static_cast(Send(this, EM_GETLIMITTEXT)); } + +CPoint CEdit::PosFromChar(UINT nChar) const { + LRESULT r = Send(this, EM_POSFROMCHAR, static_cast(nChar)); + return CPoint(static_cast(LOWORD(r)), static_cast(HIWORD(r))); +} + +int CEdit::CharFromPos(CPoint pt) const { + return static_cast(Send(this, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y))); +} + +// --------------------------------------------------------------------------------------------- +// CListBox + +BOOL CListBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("ListBox", nullptr, dwStyle, rect, pParentWnd, nID); +} + +int CListBox::GetCount() const { return static_cast(Send(this, LB_GETCOUNT)); } +int CListBox::GetTopIndex() const { return static_cast(Send(this, LB_GETTOPINDEX)); } +int CListBox::SetTopIndex(int nIndex) { return static_cast(SendMessage(LB_SETTOPINDEX, static_cast(nIndex))); } +DWORD_PTR CListBox::GetItemData(int nIndex) const { return static_cast(Send(this, LB_GETITEMDATA, static_cast(nIndex))); } + +int CListBox::SetItemData(int nIndex, DWORD_PTR dwItemData) { + return static_cast(SendMessage(LB_SETITEMDATA, static_cast(nIndex), static_cast(dwItemData))); +} + +int CListBox::GetItemRect(int nIndex, LPRECT lpRect) const { + return static_cast(Send(this, LB_GETITEMRECT, static_cast(nIndex), reinterpret_cast(lpRect))); +} + +int CListBox::GetSel(int nIndex) const { return static_cast(Send(this, LB_GETSEL, static_cast(nIndex))); } + +int CListBox::GetText(int nIndex, char* lpszBuffer) const { + return static_cast(Send(this, LB_GETTEXT, static_cast(nIndex), reinterpret_cast(lpszBuffer))); +} + +void CListBox::GetText(int nIndex, CString& rString) const { + int len = GetTextLen(nIndex); + if (len == LB_ERR) { + rString.Empty(); + return; + } + GetText(nIndex, rString.GetBufferSetLength(len)); + rString.ReleaseBuffer(); +} + +int CListBox::GetTextLen(int nIndex) const { return static_cast(Send(this, LB_GETTEXTLEN, static_cast(nIndex))); } + +int CListBox::FindStringExact(int nIndexStart, const char* lpszFind) const { + return static_cast(Send(this, LB_FINDSTRINGEXACT, static_cast(nIndexStart), reinterpret_cast(lpszFind))); +} + +int CListBox::GetCaretIndex() const { return static_cast(Send(this, LB_GETCARETINDEX)); } + +int CListBox::SetCaretIndex(int nIndex, BOOL bScroll) { + return static_cast(SendMessage(LB_SETCARETINDEX, static_cast(nIndex), MAKELONG(bScroll, 0))); +} + +int CListBox::GetCurSel() const { return static_cast(Send(this, LB_GETCURSEL)); } +int CListBox::SetCurSel(int nSelect) { return static_cast(SendMessage(LB_SETCURSEL, static_cast(nSelect))); } + +int CListBox::SetSel(int nIndex, BOOL bSelect) { + return static_cast(SendMessage(LB_SETSEL, static_cast(bSelect), static_cast(nIndex))); +} + +int CListBox::GetSelCount() const { return static_cast(Send(this, LB_GETSELCOUNT)); } + +int CListBox::GetSelItems(int nMaxItems, LPINT rgIndex) const { + return static_cast(Send(this, LB_GETSELITEMS, static_cast(nMaxItems), reinterpret_cast(rgIndex))); +} + +int CListBox::SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem) { + if (bSelect) + return static_cast(SendMessage(LB_SELITEMRANGEEX, static_cast(nFirstItem), static_cast(nLastItem))); + return static_cast(SendMessage(LB_SELITEMRANGEEX, static_cast(nLastItem), static_cast(nFirstItem))); +} + +int CListBox::AddString(const char* lpszItem) { + return static_cast(SendMessage(LB_ADDSTRING, 0, reinterpret_cast(lpszItem ? lpszItem : ""))); +} + +int CListBox::DeleteString(UINT nIndex) { return static_cast(SendMessage(LB_DELETESTRING, nIndex)); } + +int CListBox::InsertString(int nIndex, const char* lpszItem) { + return static_cast(SendMessage(LB_INSERTSTRING, static_cast(nIndex), reinterpret_cast(lpszItem ? lpszItem : ""))); +} + +void CListBox::ResetContent() { SendMessage(LB_RESETCONTENT); } + +int CListBox::FindString(int nStartAfter, const char* lpszItem) const { + return static_cast(Send(this, LB_FINDSTRING, static_cast(nStartAfter), reinterpret_cast(lpszItem))); +} + +int CListBox::SelectString(int nStartAfter, const char* lpszItem) { + return static_cast(SendMessage(LB_SELECTSTRING, static_cast(nStartAfter), reinterpret_cast(lpszItem))); +} + +UINT CListBox::ItemFromPoint(CPoint pt, BOOL& bOutside) const { + return OnMain([&]() -> UINT { + bOutside = TRUE; + auto* lb = m_hWnd ? wxDynamicCast(GetWx(), wxListBox) : nullptr; + if (!lb || lb->GetCount() == 0) + return 0; + int hit = lb->HitTest(wxPoint(pt.x, pt.y)); + if (hit != wxNOT_FOUND) { + bOutside = FALSE; + return static_cast(hit); + } + return pt.y < 0 ? 0 : lb->GetCount() - 1; + }); +} + +// --------------------------------------------------------------------------------------------- +// CCheckListBox + +void CCheckListBox::SetCheck(int nIndex, int nCheck) { + OnMain([&] { + auto* c = m_hWnd ? wxDynamicCast(GetWx(), wxCheckListBox) : nullptr; + if (c && nIndex >= 0 && nIndex < static_cast(c->GetCount())) + c->Check(static_cast(nIndex), nCheck != 0); + }); +} + +int CCheckListBox::GetCheck(int nIndex) { + return OnMain([&]() -> int { + auto* c = m_hWnd ? wxDynamicCast(GetWx(), wxCheckListBox) : nullptr; + if (!c || nIndex < 0 || nIndex >= static_cast(c->GetCount())) + return 0; + return c->IsChecked(static_cast(nIndex)) ? 1 : 0; + }); +} + +void CCheckListBox::Enable(int, BOOL) {} + +BOOL CCheckListBox::IsEnabled(int) { return TRUE; } + +// --------------------------------------------------------------------------------------------- +// CComboBox + +BOOL CComboBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("ComboBox", nullptr, dwStyle, rect, pParentWnd, nID); +} + +int CComboBox::GetCount() const { return static_cast(Send(this, CB_GETCOUNT)); } +int CComboBox::GetCurSel() const { return static_cast(Send(this, CB_GETCURSEL)); } +int CComboBox::SetCurSel(int nSelect) { return static_cast(SendMessage(CB_SETCURSEL, static_cast(nSelect))); } +DWORD CComboBox::GetEditSel() const { return static_cast(Send(this, CB_GETEDITSEL)); } +BOOL CComboBox::LimitText(int nMaxChars) { return static_cast(SendMessage(CB_LIMITTEXT, static_cast(nMaxChars))); } + +BOOL CComboBox::SetEditSel(int nStartChar, int nEndChar) { + return static_cast(SendMessage(CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar))); +} + +DWORD_PTR CComboBox::GetItemData(int nIndex) const { + return static_cast(Send(this, CB_GETITEMDATA, static_cast(nIndex))); +} + +int CComboBox::SetItemData(int nIndex, DWORD_PTR dwItemData) { + return static_cast(SendMessage(CB_SETITEMDATA, static_cast(nIndex), static_cast(dwItemData))); +} + +int CComboBox::GetLBText(int nIndex, char* lpszText) const { + return static_cast(Send(this, CB_GETLBTEXT, static_cast(nIndex), reinterpret_cast(lpszText))); +} + +void CComboBox::GetLBText(int nIndex, CString& rString) const { + int len = GetLBTextLen(nIndex); + if (len == CB_ERR) { + rString.Empty(); + return; + } + GetLBText(nIndex, rString.GetBufferSetLength(len)); + rString.ReleaseBuffer(); +} + +int CComboBox::GetLBTextLen(int nIndex) const { return static_cast(Send(this, CB_GETLBTEXTLEN, static_cast(nIndex))); } + +int CComboBox::FindStringExact(int nIndexStart, const char* lpszFind) const { + return static_cast(Send(this, CB_FINDSTRINGEXACT, static_cast(nIndexStart), reinterpret_cast(lpszFind))); +} + +void CComboBox::GetDroppedControlRect(LPRECT lprect) const { + Send(this, CB_GETDROPPEDCONTROLRECT, 0, reinterpret_cast(lprect)); +} + +void CComboBox::ShowDropDown(BOOL bShowIt) { SendMessage(CB_SHOWDROPDOWN, static_cast(bShowIt)); } + +int CComboBox::AddString(const char* lpszString) { + return static_cast(SendMessage(CB_ADDSTRING, 0, reinterpret_cast(lpszString ? lpszString : ""))); +} + +int CComboBox::DeleteString(UINT nIndex) { return static_cast(SendMessage(CB_DELETESTRING, nIndex)); } + +int CComboBox::InsertString(int nIndex, const char* lpszString) { + return static_cast(SendMessage(CB_INSERTSTRING, static_cast(nIndex), reinterpret_cast(lpszString ? lpszString : ""))); +} + +void CComboBox::ResetContent() { SendMessage(CB_RESETCONTENT); } + +int CComboBox::FindString(int nStartAfter, const char* lpszString) const { + return static_cast(Send(this, CB_FINDSTRING, static_cast(nStartAfter), reinterpret_cast(lpszString))); +} + +int CComboBox::SelectString(int nStartAfter, const char* lpszString) { + return static_cast(SendMessage(CB_SELECTSTRING, static_cast(nStartAfter), reinterpret_cast(lpszString))); +} + +void CComboBox::Clear() { SendMessage(WM_CLEAR); } +void CComboBox::Copy() { SendMessage(WM_COPY); } +void CComboBox::Cut() { SendMessage(WM_CUT); } +void CComboBox::Paste() { SendMessage(WM_PASTE); } + +// --------------------------------------------------------------------------------------------- +// CScrollBar + +BOOL CScrollBar::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("ScrollBar", nullptr, dwStyle, rect, pParentWnd, nID); +} + +int CScrollBar::GetScrollPos() const { return static_cast(Send(this, SBM_GETPOS)); } + +int CScrollBar::SetScrollPos(int nPos, BOOL bRedraw) { + return static_cast(SendMessage(SBM_SETPOS, static_cast(nPos), static_cast(bRedraw))); +} + +void CScrollBar::GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const { + Send(this, SBM_GETRANGE, reinterpret_cast(lpMinPos), reinterpret_cast(lpMaxPos)); +} + +void CScrollBar::SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw) { + SendMessage(bRedraw ? SBM_SETRANGEREDRAW : SBM_SETRANGE, static_cast(nMinPos), static_cast(nMaxPos)); +} + +void CScrollBar::ShowScrollBar(BOOL bShow) { ShowWindow(bShow ? SW_SHOW : SW_HIDE); } + +BOOL CScrollBar::EnableScrollBar(UINT nArrowFlags) { + EnableWindow((nArrowFlags & ESB_DISABLE_BOTH) != ESB_DISABLE_BOTH); + return TRUE; +} + +BOOL CScrollBar::SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw) { + if (!lpScrollInfo) + return FALSE; + lpScrollInfo->cbSize = sizeof(SCROLLINFO); + SendMessage(SBM_SETSCROLLINFO, static_cast(bRedraw), reinterpret_cast(lpScrollInfo)); + return TRUE; +} + +BOOL CScrollBar::GetScrollInfo(LPSCROLLINFO lpScrollInfo, UINT nMask) { + if (!lpScrollInfo) + return FALSE; + lpScrollInfo->cbSize = sizeof(SCROLLINFO); + lpScrollInfo->fMask = nMask; + return static_cast(SendMessage(SBM_GETSCROLLINFO, 0, reinterpret_cast(lpScrollInfo))); +} + +int CScrollBar::GetScrollLimit() { + int nMin = 0; + int nMax = 0; + GetScrollRange(&nMin, &nMax); + SCROLLINFO info; + memset(&info, 0, sizeof info); + if (GetScrollInfo(&info, SIF_PAGE)) + nMax -= std::max(static_cast(info.nPage) - 1, 0); + return nMax; +} + +// --------------------------------------------------------------------------------------------- +// CProgressCtrl + +BOOL CProgressCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("msctls_progress32", nullptr, dwStyle, rect, pParentWnd, nID); +} + +void CProgressCtrl::SetRange(short nLower, short nUpper) { SendMessage(PBM_SETRANGE, 0, MAKELPARAM(nLower, nUpper)); } + +void CProgressCtrl::SetRange32(int nLower, int nUpper) { + SendMessage(PBM_SETRANGE32, static_cast(nLower), static_cast(nUpper)); +} + +void CProgressCtrl::GetRange(int& nLower, int& nUpper) const { + int range[2] = {0, 0}; + Send(this, PBM_GETRANGE, FALSE, reinterpret_cast(range)); + nLower = range[0]; + nUpper = range[1]; +} + +int CProgressCtrl::GetPos() const { return static_cast(Send(this, PBM_GETPOS)); } +int CProgressCtrl::SetPos(int nPos) { return static_cast(SendMessage(PBM_SETPOS, static_cast(nPos))); } +int CProgressCtrl::OffsetPos(int nPos) { return static_cast(SendMessage(PBM_DELTAPOS, static_cast(nPos))); } +int CProgressCtrl::SetStep(int nStep) { return static_cast(SendMessage(PBM_SETSTEP, static_cast(nStep))); } +int CProgressCtrl::StepIt() { return static_cast(SendMessage(PBM_STEPIT)); } +COLORREF CProgressCtrl::SetBkColor(COLORREF clrNew) { return static_cast(SendMessage(PBM_SETBKCOLOR, 0, static_cast(clrNew))); } +COLORREF CProgressCtrl::SetBarColor(COLORREF clrBar) { return static_cast(SendMessage(PBM_SETBARCOLOR, 0, static_cast(clrBar))); } + +BOOL CProgressCtrl::SetMarquee(BOOL fMarqueeMode, int nInterval) { + return static_cast(SendMessage(PBM_SETMARQUEE, static_cast(fMarqueeMode), static_cast(nInterval))); +} + +// --------------------------------------------------------------------------------------------- +// CSliderCtrl + +BOOL CSliderCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("msctls_trackbar32", nullptr, dwStyle, rect, pParentWnd, nID); +} + +int CSliderCtrl::GetLineSize() const { return static_cast(Send(this, TBM_GETLINESIZE)); } +int CSliderCtrl::SetLineSize(int nSize) { return static_cast(SendMessage(TBM_SETLINESIZE, 0, static_cast(nSize))); } +int CSliderCtrl::GetPageSize() const { return static_cast(Send(this, TBM_GETPAGESIZE)); } +int CSliderCtrl::SetPageSize(int nSize) { return static_cast(SendMessage(TBM_SETPAGESIZE, 0, static_cast(nSize))); } +int CSliderCtrl::GetRangeMax() const { return static_cast(Send(this, TBM_GETRANGEMAX)); } +int CSliderCtrl::GetRangeMin() const { return static_cast(Send(this, TBM_GETRANGEMIN)); } + +void CSliderCtrl::GetRange(int& nMin, int& nMax) const { + nMin = GetRangeMin(); + nMax = GetRangeMax(); +} + +void CSliderCtrl::SetRangeMin(int nMin, BOOL bRedraw) { + SendMessage(TBM_SETRANGEMIN, static_cast(bRedraw), static_cast(nMin)); +} + +void CSliderCtrl::SetRangeMax(int nMax, BOOL bRedraw) { + SendMessage(TBM_SETRANGEMAX, static_cast(bRedraw), static_cast(nMax)); +} + +void CSliderCtrl::SetRange(int nMin, int nMax, BOOL bRedraw) { + SendMessage(TBM_SETRANGEMIN, FALSE, static_cast(nMin)); + SendMessage(TBM_SETRANGEMAX, static_cast(bRedraw), static_cast(nMax)); +} + +void CSliderCtrl::GetSelection(int& nMin, int& nMax) const { + nMin = static_cast(Send(this, TBM_GETSELSTART)); + nMax = static_cast(Send(this, TBM_GETSELEND)); +} + +void CSliderCtrl::SetSelection(int nMin, int nMax) { + SendMessage(TBM_SETSELSTART, FALSE, static_cast(nMin)); + SendMessage(TBM_SETSELEND, TRUE, static_cast(nMax)); +} + +void CSliderCtrl::GetChannelRect(LPRECT lprc) const { + OnMain([&] { + if (!lprc || !m_hWnd) + return; + wxSize sz = GetWx()->GetClientSize(); + bool vertical = (GetStyle() & TBS_VERT) != 0; + if (vertical) { + lprc->left = sz.x / 2 - 2; + lprc->right = sz.x / 2 + 2; + lprc->top = 8; + lprc->bottom = std::max(8, sz.y - 8); + } else { + lprc->left = 8; + lprc->right = std::max(8, sz.x - 8); + lprc->top = sz.y / 2 - 2; + lprc->bottom = sz.y / 2 + 2; + } + }); +} + +void CSliderCtrl::GetThumbRect(LPRECT lprc) const { + if (!lprc) + return; + RECT channel; + GetChannelRect(&channel); + int lo = GetRangeMin(); + int hi = GetRangeMax(); + int pos = GetPos(); + double f = hi > lo ? static_cast(pos - lo) / (hi - lo) : 0.0; + if (GetStyle() & TBS_VERT) { + int y = channel.top + static_cast(f * (channel.bottom - channel.top)); + lprc->left = channel.left - 8; + lprc->right = channel.right + 8; + lprc->top = y - 5; + lprc->bottom = y + 5; + } else { + int x = channel.left + static_cast(f * (channel.right - channel.left)); + lprc->left = x - 5; + lprc->right = x + 5; + lprc->top = channel.top - 8; + lprc->bottom = channel.bottom + 8; + } +} + +int CSliderCtrl::GetPos() const { return static_cast(Send(this, TBM_GETPOS)); } +void CSliderCtrl::SetPos(int nPos) { SendMessage(TBM_SETPOS, TRUE, static_cast(nPos)); } +UINT CSliderCtrl::GetNumTics() const { return static_cast(Send(this, TBM_GETNUMTICS)); } +int CSliderCtrl::GetTic(int nTic) const { return static_cast(Send(this, TBM_GETTIC, static_cast(nTic))); } +BOOL CSliderCtrl::SetTic(int nTic) { return static_cast(SendMessage(TBM_SETTIC, 0, static_cast(nTic))); } +void CSliderCtrl::SetTicFreq(int nFreq) { SendMessage(TBM_SETTICFREQ, static_cast(nFreq)); } +void CSliderCtrl::ClearSel(BOOL bRedraw) { SendMessage(TBM_CLEARSEL, static_cast(bRedraw)); } +void CSliderCtrl::ClearTics(BOOL bRedraw) { SendMessage(TBM_CLEARTICS, static_cast(bRedraw)); } + +// --------------------------------------------------------------------------------------------- +// CSpinButtonCtrl + +BOOL CSpinButtonCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("msctls_updown32", nullptr, dwStyle, rect, pParentWnd, nID); +} + +BOOL CSpinButtonCtrl::SetAccel(int nAccel, UDACCEL* pAccel) { + return static_cast(SendMessage(UDM_SETACCEL, static_cast(nAccel), reinterpret_cast(pAccel))); +} + +UINT CSpinButtonCtrl::GetAccel(int nAccel, UDACCEL* pAccel) const { + return static_cast(Send(this, UDM_GETACCEL, static_cast(nAccel), reinterpret_cast(pAccel))); +} + +int CSpinButtonCtrl::SetBase(int nBase) { return static_cast(SendMessage(UDM_SETBASE, static_cast(nBase))); } +UINT CSpinButtonCtrl::GetBase() const { return static_cast(Send(this, UDM_GETBASE)); } + +CWnd* CSpinButtonCtrl::SetBuddy(CWnd* pWndBuddy) { + return CWnd::FromHandle(reinterpret_cast( + SendMessage(UDM_SETBUDDY, reinterpret_cast(pWndBuddy ? pWndBuddy->m_hWnd : nullptr)))); +} + +CWnd* CSpinButtonCtrl::GetBuddy() const { return CWnd::FromHandle(reinterpret_cast(Send(this, UDM_GETBUDDY))); } +int CSpinButtonCtrl::SetPos(int nPos) { return static_cast(SendMessage(UDM_SETPOS32, 0, static_cast(nPos))); } +int CSpinButtonCtrl::GetPos() const { return static_cast(Send(this, UDM_GETPOS)); } +int CSpinButtonCtrl::GetPos32(BOOL* lpbError) const { return static_cast(Send(this, UDM_GETPOS32, 0, reinterpret_cast(lpbError))); } +void CSpinButtonCtrl::SetRange(short nLower, short nUpper) { SendMessage(UDM_SETRANGE, 0, MAKELPARAM(nUpper, nLower)); } + +void CSpinButtonCtrl::SetRange32(int nLower, int nUpper) { + SendMessage(UDM_SETRANGE32, static_cast(nLower), static_cast(nUpper)); +} + +DWORD CSpinButtonCtrl::GetRange() const { return static_cast(Send(this, UDM_GETRANGE)); } + +void CSpinButtonCtrl::GetRange(int& lower, int& upper) const { + Send(this, UDM_GETRANGE32, reinterpret_cast(&lower), reinterpret_cast(&upper)); +} + +// --------------------------------------------------------------------------------------------- +// CTabCtrl + +BOOL CTabCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("SysTabControl32", nullptr, dwStyle, rect, pParentWnd, nID); +} + +int CTabCtrl::GetItemCount() const { + return OnMain([&]() -> int { + TabExtra* tx = TabsOf(this); + return tx ? static_cast(tx->items.size()) : 0; + }); +} + +BOOL CTabCtrl::GetItem(int nItem, TCITEM* pTabCtrlItem) const { + return OnMain([&]() -> BOOL { + TabExtra* tx = TabsOf(this); + if (!tx || !pTabCtrlItem || nItem < 0 || nItem >= static_cast(tx->items.size())) + return FALSE; + const auto& item = tx->items[static_cast(nItem)]; + if (pTabCtrlItem->mask & TCIF_TEXT) + CopyText(item.first, pTabCtrlItem->pszText, pTabCtrlItem->cchTextMax); + if (pTabCtrlItem->mask & TCIF_PARAM) + pTabCtrlItem->lParam = item.second; + if (pTabCtrlItem->mask & TCIF_IMAGE) + pTabCtrlItem->iImage = -1; + if (pTabCtrlItem->mask & TCIF_STATE) + pTabCtrlItem->dwState = 0; + return TRUE; + }); +} + +BOOL CTabCtrl::SetItem(int nItem, TCITEM* pTabCtrlItem) { + return OnMain([&]() -> BOOL { + TabExtra* tx = TabsOf(this); + if (!tx || !pTabCtrlItem || nItem < 0 || nItem >= static_cast(tx->items.size())) + return FALSE; + auto& item = tx->items[static_cast(nItem)]; + if ((pTabCtrlItem->mask & TCIF_TEXT) && pTabCtrlItem->pszText) + item.first = ToWx(pTabCtrlItem->pszText); + if (pTabCtrlItem->mask & TCIF_PARAM) + item.second = pTabCtrlItem->lParam; + GetWx()->Refresh(); + return TRUE; + }); +} + +BOOL CTabCtrl::GetItemRect(int nItem, LPRECT lpRect) const { + return OnMain([&]() -> BOOL { + if (!TabsOf(this) || !lpRect) + return FALSE; + std::vector rects = TabRects(GetWx()); + if (nItem < 0 || nItem >= static_cast(rects.size())) + return FALSE; + const wxRect& r = rects[static_cast(nItem)]; + lpRect->left = r.x; + lpRect->top = r.y; + lpRect->right = r.x + r.width; + lpRect->bottom = r.y + r.height; + return TRUE; + }); +} + +int CTabCtrl::GetCurSel() const { + return OnMain([&]() -> int { + TabExtra* tx = TabsOf(this); + return tx ? tx->current : -1; + }); +} + +int CTabCtrl::SetCurSel(int nItem) { + return OnMain([&]() -> int { + TabExtra* tx = TabsOf(this); + if (!tx || nItem < 0 || nItem >= static_cast(tx->items.size())) + return -1; + int old = tx->current; + tx->current = nItem; + GetWx()->Refresh(); + return old; + }); +} + +void CTabCtrl::SetCurFocus(int nItem) { + OnMain([&] { + TabExtra* tx = TabsOf(this); + if (!tx || nItem < 0 || nItem >= static_cast(tx->items.size()) || nItem == tx->current) + return; + wxWindow* w = GetWx(); + NMHDR hdr; + hdr.code = TCN_SELCHANGING; + if (NotifyParentNM(w, &hdr)) + return; + if (!(tx = TabsOf(this))) + return; + tx->current = nItem; + w->Refresh(); + NMHDR changed; + changed.code = TCN_SELCHANGE; + NotifyParentNM(w, &changed); + }); +} + +CSize CTabCtrl::SetItemSize(CSize size) { + return OnMain([&]() -> CSize { + TabExtra* tx = TabsOf(this); + if (!tx) + return CSize(0, 0); + wxSize old = tx->itemSize; + if (GetStyle() & TCS_FIXEDWIDTH) + tx->itemSize.x = size.cx; + tx->itemSize.y = size.cy; + GetWx()->Refresh(); + return CSize(old.x, old.y); + }); +} + +LONG CTabCtrl::InsertItem(int nItem, TCITEM* pTabCtrlItem) { + return OnMain([&]() -> LONG { + TabExtra* tx = TabsOf(this); + if (!tx || !pTabCtrlItem || nItem < 0) + return -1; + int at = std::min(nItem, static_cast(tx->items.size())); + wxString text = (pTabCtrlItem->mask & TCIF_TEXT) && pTabCtrlItem->pszText ? ToWx(pTabCtrlItem->pszText) : wxString(); + LPARAM param = (pTabCtrlItem->mask & TCIF_PARAM) ? pTabCtrlItem->lParam : 0; + tx->items.insert(tx->items.begin() + at, std::make_pair(text, param)); + if (tx->current >= at) + ++tx->current; + if (tx->current < 0) + tx->current = 0; + GetWx()->Refresh(); + return at; + }); +} + +LONG CTabCtrl::InsertItem(int nItem, const char* lpszItem) { + TCITEM item; + memset(&item, 0, sizeof item); + item.mask = TCIF_TEXT; + item.pszText = const_cast(lpszItem); + return InsertItem(nItem, &item); +} + +LONG CTabCtrl::InsertItem(int nItem, const char* lpszItem, int nImage) { + TCITEM item; + memset(&item, 0, sizeof item); + item.mask = TCIF_TEXT | TCIF_IMAGE; + item.pszText = const_cast(lpszItem); + item.iImage = nImage; + return InsertItem(nItem, &item); +} + +BOOL CTabCtrl::DeleteItem(int nItem) { + return OnMain([&]() -> BOOL { + TabExtra* tx = TabsOf(this); + if (!tx || nItem < 0 || nItem >= static_cast(tx->items.size())) + return FALSE; + tx->items.erase(tx->items.begin() + nItem); + if (tx->current == nItem) + tx->current = -1; + else if (tx->current > nItem) + --tx->current; + GetWx()->Refresh(); + return TRUE; + }); +} + +BOOL CTabCtrl::DeleteAllItems() { + return OnMain([&]() -> BOOL { + TabExtra* tx = TabsOf(this); + if (!tx) + return FALSE; + tx->items.clear(); + tx->current = -1; + GetWx()->Refresh(); + return TRUE; + }); +} + +void CTabCtrl::AdjustRect(BOOL bLarger, LPRECT lpRect) { + if (!lpRect) + return; + int header = OnMain([&]() -> int { return m_hWnd ? TabHeaderHeight(GetWx()) : 0; }); + int d = bLarger ? -1 : 1; + lpRect->left += 2 * d; + lpRect->top += (header + 2) * d; + lpRect->right -= 2 * d; + lpRect->bottom -= 2 * d; +} + +// --------------------------------------------------------------------------------------------- +// CToolTipCtrl + +BOOL CToolTipCtrl::Create(CWnd* pParentWnd, DWORD dwStyle) { + if (!pParentWnd || !pParentWnd->m_hWnd) + return FALSE; + RECT r = {0, 0, 0, 0}; + return CWnd::CreateEx(0, "tooltips_class32", nullptr, WS_CHILD | (dwStyle & ~(WS_VISIBLE | WS_POPUP | WS_TABSTOP)), + r, pParentWnd, 0); +} + +BOOL CToolTipCtrl::AddTool(CWnd* pWnd, UINT nIDText, LPCRECT lpRectTool, UINT_PTR nIDTool) { + std::string text; + if (!LoadResourceString(nIDText, text)) + return FALSE; + return AddTool(pWnd, text.c_str(), lpRectTool, nIDTool); +} + +BOOL CToolTipCtrl::AddTool(CWnd* pWnd, const char* lpszText, LPCRECT, UINT_PTR nIDTool) { + if (!pWnd || !pWnd->m_hWnd) + return FALSE; + HWND tool = pWnd->m_hWnd; + return OnMain([&]() -> BOOL { + ToolTipExtra* tips = TipsOf(this); + if (!tips) + return FALSE; + wxString text = lpszText == LPSTR_TEXTCALLBACK ? CallbackToolText(tool, m_hWnd, nIDTool) + : (lpszText ? ToWx(lpszText) : wxString()); + auto it = std::find_if(tips->tools.begin(), tips->tools.end(), + [&](const ToolTipExtra::Tool& t) { return t.hwnd == tool && t.id == nIDTool; }); + if (it == tips->tools.end()) + it = tips->tools.insert(tips->tools.end(), ToolTipExtra::Tool{tool, nIDTool, text}); + else + it->text = text; + ApplyTool(*it, tips->active); + return TRUE; + }); +} + +void CToolTipCtrl::DelTool(CWnd* pWnd, UINT_PTR nIDTool) { + if (!pWnd) + return; + HWND tool = pWnd->m_hWnd; + OnMain([&] { + ToolTipExtra* tips = TipsOf(this); + if (!tips) + return; + auto it = std::find_if(tips->tools.begin(), tips->tools.end(), + [&](const ToolTipExtra::Tool& t) { return t.hwnd == tool && t.id == nIDTool; }); + if (it == tips->tools.end()) + return; + ApplyTool(ToolTipExtra::Tool{it->hwnd, it->id, wxString()}, false); + tips->tools.erase(it); + }); +} + +void CToolTipCtrl::UpdateTipText(const char* lpszText, CWnd* pWnd, UINT_PTR nIDTool) { + if (!pWnd) + return; + HWND tool = pWnd->m_hWnd; + OnMain([&] { + ToolTipExtra* tips = TipsOf(this); + if (!tips) + return; + auto it = std::find_if(tips->tools.begin(), tips->tools.end(), + [&](const ToolTipExtra::Tool& t) { return t.hwnd == tool && t.id == nIDTool; }); + if (it == tips->tools.end()) + it = std::find_if(tips->tools.begin(), tips->tools.end(), + [&](const ToolTipExtra::Tool& t) { return t.hwnd == tool; }); + if (it == tips->tools.end()) + return; + it->text = lpszText == LPSTR_TEXTCALLBACK ? CallbackToolText(tool, m_hWnd, nIDTool) + : (lpszText ? ToWx(lpszText) : wxString()); + ApplyTool(*it, tips->active); + }); +} + +void CToolTipCtrl::UpdateTipText(UINT nIDText, CWnd* pWnd, UINT_PTR nIDTool) { + std::string text; + LoadResourceString(nIDText, text); + UpdateTipText(text.c_str(), pWnd, nIDTool); +} + +void CToolTipCtrl::RelayEvent(LPMSG) {} + +void CToolTipCtrl::Activate(BOOL bActivate) { + OnMain([&] { + ToolTipExtra* tips = TipsOf(this); + if (!tips || tips->active == (bActivate != FALSE)) + return; + tips->active = bActivate != FALSE; + for (const auto& t : tips->tools) + ApplyTool(t, tips->active); + }); +} + +void CToolTipCtrl::SetDelayTime(UINT nDelay) { SetDelayTime(nDelay, TTDT_AUTOMATIC); } + +void CToolTipCtrl::SetDelayTime(DWORD dwDuration, int iTime) { + OnMain([&] { + long ms = static_cast(dwDuration); + switch (iTime) { + case TTDT_AUTOPOP: + wxToolTip::SetAutoPop(ms); + break; + case TTDT_RESHOW: + wxToolTip::SetReshow(ms); + break; + default: + wxToolTip::SetDelay(ms); + break; + } + }); +} + +int CToolTipCtrl::SetMaxTipWidth(int iWidth) { + return OnMain([&]() -> int { + ToolTipExtra* tips = TipsOf(this); + if (!tips) + return -1; + int old = tips->maxWidth; + tips->maxWidth = iWidth; + return old; + }); +} + +int CToolTipCtrl::GetToolCount() const { + return OnMain([&]() -> int { + ToolTipExtra* tips = TipsOf(this); + return tips ? static_cast(tips->tools.size()) : 0; + }); +} + +// --------------------------------------------------------------------------------------------- +// CRichEditCtrl + +BOOL CRichEditCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("RichEdit20A", nullptr, dwStyle, rect, pParentWnd, nID); +} + +BOOL CRichEditCtrl::CanUndo() const { return static_cast(Send(this, EM_CANUNDO)); } +BOOL CRichEditCtrl::CanRedo() const { return static_cast(Send(this, EM_CANREDO)); } +int CRichEditCtrl::GetLineCount() const { return static_cast(Send(this, EM_GETLINECOUNT)); } +BOOL CRichEditCtrl::GetModify() const { return static_cast(Send(this, EM_GETMODIFY)); } +void CRichEditCtrl::SetModify(BOOL bModified) { SendMessage(EM_SETMODIFY, static_cast(bModified)); } +void CRichEditCtrl::GetRect(LPRECT lpRect) const { Send(this, EM_GETRECT, 0, reinterpret_cast(lpRect)); } + +CPoint CRichEditCtrl::GetCharPos(long lChar) const { + POINT pt = {0, 0}; + Send(this, EM_POSFROMCHAR, reinterpret_cast(&pt), static_cast(lChar)); + return CPoint(pt.x, pt.y); +} + +int CRichEditCtrl::GetLine(int nIndex, char* lpszBuffer) const { + return static_cast(Send(this, EM_GETLINE, static_cast(nIndex), reinterpret_cast(lpszBuffer))); +} + +int CRichEditCtrl::GetLine(int nIndex, char* lpszBuffer, int nMaxLength) const { + if (!lpszBuffer || nMaxLength < static_cast(sizeof(WORD))) + return 0; + *reinterpret_cast(lpszBuffer) = static_cast(nMaxLength); + return GetLine(nIndex, lpszBuffer); +} + +BOOL CRichEditCtrl::CanPaste(UINT nFormat) const { return static_cast(Send(this, EM_CANPASTE, nFormat)); } + +void CRichEditCtrl::GetSel(long& nStartChar, long& nEndChar) const { + CHARRANGE cr = {0, 0}; + Send(this, EM_EXGETSEL, 0, reinterpret_cast(&cr)); + nStartChar = cr.cpMin; + nEndChar = cr.cpMax; +} + +void CRichEditCtrl::GetSel(CHARRANGE& cr) const { Send(this, EM_EXGETSEL, 0, reinterpret_cast(&cr)); } +void CRichEditCtrl::LimitText(long nChars) { SendMessage(EM_EXLIMITTEXT, 0, static_cast(nChars)); } +long CRichEditCtrl::LineFromChar(long nIndex) const { return static_cast(Send(this, EM_EXLINEFROMCHAR, 0, static_cast(nIndex))); } + +void CRichEditCtrl::SetSel(long nStartChar, long nEndChar) { + CHARRANGE cr = {static_cast(nStartChar), static_cast(nEndChar)}; + SendMessage(EM_EXSETSEL, 0, reinterpret_cast(&cr)); +} + +void CRichEditCtrl::SetSel(CHARRANGE& cr) { SendMessage(EM_EXSETSEL, 0, reinterpret_cast(&cr)); } + +DWORD CRichEditCtrl::GetDefaultCharFormat(CHARFORMAT& cf) const { + cf.cbSize = sizeof(CHARFORMAT); + return static_cast(Send(this, EM_GETCHARFORMAT, 0, reinterpret_cast(&cf))); +} + +DWORD CRichEditCtrl::GetSelectionCharFormat(CHARFORMAT& cf) const { + cf.cbSize = sizeof(CHARFORMAT); + return static_cast(Send(this, EM_GETCHARFORMAT, SCF_SELECTION, reinterpret_cast(&cf))); +} + +long CRichEditCtrl::GetLimitText() const { return static_cast(Send(this, EM_GETLIMITTEXT)); } + +DWORD CRichEditCtrl::GetParaFormat(PARAFORMAT& pf) const { + pf.cbSize = sizeof(PARAFORMAT); + return static_cast(Send(this, EM_GETPARAFORMAT, 0, reinterpret_cast(&pf))); +} + +long CRichEditCtrl::GetSelText(char* lpBuf) const { + return static_cast(Send(this, EM_GETSELTEXT, 0, reinterpret_cast(lpBuf))); +} + +CString CRichEditCtrl::GetSelText() const { + CHARRANGE cr = {0, 0}; + Send(this, EM_EXGETSEL, 0, reinterpret_cast(&cr)); + int len = std::max(0, static_cast(cr.cpMax - cr.cpMin)); + CString s; + char* buf = s.GetBuffer(len + 1); + buf[0] = 0; + long n = static_cast(Send(this, EM_GETSELTEXT, 0, reinterpret_cast(buf))); + s.ReleaseBuffer(static_cast(std::min(std::max(n, 0), len))); + return s; +} + +WORD CRichEditCtrl::GetSelectionType() const { return static_cast(Send(this, EM_SELECTIONTYPE)); } + +COLORREF CRichEditCtrl::SetBackgroundColor(BOOL bSysColor, COLORREF cr) { + return static_cast(SendMessage(EM_SETBKGNDCOLOR, static_cast(bSysColor), static_cast(cr))); +} + +BOOL CRichEditCtrl::SetDefaultCharFormat(CHARFORMAT& cf) { + cf.cbSize = sizeof(CHARFORMAT); + return static_cast(SendMessage(EM_SETCHARFORMAT, 0, reinterpret_cast(&cf))); +} + +BOOL CRichEditCtrl::SetSelectionCharFormat(CHARFORMAT& cf) { + cf.cbSize = sizeof(CHARFORMAT); + return static_cast(SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast(&cf))); +} + +BOOL CRichEditCtrl::SetWordCharFormat(CHARFORMAT& cf) { + cf.cbSize = sizeof(CHARFORMAT); + return static_cast(SendMessage(EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, reinterpret_cast(&cf))); +} + +BOOL CRichEditCtrl::SetParaFormat(PARAFORMAT& pf) { + pf.cbSize = sizeof(PARAFORMAT); + return static_cast(SendMessage(EM_SETPARAFORMAT, 0, reinterpret_cast(&pf))); +} + +BOOL CRichEditCtrl::SetReadOnly(BOOL bReadOnly) { + return static_cast(SendMessage(EM_SETREADONLY, static_cast(bReadOnly))); +} + +long CRichEditCtrl::GetTextLength() const { return static_cast(Send(this, WM_GETTEXTLENGTH)); } +void CRichEditCtrl::EmptyUndoBuffer() { SendMessage(EM_EMPTYUNDOBUFFER); } +int CRichEditCtrl::LineIndex(int nLine) const { return static_cast(Send(this, EM_LINEINDEX, static_cast(nLine))); } +int CRichEditCtrl::LineLength(int nLine) const { return static_cast(Send(this, EM_LINELENGTH, static_cast(nLine))); } + +void CRichEditCtrl::LineScroll(int nLines, int nChars) { + SendMessage(EM_LINESCROLL, static_cast(nChars), static_cast(nLines)); +} + +void CRichEditCtrl::ReplaceSel(const char* lpszNewText, BOOL bCanUndo) { + SendMessage(EM_REPLACESEL, static_cast(bCanUndo), reinterpret_cast(lpszNewText ? lpszNewText : "")); +} + +long CRichEditCtrl::StreamIn(int nFormat, EDITSTREAM& es) { + return static_cast(SendMessage(EM_STREAMIN, static_cast(nFormat), reinterpret_cast(&es))); +} + +long CRichEditCtrl::StreamOut(int nFormat, EDITSTREAM& es) { + return static_cast(SendMessage(EM_STREAMOUT, static_cast(nFormat), reinterpret_cast(&es))); +} + +long CRichEditCtrl::FindText(DWORD dwFlags, FINDTEXTEX* pFindText) const { + return static_cast(Send(this, EM_FINDTEXTEX, dwFlags, reinterpret_cast(pFindText))); +} + +BOOL CRichEditCtrl::Undo() { return static_cast(SendMessage(EM_UNDO)); } +BOOL CRichEditCtrl::Redo() { return static_cast(SendMessage(EM_REDO)); } +void CRichEditCtrl::Clear() { SendMessage(WM_CLEAR); } +void CRichEditCtrl::Copy() { SendMessage(WM_COPY); } +void CRichEditCtrl::Cut() { SendMessage(WM_CUT); } +void CRichEditCtrl::Paste() { SendMessage(WM_PASTE); } +int CRichEditCtrl::GetFirstVisibleLine() const { return static_cast(Send(this, EM_GETFIRSTVISIBLELINE)); } + +// --------------------------------------------------------------------------------------------- +// CBitmapButton + +BOOL CBitmapButton::LoadBitmaps(const char* lpszBitmapResource, const char* lpszBitmapResourceSel, + const char* lpszBitmapResourceFocus, const char* lpszBitmapResourceDisabled) { + m_bitmap.DeleteObject(); + m_bitmapSel.DeleteObject(); + m_bitmapFocus.DeleteObject(); + m_bitmapDisabled.DeleteObject(); + if (!lpszBitmapResource || !m_bitmap.LoadBitmap(lpszBitmapResource)) + return FALSE; + BOOL all = TRUE; + if (lpszBitmapResourceSel && !m_bitmapSel.LoadBitmap(lpszBitmapResourceSel)) + all = FALSE; + if (lpszBitmapResourceFocus && !m_bitmapFocus.LoadBitmap(lpszBitmapResourceFocus)) + all = FALSE; + if (lpszBitmapResourceDisabled && !m_bitmapDisabled.LoadBitmap(lpszBitmapResourceDisabled)) + all = FALSE; + if (m_hWnd) + Invalidate(); + return all; +} + +BOOL CBitmapButton::LoadBitmaps(UINT nIDBitmapResource, UINT nIDBitmapResourceSel, UINT nIDBitmapResourceFocus, + UINT nIDBitmapResourceDisabled) { + m_bitmap.DeleteObject(); + m_bitmapSel.DeleteObject(); + m_bitmapFocus.DeleteObject(); + m_bitmapDisabled.DeleteObject(); + if (!nIDBitmapResource || !m_bitmap.LoadBitmap(nIDBitmapResource)) + return FALSE; + BOOL all = TRUE; + if (nIDBitmapResourceSel && !m_bitmapSel.LoadBitmap(nIDBitmapResourceSel)) + all = FALSE; + if (nIDBitmapResourceFocus && !m_bitmapFocus.LoadBitmap(nIDBitmapResourceFocus)) + all = FALSE; + if (nIDBitmapResourceDisabled && !m_bitmapDisabled.LoadBitmap(nIDBitmapResourceDisabled)) + all = FALSE; + if (m_hWnd) + Invalidate(); + return all; +} + +BOOL CBitmapButton::AutoLoad(UINT nID, CWnd* pParent) { + if (!SubclassDlgItem(nID, pParent)) + return FALSE; + CString name; + GetWindowText(name); + LoadBitmaps(name + "U", name + "D", name + "F", name + "X"); + if (!m_bitmap.m_hObject) + return FALSE; + SizeToContent(); + return TRUE; +} + +void CBitmapButton::SizeToContent() { + BITMAP bm; + memset(&bm, 0, sizeof bm); + if (!m_bitmap.m_hObject || m_bitmap.GetObject(sizeof bm, &bm) <= 0) + return; + SetWindowPos(nullptr, -1, -1, bm.bmWidth, bm.bmHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); +} + +void CBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) { + if (!lpDIS) + return; + CDC* pDC = CDC::FromHandle(lpDIS->hDC); + if (!pDC) + return; + CRect rect(lpDIS->rcItem.left, lpDIS->rcItem.top, lpDIS->rcItem.right, lpDIS->rcItem.bottom); + if (!m_bitmap.m_hObject) { + wxDC* dc = pDC->GetWx(); + if (!dc || !m_hWnd) + return; + wxRect r(rect.left, rect.top, rect.Width(), rect.Height()); + int flags = 0; + if (lpDIS->itemState & ODS_SELECTED) + flags |= wxCONTROL_PRESSED; + if (lpDIS->itemState & ODS_DISABLED) + flags |= wxCONTROL_DISABLED; + if (lpDIS->itemState & ODS_FOCUS) + flags |= wxCONTROL_FOCUSED; + wxRendererNative::Get().DrawPushButton(GetWx(), *dc, r, flags); + CString text; + GetWindowText(text); + dc->SetFont(GetWx()->GetFont()); + dc->SetTextForeground(wxSystemSettings::GetColour((lpDIS->itemState & ODS_DISABLED) ? wxSYS_COLOUR_GRAYTEXT + : wxSYS_COLOUR_BTNTEXT)); + dc->DrawLabel(wxStripMenuCodes(ToWx(text), wxStrip_Mnemonics), r, wxALIGN_CENTER); + return; + } + CBitmap* pBitmap = &m_bitmap; + UINT state = lpDIS->itemState; + if ((state & ODS_SELECTED) && m_bitmapSel.m_hObject) + pBitmap = &m_bitmapSel; + else if ((state & ODS_FOCUS) && m_bitmapFocus.m_hObject) + pBitmap = &m_bitmapFocus; + else if ((state & ODS_DISABLED) && m_bitmapDisabled.m_hObject) + pBitmap = &m_bitmapDisabled; + CDC memDC; + if (!memDC.CreateCompatibleDC(pDC)) + return; + CBitmap* pOld = memDC.SelectObject(pBitmap); + if (!pOld) + return; + pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY); + memDC.SelectObject(pOld); +} diff --git a/port/mfcwx/src/dialog.cpp b/port/mfcwx/src/dialog.cpp new file mode 100644 index 000000000..79c7ad354 --- /dev/null +++ b/port/mfcwx/src/dialog.cpp @@ -0,0 +1,1188 @@ +#include "windows_impl.h" + +#include "afxdlgs.h" + +#include +#include +#include +#include +#include +#include + +#include + +namespace mfcwx { + +// --------------------------------------------------------------------------------------------- +// Dialog units + +namespace { + +wxFont DialogFontFor(const rc::Dialog* tmpl) { + wxFont f = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); +#ifdef __WXOSX__ + f.SetPointSize(11); +#endif + if (tmpl && tmpl->fontName && tmpl->fontWeight >= FW_BOLD) + f.SetWeight(wxFONTWEIGHT_BOLD); + return f; +} + +wxSize BaseUnits(const wxFont& font) { + wxBitmap bmp(1, 1); + wxMemoryDC dc(bmp); + dc.SetFont(font); + wxCoord w = 0, h = 0; + dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", &w, &h); + int baseX = static_cast((w / 26 + 1) / 2); + return wxSize(std::max(4, baseX), std::max(8, static_cast(h))); +} + +} // namespace + +wxRect DialogUnitsToPixels(wxWindow* dialog, int x, int y, int cx, int cy) { + static wxSize defaultUnits = BaseUnits(DialogFontFor(nullptr)); + wxSize base = defaultUnits; + if (dialog) { + WindowState* st = GetState(dialog); + if (st && st->baseUnits.x > 0) + base = st->baseUnits; + } + return wxRect(MulDiv(x, base.x, 4), MulDiv(y, base.y, 8), MulDiv(cx, base.x, 4), MulDiv(cy, base.y, 8)); +} + +bool CreateDialogControls(wxWindow* parent, const rc::Dialog& tmpl) { + WindowState& ps = EnsureState(parent); + wxWindow* previous = nullptr; + for (int i = 0; i < tmpl.controlCount; ++i) { + const rc::Control& c = tmpl.controls[i]; + wxRect r = DialogUnitsToPixels(parent, c.x, c.y, c.cx, c.cy); + wxWindow* w = CreateControl(parent, c.cls, Utf8ToAnsi(c.text).c_str(), c.id, r, c.style, c.exStyle); + if (!w) + continue; + w->SetFont(parent->GetFont()); + WindowState* st = GetState(w); + if (st && st->kind == ControlKind::PushButton && (c.style & BS_TYPEMASK) == BS_DEFPUSHBUTTON) { + if (auto* b = wxDynamicCast(w, wxButton)) + b->SetDefault(); + ps.defaultButtonId = c.id; + } + if (st && st->kind == ControlKind::Spin && previous && (c.style & UDS_AUTOBUDDY)) { + st->buddy = WrapperFor(previous); + if (c.style & (UDS_ALIGNRIGHT | UDS_ALIGNLEFT)) { + wxRect br = previous->GetRect(); + int sw = std::max(16, w->GetBestSize().x); + if (c.style & UDS_ALIGNRIGHT) { + previous->SetSize(br.x, br.y, std::max(10, br.width - sw), br.height); + w->SetSize(br.x + std::max(10, br.width - sw), br.y, sw, br.height); + } else { + previous->SetSize(br.x + sw, br.y, std::max(10, br.width - sw), br.height); + w->SetSize(br.x, br.y, sw, br.height); + } + } + } + previous = w; + } + return true; +} + +// --------------------------------------------------------------------------------------------- +// Keyboard handling of dialogs (IsDialogMessage) + +bool PreTranslateKey(wxWindow* topLevel, wxKeyEvent& event, UINT message) { + wxWindow* focus = wxWindow::FindFocus(); + while (focus && !IsManagedWindow(focus)) + focus = focus->GetParent(); + MSG msg; + memset(&msg, 0, sizeof msg); + msg.hwnd = ToHwnd(focus ? focus : topLevel); + msg.message = message; + msg.wParam = VirtualKeyFromWx(event.GetKeyCode()); + msg.lParam = KeyLParam(event, false); + if (!msg.wParam) + return false; + for (wxWindow* w = focus ? focus : topLevel; w; w = w->GetParent()) { + CWnd* p = PermanentWnd(w); + if (p && p->PreTranslateMessage(&msg)) + return true; + if (w == topLevel) + break; + } + CWinApp* app = AfxGetApp(); + CWnd* main = app ? app->m_pMainWnd : nullptr; + if (main && main->m_hWnd && main->GetWx() != topLevel && main->PreTranslateMessage(&msg)) + return true; + return false; +} + +bool DialogKeyHook(wxWindow* dialog, wxKeyEvent& event) { + if (PreTranslateKey(dialog, event, event.AltDown() ? WM_SYSKEYDOWN : WM_KEYDOWN)) + return true; + int code = event.GetKeyCode(); + wxWindow* focus = wxWindow::FindFocus(); + WindowState* fs = nullptr; + for (wxWindow* f = focus; f && !fs; f = f->GetParent()) + fs = GetState(f); + if (code == WXK_ESCAPE) { + wxWindow* cancel = nullptr; + for (wxWindow* c : dialog->GetChildren()) { + WindowState* st = GetState(c); + if (st && st->winId == IDCANCEL) + cancel = c; + } + if (cancel && !cancel->IsEnabled()) + return true; + DispatchMessageTo(ToHwnd(dialog), WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED), reinterpret_cast(ToHwnd(cancel))); + return true; + } + if (code == WXK_RETURN || code == WXK_NUMPAD_ENTER) { + if (fs && (fs->kind == ControlKind::Edit || fs->kind == ControlKind::RichEdit) && (fs->style & ES_MULTILINE) && + (fs->style & ES_WANTRETURN)) + return false; + if (fs && (fs->kind == ControlKind::ListView || fs->kind == ControlKind::Scintilla || fs->kind == ControlKind::Generic)) + return false; + int id = IDOK; + wxWindow* target = nullptr; + if (fs && (fs->kind == ControlKind::PushButton || fs->kind == ControlKind::OwnerDrawButton)) { + id = fs->winId; + target = fs->window; + } else { + WindowState* ds = GetState(dialog); + if (ds && ds->defaultButtonId) + id = ds->defaultButtonId; + for (wxWindow* c : dialog->GetChildren()) { + WindowState* st = GetState(c); + if (st && st->winId == id) + target = c; + } + } + if (target && !target->IsEnabled()) + return true; + DispatchMessageTo(ToHwnd(dialog), WM_COMMAND, MAKEWPARAM(id, BN_CLICKED), reinterpret_cast(ToHwnd(target))); + return true; + } + if (code == WXK_F1) { + HELPINFO hi; + memset(&hi, 0, sizeof hi); + hi.cbSize = sizeof hi; + hi.iContextType = HELPINFO_WINDOW; + hi.iCtrlId = fs ? fs->winId : 0; + hi.hItemHandle = fs ? fs->window : nullptr; + wxPoint p = wxGetMousePosition(); + hi.MousePos.x = p.x; + hi.MousePos.y = p.y; + HWND target = fs ? ToHwnd(fs->window) : ToHwnd(dialog); + DispatchMessageTo(target, WM_HELP, 0, reinterpret_cast(&hi)); + return true; + } + return false; +} + +BOOL ApplyDlgInit(CWnd* pWnd, int dialogId) { + if (!pWnd || !pWnd->m_hWnd || !dialogId) + return TRUE; + for (const rc::DlgInitEntry* e : FindDlgInit(dialogId)) { + HWND h = ::GetDlgItem(pWnd->m_hWnd, e->controlId); + WindowState* st = h ? GetState(ToWx(h)) : nullptr; + if (!st) + continue; + std::string text = Utf8ToAnsi(e->text); + UINT msg = st->kind == ControlKind::ListBox ? LB_ADDSTRING : CB_ADDSTRING; + DispatchMessageTo(h, msg, 0, reinterpret_cast(text.c_str())); + } + return TRUE; +} + +namespace { + +long DialogWxStyle(DWORD style) { + long f = 0; + if (style & WS_CAPTION) + f |= wxCAPTION; + if (style & WS_SYSMENU) + f |= wxSYSTEM_MENU | wxCLOSE_BOX; + if (style & WS_THICKFRAME) + f |= wxRESIZE_BORDER; + if (style & WS_MINIMIZEBOX) + f |= wxMINIMIZE_BOX; + if (style & WS_MAXIMIZEBOX) + f |= wxMAXIMIZE_BOX; + if (!(style & WS_CAPTION)) + f |= wxBORDER_SIMPLE; + return f; +} + +class MfcDialog : public wxDialog { +public: + MfcDialog(wxWindow* parent, const wxString& title, long style) : wxDialog() { + SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS); + Create(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, style); + Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { + if (IsManagedWindow(this)) { + e.Veto(); + DispatchMessageTo(ToHwnd(this), WM_CLOSE, 0, 0); + } else { + e.Skip(); + } + }); + Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) { + if (!DialogKeyHook(this, e)) + e.Skip(); + }); + } +}; + +class MfcPanel : public wxPanel { +public: + MfcPanel(wxWindow* parent, const wxPoint& pos, const wxSize& size) + : wxPanel(parent, wxID_ANY, pos, size, wxTAB_TRAVERSAL | wxBORDER_NONE) {} +}; + +} // namespace + +// Creates the window of a dialog from its template; returns null on failure. +wxWindow* CreateDialogWindow(CDialog* dlg, const rc::Dialog& tmpl, wxWindow* parent) { + wxFont font = DialogFontFor(&tmpl); + wxSize base = BaseUnits(font); + wxRect r(MulDiv(tmpl.x, base.x, 4), MulDiv(tmpl.y, base.y, 8), MulDiv(tmpl.cx, base.x, 4), + MulDiv(tmpl.cy, base.y, 8)); + wxWindow* w = nullptr; + ControlKind kind = ControlKind::Dialog; + if ((tmpl.style & WS_CHILD) && parent) { + w = new MfcPanel(parent, r.GetPosition(), r.GetSize()); + kind = ControlKind::Generic; + } else { + auto* d = new MfcDialog(parent, wxString::FromUTF8(tmpl.caption ? tmpl.caption : ""), DialogWxStyle(tmpl.style)); + d->SetClientSize(r.GetSize()); + w = d; + } + w->SetFont(font); + HookWindow(w, kind, static_cast(tmpl.id), tmpl.style, tmpl.exStyle); + WindowState& st = EnsureState(w); + st.baseUnits = base; + st.text = wxString::FromUTF8(tmpl.caption ? tmpl.caption : ""); + if (dlg) + dlg->AttachWx(w); + CreateDialogControls(w, tmpl); + if (w->IsTopLevel()) { + if (tmpl.style & (DS_CENTER | DS_CENTERMOUSE) || true) + w->CentreOnParent(); + } + return w; +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CDialog + +IMPLEMENT_DYNAMIC(CDialog, CWnd) + +BEGIN_MESSAGE_MAP(CDialog, CWnd) + ON_COMMAND(IDOK, &CDialog::OnOK) + ON_COMMAND(IDCANCEL, &CDialog::OnCancel) + ON_COMMAND(ID_HELP, &CDialog::OnHelp) + ON_MESSAGE(WM_INITDIALOG, &CDialog::HandleInitDialog) +END_MESSAGE_MAP() + +CDialog::CDialog() + : m_nIDHelp(0), m_lpszTemplateName(nullptr), m_nIDTemplate(0), m_pParentWnd(nullptr), m_bModalRunning(FALSE), + m_nModalResult(-1) {} + +CDialog::CDialog(const char* lpszTemplateName, CWnd* pParentWnd) : CDialog() { + if (IS_INTRESOURCE(lpszTemplateName)) + m_nIDTemplate = static_cast(reinterpret_cast(lpszTemplateName)); + else + m_lpszTemplateName = lpszTemplateName; + m_pParentWnd = pParentWnd; + m_nIDHelp = m_nIDTemplate; +} + +CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd) : CDialog() { + m_nIDTemplate = nIDTemplate; + m_pParentWnd = pParentWnd; + m_nIDHelp = nIDTemplate; +} + +CDialog::~CDialog() { + if (m_hWnd) + DestroyWindow(); +} + +BOOL CDialog::CreateFromTemplate(BOOL bModal) { + ResRef ref = m_lpszTemplateName ? ResRef::From(m_lpszTemplateName) : ResRef::FromId(m_nIDTemplate); + const rc::Dialog* tmpl = FindDialog(ref); + if (!tmpl) { + wxLogDebug("mfcwx: dialog template %d not found", static_cast(m_nIDTemplate)); + return FALSE; + } + CWnd* parent = m_pParentWnd; + if (!parent && bModal) + parent = AfxGetMainWnd(); + wxWindow* parentWx = parent && parent->m_hWnd ? parent->GetWx() : nullptr; + if (parentWx && bModal) + parentWx = wxGetTopLevelParent(parentWx); + wxWindow* w = CreateDialogWindow(this, *tmpl, parentWx); + if (!w) + return FALSE; + ApplyDlgInit(this, tmpl->id); + m_nModalResult = -1; + m_bModalRunning = bModal; + if (!SendMessage(WM_INITDIALOG, 0, 0) && m_hWnd) { + } + if (!m_hWnd) + return FALSE; + for (wxWindow* c : w->GetChildren()) + ApplyCtlColor(c); + if (!bModal && (tmpl->style & WS_VISIBLE)) + w->Show(); + return TRUE; +} + +LRESULT CDialog::HandleInitDialog(WPARAM, LPARAM) { + BOOL focusDefault = OnInitDialog(); + if (focusDefault && m_hWnd) { + HWND first = ::GetNextDlgTabItem(m_hWnd, nullptr, FALSE); + if (first) + ::SetFocus(first); + } + return focusDefault; +} + +BOOL CDialog::OnInitDialog() { + UpdateData(FALSE); + return TRUE; +} + +INT_PTR CDialog::DoModal() { + return OnMain([&]() -> INT_PTR { + if (!CreateFromTemplate(TRUE)) + return -1; + wxWindow* w = GetWx(); + auto* dlg = wxDynamicCast(w, wxDialog); + if (dlg && m_bModalRunning && m_nModalResult == -1) { + wxWindow* active = wxGetActiveWindow(); + dlg->ShowModal(); + if (active && active != dlg && !active->IsBeingDeleted()) + active->Raise(); + } + m_bModalRunning = FALSE; + int result = m_nModalResult; + if (m_hWnd) + DestroyWindow(); + return result; + }); +} + +void CDialog::EndDialog(int nResult) { + OnMain([&] { + m_nModalResult = nResult; + if (!m_hWnd) + return; + auto* dlg = wxDynamicCast(GetWx(), wxDialog); + if (m_bModalRunning) { + if (dlg && dlg->IsModal()) + dlg->EndModal(nResult); + } else if (dlg) { + dlg->Hide(); + } + }); +} + +BOOL CDialog::Create(UINT nIDTemplate, CWnd* pParentWnd) { + m_nIDTemplate = nIDTemplate; + m_lpszTemplateName = nullptr; + m_pParentWnd = pParentWnd; + if (!m_nIDHelp) + m_nIDHelp = nIDTemplate; + return OnMain([&]() -> BOOL { return CreateFromTemplate(FALSE); }); +} + +BOOL CDialog::Create(const char* lpszTemplateName, CWnd* pParentWnd) { + if (IS_INTRESOURCE(lpszTemplateName)) + return Create(static_cast(reinterpret_cast(lpszTemplateName)), pParentWnd); + m_lpszTemplateName = lpszTemplateName; + m_pParentWnd = pParentWnd; + return OnMain([&]() -> BOOL { return CreateFromTemplate(FALSE); }); +} + +BOOL CDialog::CreateIndirect(const void*, CWnd*, void*) { return FALSE; } +BOOL CDialog::InitModalIndirect(const void*, CWnd*, void*) { return FALSE; } + +BOOL CDialog::DestroyWindow() { + if (m_hWnd && m_bModalRunning) { + EndDialog(IDCANCEL); + m_bModalRunning = FALSE; + } + return CWnd::DestroyWindow(); +} + +void CDialog::OnOK() { + if (!UpdateData(TRUE)) + return; + EndDialog(IDOK); +} + +void CDialog::OnCancel() { EndDialog(IDCANCEL); } + +void CDialog::OnHelp() { + CWinApp* app = AfxGetApp(); + if (app && m_nIDHelp) + app->WinHelpInternal(0x20000 + m_nIDHelp, HELP_CONTEXT); +} + +void CDialog::MapDialogRect(LPRECT lpRect) const { ::MapDialogRect(m_hWnd, lpRect); } + +void CDialog::SetDefID(UINT nID) { SendMessage(DM_SETDEFID, nID, 0); } + +DWORD CDialog::GetDefID() const { return static_cast(const_cast(this)->SendMessage(DM_GETDEFID)); } + +void CDialog::NextDlgCtrl() const { const_cast(this)->SendMessage(WM_NEXTDLGCTL, 0, 0); } +void CDialog::PrevDlgCtrl() const { const_cast(this)->SendMessage(WM_NEXTDLGCTL, 1, 0); } + +void CDialog::GotoDlgCtrl(CWnd* pWndCtrl) { + if (pWndCtrl && pWndCtrl->m_hWnd) + SendMessage(WM_NEXTDLGCTL, reinterpret_cast(pWndCtrl->m_hWnd), 1); +} + +// --------------------------------------------------------------------------------------------- +// Data exchange + +CDataExchange::CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate) + : m_bSaveAndValidate(bSaveAndValidate), m_pDlgWnd(pDlgWnd), m_hWndLastControl(nullptr), m_bEditLastControl(FALSE) {} + +HWND CDataExchange::PrepareCtrl(int nIDC) { + HWND h = ::GetDlgItem(m_pDlgWnd->m_hWnd, nIDC); + if (!h) + wxLogDebug("mfcwx: DDX control %d not found", nIDC); + m_hWndLastControl = h; + m_bEditLastControl = FALSE; + return h; +} + +HWND CDataExchange::PrepareEditCtrl(int nIDC) { + HWND h = PrepareCtrl(nIDC); + m_bEditLastControl = TRUE; + return h; +} + +void CDataExchange::Fail() { + if (m_bSaveAndValidate && m_hWndLastControl) { + ::SetFocus(m_hWndLastControl); + if (m_bEditLastControl) + ::SendMessage(m_hWndLastControl, EM_SETSEL, 0, -1); + } + throw new CUserException(); +} + +namespace { + +CString PromptText(UINT id, const char* fallback) { + CString s; + if (!s.LoadString(id)) + s = fallback; + return s; +} + +void FailWith(CDataExchange* pDX, UINT id, const char* fallback, const char* a1 = nullptr, const char* a2 = nullptr) { + CString text = PromptText(id, fallback); + if (a1) { + text.Replace("%1", a1); + if (a2) + text.Replace("%2", a2); + } + AfxMessageBox(text, MB_ICONEXCLAMATION); + pDX->Fail(); +} + +void SetTextIfChanged(HWND h, const char* text) { + char buf[256]; + int len = ::GetWindowTextLength(h); + if (len < static_cast(sizeof buf)) { + ::GetWindowText(h, buf, sizeof buf); + if (strcmp(buf, text) == 0) + return; + } + ::SetWindowText(h, text); +} + +CString WindowText(HWND h) { + int len = ::GetWindowTextLength(h); + CString s; + ::GetWindowText(h, s.GetBuffer(len + 1), len + 1); + s.ReleaseBuffer(); + return s; +} + +template +void TextSigned(CDataExchange* pDX, int nIDC, T& value) { + HWND h = pDX->PrepareEditCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) { + CString s = WindowText(h); + s.Trim(); + char* end = nullptr; + long long v = strtoll(s, &end, 10); + if (s.IsEmpty() || (end && *end)) + FailWith(pDX, AFX_IDP_PARSE_INT, "Please enter an integer."); + value = static_cast(v); + } else { + char buf[32]; + snprintf(buf, sizeof buf, "%lld", static_cast(value)); + SetTextIfChanged(h, buf); + } +} + +template +void TextUnsigned(CDataExchange* pDX, int nIDC, T& value) { + HWND h = pDX->PrepareEditCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) { + CString s = WindowText(h); + s.Trim(); + char* end = nullptr; + unsigned long long v = strtoull(s, &end, 10); + if (s.IsEmpty() || (end && *end) || s[0] == '-') + FailWith(pDX, AFX_IDP_PARSE_UINT, "Please enter a positive integer."); + value = static_cast(v); + } else { + char buf[32]; + snprintf(buf, sizeof buf, "%llu", static_cast(value)); + SetTextIfChanged(h, buf); + } +} + +template +void TextFloat(CDataExchange* pDX, int nIDC, T& value, int digits) { + HWND h = pDX->PrepareEditCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) { + CString s = WindowText(h); + s.Trim(); + char* end = nullptr; + double v = strtod(s, &end); + if (s.IsEmpty() || (end && *end)) + FailWith(pDX, AFX_IDP_PARSE_REAL, "Please enter a number."); + value = static_cast(v); + } else { + char buf[64]; + snprintf(buf, sizeof buf, "%.*g", digits, static_cast(value)); + SetTextIfChanged(h, buf); + } +} + +template +void MinMax(CDataExchange* pDX, T value, T minVal, T maxVal, UINT id, const char* fmt) { + if (!pDX->m_bSaveAndValidate || (value >= minVal && value <= maxVal)) + return; + char a[64], b[64]; + snprintf(a, sizeof a, fmt, minVal); + snprintf(b, sizeof b, fmt, maxVal); + FailWith(pDX, id, "Please enter a value between %1 and %2.", a, b); +} + +std::vector RadioGroup(CDataExchange* pDX, int nIDC) { + std::vector group; + HWND first = pDX->PrepareCtrl(nIDC); + if (!first) + return group; + for (HWND h = first; h; h = ::GetWindow(h, GW_HWNDNEXT)) { + if (h != first && (::GetWindowLongPtr(h, GWL_STYLE) & WS_GROUP)) + break; + WindowState* st = GetState(ToWx(h)); + if (st && st->kind == ControlKind::RadioButton) + group.push_back(h); + } + return group; +} + +} // namespace + +void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl) { + if (rControl.m_hWnd) + return; + HWND h = pDX->PrepareCtrl(nIDC); + if (h) + rControl.SubclassWindow(h); +} + +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, BYTE& value) { + int v = value; + TextSigned(pDX, nIDC, v); + if (pDX->m_bSaveAndValidate) { + if (v < 0 || v > 255) + FailWith(pDX, AFX_IDP_PARSE_BYTE, "Please enter an integer between 0 and 255."); + value = static_cast(v); + } +} +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, short& value) { TextSigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, int& value) { TextSigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, UINT& value) { TextUnsigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, long& value) { TextSigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, unsigned long& value) { TextUnsigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, LONGLONG& value) { TextSigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, ULONGLONG& value) { TextUnsigned(pDX, nIDC, value); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, float& value) { TextFloat(pDX, nIDC, value, FLT_DIG); } +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, double& value) { TextFloat(pDX, nIDC, value, DBL_DIG); } + +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value) { + HWND h = pDX->PrepareEditCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + value = WindowText(h); + else + SetTextIfChanged(h, value); +} + +void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, char* value, int nMaxLen) { + HWND h = pDX->PrepareEditCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + ::GetWindowText(h, value, nMaxLen); + else + SetTextIfChanged(h, value); +} + +void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, int& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + value = static_cast(::SendMessage(h, BM_GETCHECK, 0, 0)); + else + ::SendMessage(h, BM_SETCHECK, static_cast(value), 0); +} + +void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, bool& value) { + int v = value ? 1 : 0; + DDX_Check(pDX, nIDC, v); + value = v != 0; +} + +void AFXAPI DDX_Radio(CDataExchange* pDX, int nIDC, int& value) { + std::vector group = RadioGroup(pDX, nIDC); + if (pDX->m_bSaveAndValidate) { + value = -1; + for (size_t i = 0; i < group.size(); ++i) + if (::SendMessage(group[i], BM_GETCHECK, 0, 0) == BST_CHECKED) + value = static_cast(i); + } else { + for (size_t i = 0; i < group.size(); ++i) + ::SendMessage(group[i], BM_SETCHECK, static_cast(i) == value ? BST_CHECKED : BST_UNCHECKED, 0); + } +} + +void AFXAPI DDX_LBString(CDataExchange* pDX, int nIDC, CString& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) { + int sel = static_cast(::SendMessage(h, LB_GETCURSEL, 0, 0)); + if (sel == LB_ERR) { + value.Empty(); + return; + } + int len = static_cast(::SendMessage(h, LB_GETTEXTLEN, static_cast(sel), 0)); + ::SendMessage(h, LB_GETTEXT, static_cast(sel), reinterpret_cast(value.GetBuffer(len + 1))); + value.ReleaseBuffer(); + } else if (::SendMessage(h, LB_SELECTSTRING, static_cast(-1), reinterpret_cast(value.GetString())) == LB_ERR) { + ::SendMessage(h, LB_SETCURSEL, static_cast(-1), 0); + } +} + +void AFXAPI DDX_LBStringExact(CDataExchange* pDX, int nIDC, CString& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) { + DDX_LBString(pDX, nIDC, value); + return; + } + LRESULT i = ::SendMessage(h, LB_FINDSTRINGEXACT, static_cast(-1), reinterpret_cast(value.GetString())); + ::SendMessage(h, LB_SETCURSEL, static_cast(i == LB_ERR ? -1 : i), 0); +} + +void AFXAPI DDX_CBString(CDataExchange* pDX, int nIDC, CString& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + WindowState* st = GetState(ToWx(h)); + if (pDX->m_bSaveAndValidate) { + if (st && st->kind == ControlKind::ComboList) { + int sel = static_cast(::SendMessage(h, CB_GETCURSEL, 0, 0)); + if (sel == CB_ERR) { + value.Empty(); + return; + } + int len = static_cast(::SendMessage(h, CB_GETLBTEXTLEN, static_cast(sel), 0)); + ::SendMessage(h, CB_GETLBTEXT, static_cast(sel), reinterpret_cast(value.GetBuffer(len + 1))); + value.ReleaseBuffer(); + } else { + value = WindowText(h); + } + } else { + if (::SendMessage(h, CB_SELECTSTRING, static_cast(-1), reinterpret_cast(value.GetString())) == CB_ERR) + ::SetWindowText(h, value); + } +} + +void AFXAPI DDX_CBStringExact(CDataExchange* pDX, int nIDC, CString& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) { + DDX_CBString(pDX, nIDC, value); + return; + } + LRESULT i = ::SendMessage(h, CB_FINDSTRINGEXACT, static_cast(-1), reinterpret_cast(value.GetString())); + if (i == CB_ERR) + ::SetWindowText(h, value); + else + ::SendMessage(h, CB_SETCURSEL, static_cast(i), 0); +} + +void AFXAPI DDX_LBIndex(CDataExchange* pDX, int nIDC, int& index) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + index = static_cast(::SendMessage(h, LB_GETCURSEL, 0, 0)); + else + ::SendMessage(h, LB_SETCURSEL, static_cast(index), 0); +} + +void AFXAPI DDX_CBIndex(CDataExchange* pDX, int nIDC, int& index) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + index = static_cast(::SendMessage(h, CB_GETCURSEL, 0, 0)); + else + ::SendMessage(h, CB_SETCURSEL, static_cast(index), 0); +} + +void AFXAPI DDX_Scroll(CDataExchange* pDX, int nIDC, int& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + value = static_cast(::SendMessage(h, SBM_GETPOS, 0, 0)); + else + ::SendMessage(h, SBM_SETPOS, static_cast(value), TRUE); +} + +void AFXAPI DDX_Slider(CDataExchange* pDX, int nIDC, int& value) { + HWND h = pDX->PrepareCtrl(nIDC); + if (!h) + return; + if (pDX->m_bSaveAndValidate) + value = static_cast(::SendMessage(h, TBM_GETPOS, 0, 0)); + else + ::SendMessage(h, TBM_SETPOS, TRUE, value); +} + +void AFXAPI DDV_MaxChars(CDataExchange* pDX, const CString& value, int nChars) { + if (pDX->m_bSaveAndValidate) { + if (value.GetLength() > nChars) { + char n[32]; + snprintf(n, sizeof n, "%d", nChars); + FailWith(pDX, AFX_IDP_PARSE_STRING_SIZE, "Please enter no more than %1 characters.", n); + } + } else if (pDX->m_hWndLastControl && pDX->m_bEditLastControl) { + WindowState* st = GetState(ToWx(pDX->m_hWndLastControl)); + if (st && st->kind == ControlKind::ComboBox) + ::SendMessage(pDX->m_hWndLastControl, CB_LIMITTEXT, static_cast(nChars), 0); + else + ::SendMessage(pDX->m_hWndLastControl, EM_LIMITTEXT, static_cast(nChars), 0); + } +} + +void AFXAPI DDV_MinMaxByte(CDataExchange* pDX, BYTE value, BYTE minVal, BYTE maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%d"); +} +void AFXAPI DDV_MinMaxShort(CDataExchange* pDX, short value, short minVal, short maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%d"); +} +void AFXAPI DDV_MinMaxInt(CDataExchange* pDX, int value, int minVal, int maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%d"); +} +void AFXAPI DDV_MinMaxLong(CDataExchange* pDX, long value, long minVal, long maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%ld"); +} +void AFXAPI DDV_MinMaxUInt(CDataExchange* pDX, UINT value, UINT minVal, UINT maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%u"); +} +void AFXAPI DDV_MinMaxDWord(CDataExchange* pDX, DWORD value, DWORD minVal, DWORD maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%u"); +} +void AFXAPI DDV_MinMaxLongLong(CDataExchange* pDX, LONGLONG value, LONGLONG minVal, LONGLONG maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%lld"); +} +void AFXAPI DDV_MinMaxULongLong(CDataExchange* pDX, ULONGLONG value, ULONGLONG minVal, ULONGLONG maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%llu"); +} +void AFXAPI DDV_MinMaxFloat(CDataExchange* pDX, float const& value, float minVal, float maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_REAL_RANGE, "%g"); +} +void AFXAPI DDV_MinMaxDouble(CDataExchange* pDX, double const& value, double minVal, double maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_REAL_RANGE, "%g"); +} +void AFXAPI DDV_MinMaxSlider(CDataExchange* pDX, DWORD value, DWORD minVal, DWORD maxVal) { + MinMax(pDX, value, minVal, maxVal, AFX_IDP_PARSE_INT_RANGE, "%u"); +} + +// --------------------------------------------------------------------------------------------- +// Common dialogs + +IMPLEMENT_DYNAMIC(CCommonDialog, CDialog) +IMPLEMENT_DYNAMIC(CFileDialog, CCommonDialog) +IMPLEMENT_DYNAMIC(CColorDialog, CCommonDialog) +IMPLEMENT_DYNAMIC(CFontDialog, CCommonDialog) +IMPLEMENT_DYNAMIC(CPageSetupDialog, CCommonDialog) +IMPLEMENT_DYNAMIC(CPrintDialog, CCommonDialog) +IMPLEMENT_DYNAMIC(CFindReplaceDialog, CCommonDialog) +IMPLEMENT_DYNAMIC(CPropertyPage, CDialog) +IMPLEMENT_DYNAMIC(CPropertySheet, CWnd) + +namespace { + +wxWindow* OwnerWindow(CWnd* pParent) { + if (pParent && pParent->m_hWnd) + return wxGetTopLevelParent(pParent->GetWx()); + return MainWxWindow(); +} + +// "Text (*.txt)|*.txt|All files (*.*)|*.*||" -> wx wildcard +wxString MfcFilterToWx(const CString& filter) { + wxString f = ToWx(filter); + while (f.EndsWith("|")) + f.RemoveLast(); + return f.empty() ? wxString("*") : f; +} + +} // namespace + +CFileDialog::CFileDialog(BOOL bOpenFileDialog, const char* lpszDefExt, const char* lpszFileName, DWORD dwFlags, + const char* lpszFilter, CWnd* pParentWnd, DWORD, BOOL) + : CCommonDialog(pParentWnd), m_bOpenFileDialog(bOpenFileDialog) { + memset(&m_ofn, 0, sizeof m_ofn); + m_ofn.lStructSize = sizeof m_ofn; + m_ofn.Flags = dwFlags; + m_szFileName[0] = 0; + m_szFileTitle[0] = 0; + if (lpszFileName) { + strncpy(m_szFileName, lpszFileName, sizeof m_szFileName - 1); + m_szFileName[sizeof m_szFileName - 1] = 0; + } + m_ofn.lpstrFile = m_szFileName; + m_ofn.nMaxFile = sizeof m_szFileName; + m_ofn.lpstrFileTitle = m_szFileTitle; + m_ofn.nMaxFileTitle = sizeof m_szFileTitle; + m_ofn.nFilterIndex = 1; + if (lpszDefExt) + m_strDefExt = lpszDefExt; + if (lpszFilter) + m_strFilter = lpszFilter; +} + +INT_PTR CFileDialog::DoModal() { + return OnMain([&]() -> INT_PTR { + long style = m_bOpenFileDialog ? wxFD_OPEN : wxFD_SAVE; + if (m_bOpenFileDialog && (m_ofn.Flags & OFN_FILEMUSTEXIST)) + style |= wxFD_FILE_MUST_EXIST; + if (!m_bOpenFileDialog && (m_ofn.Flags & OFN_OVERWRITEPROMPT)) + style |= wxFD_OVERWRITE_PROMPT; + if (m_ofn.Flags & OFN_ALLOWMULTISELECT) + style |= wxFD_MULTIPLE; + wxString initialDir; + if (m_ofn.lpstrInitialDir && *m_ofn.lpstrInitialDir) + initialDir = NativePathWx(m_ofn.lpstrInitialDir); + else if (!m_strInitialDir.IsEmpty()) + initialDir = NativePathWx(m_strInitialDir); + wxFileName current(NativePathWx(m_ofn.lpstrFile ? m_ofn.lpstrFile : "")); + if (initialDir.empty() && current.IsAbsolute()) + initialDir = current.GetPath(); + wxString title = m_ofn.lpstrTitle ? ToWx(m_ofn.lpstrTitle) : ToWx(m_strTitle); + wxFileDialog dlg(OwnerWindow(m_pParentWnd), title, initialDir, current.GetFullName(), MfcFilterToWx(m_strFilter), + style); + if (m_ofn.nFilterIndex > 0) + dlg.SetFilterIndex(static_cast(m_ofn.nFilterIndex) - 1); + if (dlg.ShowModal() != wxID_OK) + return IDCANCEL; + m_paths.clear(); + wxArrayString paths; + if (style & wxFD_MULTIPLE) + dlg.GetPaths(paths); + else + paths.Add(dlg.GetPath()); + for (const wxString& p : paths) { + std::string a = AppPath(p.utf8_str()); + CString path(a.c_str()); + if (!m_bOpenFileDialog && !m_strDefExt.IsEmpty()) { + int slash = path.ReverseFind('\\'); + if (path.Find('.', slash + 1) < 0) + path += "." + m_strDefExt; + } + m_paths.push_back(path); + } + strncpy(m_szFileName, m_paths.front(), sizeof m_szFileName - 1); + m_szFileName[sizeof m_szFileName - 1] = 0; + CString title2 = GetFileName(); + strncpy(m_szFileTitle, title2, sizeof m_szFileTitle - 1); + m_szFileTitle[sizeof m_szFileTitle - 1] = 0; + m_ofn.nFilterIndex = static_cast(dlg.GetFilterIndex() + 1); + return IDOK; + }); +} + +CString CFileDialog::GetPathName() const { return m_paths.empty() ? CString(m_szFileName) : m_paths.front(); } + +CString CFileDialog::GetFileName() const { + CString p = GetPathName(); + int slash = p.ReverseFind('\\'); + return p.Mid(slash + 1); +} + +CString CFileDialog::GetFileExt() const { + CString n = GetFileName(); + int dot = n.ReverseFind('.'); + return dot < 0 ? CString() : n.Mid(dot + 1); +} + +CString CFileDialog::GetFileTitle() const { + CString n = GetFileName(); + int dot = n.ReverseFind('.'); + return dot < 0 ? n : n.Left(dot); +} + +CString CFileDialog::GetFolderPath() const { + CString p = GetPathName(); + int slash = p.ReverseFind('\\'); + return slash < 0 ? CString() : p.Left(slash); +} + +POSITION CFileDialog::GetStartPosition() const { + return m_paths.empty() ? nullptr : reinterpret_cast(static_cast(1)); +} + +CString CFileDialog::GetNextPathName(POSITION& pos) const { + size_t i = static_cast(reinterpret_cast(pos)) - 1; + CString r = i < m_paths.size() ? m_paths[i] : CString(); + pos = i + 1 < m_paths.size() ? reinterpret_cast(static_cast(i + 2)) : nullptr; + return r; +} + +CColorDialog::CColorDialog(COLORREF clrInit, DWORD dwFlags, CWnd* pParentWnd) : CCommonDialog(pParentWnd) { + memset(&m_cc, 0, sizeof m_cc); + m_cc.lStructSize = sizeof m_cc; + m_cc.rgbResult = clrInit; + m_cc.Flags = dwFlags; +} + +INT_PTR CColorDialog::DoModal() { + return OnMain([&]() -> INT_PTR { + wxColourData data; + data.SetColour(ToWxColour(m_cc.rgbResult)); + wxColourDialog dlg(OwnerWindow(m_pParentWnd), &data); + if (dlg.ShowModal() != wxID_OK) + return IDCANCEL; + m_cc.rgbResult = FromWxColour(dlg.GetColourData().GetColour()); + return IDOK; + }); +} + +CFontDialog::CFontDialog(LPLOGFONT lplfInitial, DWORD dwFlags, CDC*, CWnd* pParentWnd) : CCommonDialog(pParentWnd) { + memset(&m_cf, 0, sizeof m_cf); + memset(&m_lf, 0, sizeof m_lf); + m_cf.lStructSize = sizeof m_cf; + m_cf.Flags = dwFlags; + m_cf.lpLogFont = &m_lf; + if (lplfInitial) + m_lf = *lplfInitial; +} + +INT_PTR CFontDialog::DoModal() { + return OnMain([&]() -> INT_PTR { + wxFontData data; + if (m_lf.lfFaceName[0]) { + CFont initial; + initial.CreateFontIndirect(&m_lf); + data.SetInitialFont(FontFromHandle(reinterpret_cast(initial.m_hObject))); + } + data.SetColour(ToWxColour(m_cf.rgbColors)); + wxFontDialog dlg(OwnerWindow(m_pParentWnd), data); + if (dlg.ShowModal() != wxID_OK) + return IDCANCEL; + wxFont f = dlg.GetFontData().GetChosenFont(); + std::string face = mfcwx::FromWx(f.GetFaceName()); + memset(m_lf.lfFaceName, 0, sizeof m_lf.lfFaceName); + strncpy(m_lf.lfFaceName, face.c_str(), sizeof m_lf.lfFaceName - 1); + m_lf.lfHeight = -MulDiv(f.GetPointSize(), 96, 72); + m_lf.lfWeight = f.GetWeight() >= wxFONTWEIGHT_BOLD ? FW_BOLD : FW_NORMAL; + m_lf.lfItalic = f.GetStyle() == wxFONTSTYLE_ITALIC; + m_lf.lfUnderline = f.GetUnderlined(); + m_cf.iPointSize = f.GetPointSize() * 10; + m_cf.rgbColors = FromWxColour(dlg.GetFontData().GetColour()); + if (m_cf.lpLogFont && m_cf.lpLogFont != &m_lf) + *m_cf.lpLogFont = m_lf; + return IDOK; + }); +} + +void CFontDialog::GetCurrentFont(LPLOGFONT lplf) { + if (lplf) + *lplf = m_lf; +} + +CString CFontDialog::GetFaceName() const { return CString(m_lf.lfFaceName); } +int CFontDialog::GetSize() const { return m_cf.iPointSize; } + +CPageSetupDialog::CPageSetupDialog(DWORD dwFlags, CWnd* pParentWnd) : CCommonDialog(pParentWnd) { + memset(&m_psd, 0, sizeof m_psd); + m_psd.Flags = dwFlags; +} + +INT_PTR CPageSetupDialog::DoModal() { return IDCANCEL; } +CSize CPageSetupDialog::GetPaperSize() const { return CSize(21000, 29700); } +void CPageSetupDialog::GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const { + if (lpRectMargins) + *lpRectMargins = m_psd.rtMargin; + if (lpRectMinMargins) + *lpRectMinMargins = m_psd.rtMinMargin; +} + +CPrintDialog::CPrintDialog(BOOL, DWORD dwFlags, CWnd* pParentWnd) : CCommonDialog(pParentWnd) { + memset(&m_pd, 0, sizeof m_pd); + m_pd.lStructSize = sizeof m_pd; + m_pd.Flags = dwFlags; +} + +INT_PTR CPrintDialog::DoModal() { return IDCANCEL; } + +namespace { + +std::map& FindDialogs() { + static std::map m; + return m; +} + +} // namespace + +CFindReplaceDialog::CFindReplaceDialog() : CCommonDialog(nullptr), m_flags(FR_DOWN) {} + +BOOL CFindReplaceDialog::Create(BOOL bFindDialogOnly, const char* lpszFindWhat, const char* lpszReplaceWith, + DWORD dwFlags, CWnd* pParentWnd) { + return OnMain([&]() -> BOOL { + m_find = lpszFindWhat ? lpszFindWhat : ""; + m_replace = lpszReplaceWith ? lpszReplaceWith : ""; + m_flags = dwFlags; + m_pParentWnd = pParentWnd; + auto* data = new wxFindReplaceData(static_cast((dwFlags & FR_DOWN ? wxFR_DOWN : 0) | + (dwFlags & FR_MATCHCASE ? wxFR_MATCHCASE : 0) | + (dwFlags & FR_WHOLEWORD ? wxFR_WHOLEWORD : 0))); + data->SetFindString(ToWx(m_find)); + data->SetReplaceString(ToWx(m_replace)); + auto* dlg = new wxFindReplaceDialog(OwnerWindow(pParentWnd), data, wxString(), + bFindDialogOnly ? 0 : wxFR_REPLACEDIALOG); + HookWindow(dlg, ControlKind::Dialog, 0, WS_POPUP | WS_CAPTION, 0); + AttachWx(dlg); + FindDialogs()[dlg] = this; + static const UINT findMsg = RegisterWindowMessage(FINDMSGSTRING); + CWnd* owner = pParentWnd; + auto notify = [this, dlg, data, owner](DWORD extra) { + m_find = CStr(data->GetFindString()); + m_replace = CStr(data->GetReplaceString()); + int f = data->GetFlags(); + m_flags = extra | (f & wxFR_DOWN ? FR_DOWN : 0) | (f & wxFR_MATCHCASE ? FR_MATCHCASE : 0) | + (f & wxFR_WHOLEWORD ? FR_WHOLEWORD : 0); + if (owner && owner->m_hWnd) + owner->SendMessage(findMsg, 0, reinterpret_cast(this)); + (void)dlg; + }; + dlg->Bind(wxEVT_FIND, [notify](wxFindDialogEvent&) { notify(FR_FINDNEXT); }); + dlg->Bind(wxEVT_FIND_NEXT, [notify](wxFindDialogEvent&) { notify(FR_FINDNEXT); }); + dlg->Bind(wxEVT_FIND_REPLACE, [notify](wxFindDialogEvent&) { notify(FR_REPLACE); }); + dlg->Bind(wxEVT_FIND_REPLACE_ALL, [notify](wxFindDialogEvent&) { notify(FR_REPLACEALL); }); + dlg->Bind(wxEVT_FIND_CLOSE, [this, notify, dlg, data](wxFindDialogEvent&) { + notify(FR_DIALOGTERM); + FindDialogs().erase(dlg); + DestroyWindow(); + delete data; + }); + dlg->Show(); + return TRUE; + }); +} + +CFindReplaceDialog* CFindReplaceDialog::GetNotifier(LPARAM lParam) { return reinterpret_cast(lParam); } + +CPropertyPage::CPropertyPage() : CDialog() {} +CPropertyPage::CPropertyPage(UINT nIDTemplate, UINT nIDCaption, DWORD) : CDialog(nIDTemplate) { + if (nIDCaption) + m_strCaption.LoadString(nIDCaption); +} + +CPropertySheet::CPropertySheet() : m_pParentWnd(nullptr), m_active(0) {} +CPropertySheet::CPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + : m_pParentWnd(pParentWnd), m_active(static_cast(iSelectPage)) { + m_strCaption.LoadString(nIDCaption); +} +CPropertySheet::CPropertySheet(const char* pszCaption, CWnd* pParentWnd, UINT iSelectPage) + : m_strCaption(pszCaption), m_pParentWnd(pParentWnd), m_active(static_cast(iSelectPage)) {} + +void CPropertySheet::AddPage(CPropertyPage* pPage) { m_pages.push_back(pPage); } + +void CPropertySheet::RemovePage(CPropertyPage* pPage) { + m_pages.erase(std::remove(m_pages.begin(), m_pages.end(), pPage), m_pages.end()); +} + +BOOL CPropertySheet::SetActivePage(int nPage) { + m_active = nPage; + return TRUE; +} + +INT_PTR CPropertySheet::DoModal() { + return OnMain([&]() -> INT_PTR { + wxDialog dlg(OwnerWindow(m_pParentWnd), wxID_ANY, ToWx(m_strCaption), wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE); + dlg.SetFont(DialogFontFor(nullptr)); + auto* sizer = new wxBoxSizer(wxVERTICAL); + auto* book = new wxNotebook(&dlg, wxID_ANY); + sizer->Add(book, 1, wxEXPAND | wxALL, 8); + HookWindow(book, ControlKind::Generic, 0, WS_CHILD | WS_VISIBLE, 0); + for (CPropertyPage* page : m_pages) { + const rc::Dialog* tmpl = FindDialog(ResRef::FromId(page->m_nIDTemplate)); + if (!tmpl) + continue; + rc::Dialog child = *tmpl; + child.style = (child.style & ~WS_POPUP) | WS_CHILD; + wxWindow* w = CreateDialogWindow(page, child, book); + CString caption = page->m_strCaption.IsEmpty() ? CString(child.caption ? Utf8ToAnsi(child.caption).c_str() : "") + : page->m_strCaption; + book->AddPage(w, ToWx(caption)); + page->SendMessage(WM_INITDIALOG, 0, 0); + } + if (m_active >= 0 && m_active < static_cast(book->GetPageCount())) + book->SetSelection(static_cast(m_active)); + sizer->Add(dlg.CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 8); + dlg.SetSizerAndFit(sizer); + dlg.CentreOnParent(); + int r = dlg.ShowModal(); + for (CPropertyPage* page : m_pages) { + if (r == wxID_OK && page->m_hWnd) { + page->OnKillActive(); + page->OnApply(); + } + if (page->m_hWnd) + page->CWnd::DestroyWindow(); + } + return r == wxID_OK ? IDOK : IDCANCEL; + }); +} diff --git a/port/mfcwx/src/docview.cpp b/port/mfcwx/src/docview.cpp new file mode 100644 index 000000000..8f2477a8d --- /dev/null +++ b/port/mfcwx/src/docview.cpp @@ -0,0 +1,1829 @@ +#include "windows_impl.h" + +#include "afxdlgs.h" +#include "afxext.h" +#include "afxrich.h" + +#include +#include +#include + +namespace mfcwx { + +namespace { + +struct AFX_NOTIFY_LOCAL { + LRESULT* pResult; + NMHDR* pNMHDR; +}; + +CString ResourceString(UINT id) { + CString s; + s.LoadString(id); + return s; +} + +// Main window of an MDI application: menu, toolbar, status bar and a notebook of child frames. +class MfcFrame : public wxFrame { +public: + MfcFrame(wxWindow* parent, const wxString& title, const wxPoint& pos, const wxSize& size, long style) + : wxFrame(parent, wxID_ANY, title, pos, size, style) { + Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { + if (IsManagedWindow(this) && PermanentWnd(this)) { + e.Veto(); + DispatchMessageTo(ToHwnd(this), WM_CLOSE, 0, 0); + } else { + e.Skip(); + } + }); + Bind(wxEVT_MENU, [this](wxCommandEvent& e) { + int id = MenuWinId(e.GetId()); + if (id >= ID_FILE_MRU_FILE1 && id <= ID_FILE_MRU_FILE16 && e.GetId() >= wxID_FILE1 && e.GetId() <= wxID_FILE9) + id = ID_FILE_MRU_FILE1 + (e.GetId() - wxID_FILE1); + DispatchMessageTo(ToHwnd(this), WM_COMMAND, MAKEWPARAM(id, 0), 0); + }); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& e) { UpdateCommandUI(this, e); }); + Bind(wxEVT_MENU_HIGHLIGHT, [this](wxMenuEvent& e) { + CWnd* p = PermanentWnd(this); + if (p && p->IsKindOf(RUNTIME_CLASS(CFrameWnd)) && IsCommandWxId(e.GetMenuId())) { + CString text; + static_cast(p)->GetMessageString(static_cast(MenuWinId(e.GetMenuId())), text); + static_cast(p)->SetMessageText(text); + } else { + e.Skip(); + } + }); + Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) { + if (!PreTranslateKey(this, e, e.AltDown() ? WM_SYSKEYDOWN : WM_KEYDOWN)) + e.Skip(); + }); + } + + static void UpdateCommandUI(wxWindow* frame, wxUpdateUIEvent& e) { + CWnd* p = PermanentWnd(frame); + if (!p || !IsCommandWxId(e.GetId()) || !p->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { + if (e.GetId() == wxID_ABOUT || e.GetId() == wxID_EXIT) + e.Enable(true); + return; + } + auto* frameWnd = static_cast(p); + CCmdUI ui; + ui.m_nID = static_cast(MenuWinId(e.GetId())); + ui.m_pOther = nullptr; + ui.DoUpdate(frameWnd, frameWnd->m_bAutoMenuEnable); + e.Enable(ui.m_enabled); + if (ui.m_checkSet) + e.Check(ui.m_check != 0); + if (ui.m_textSet) + e.SetText(ToWx(ui.m_text)); + } +}; + +class MfcChildPanel : public wxPanel { +public: + explicit MfcChildPanel(wxWindow* parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE) {} +}; + +wxAuiNotebook* ClientNotebook(CMDIFrameWnd* frame) { + return frame && frame->m_hWndMDIClient ? wxDynamicCast(ToWx(frame->m_hWndMDIClient), wxAuiNotebook) : nullptr; +} + +CMDIFrameWnd* MainMDIFrame() { + CWinApp* app = AfxGetApp(); + CWnd* main = app ? app->m_pMainWnd : nullptr; + if (main && main->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) + return static_cast(main); + return nullptr; +} + +} // namespace + +wxWindow* MainWxWindow() { + CWinApp* app = AfxGetApp(); + return app && app->m_pMainWnd && app->m_pMainWnd->m_hWnd ? app->m_pMainWnd->GetWx() : nullptr; +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CPrintInfo + +CPrintInfo::CPrintInfo() + : m_pPD(nullptr), m_bDirect(FALSE), m_bPreview(FALSE), m_bContinuePrinting(TRUE), m_nCurPage(1), + m_nNumPreviewPages(1), m_lpUserData(nullptr), m_nMinPage(1), m_nMaxPage(0xFFFF) {} + +CPrintInfo::~CPrintInfo() {} + +// --------------------------------------------------------------------------------------------- +// CDocument + +IMPLEMENT_DYNAMIC(CDocument, CCmdTarget) + +BEGIN_MESSAGE_MAP(CDocument, CCmdTarget) + ON_COMMAND(ID_FILE_CLOSE, &CDocument::OnFileClose) + ON_COMMAND(ID_FILE_SAVE, &CDocument::OnFileSave) + ON_COMMAND(ID_FILE_SAVE_AS, &CDocument::OnFileSaveAs) +END_MESSAGE_MAP() + +CDocument::CDocument() : m_pDocTemplate(nullptr), m_bModified(FALSE), m_bAutoDelete(TRUE), m_bEmbedded(FALSE) {} + +CDocument::~CDocument() { + if (m_pDocTemplate) + m_pDocTemplate->RemoveDocument(this); +} + +void CDocument::SetTitle(const char* lpszTitle) { + m_strTitle = lpszTitle; + for (CView* v : m_viewList) { + CFrameWnd* frame = v->GetParentFrame(); + if (frame) + frame->OnUpdateFrameTitle(TRUE); + } +} + +void CDocument::SetPathName(const char* lpszPathName, BOOL bAddToMRU) { + m_strPathName = lpszPathName; + int start = 0; + for (int i = 0; i < m_strPathName.GetLength(); ++i) { + char c = m_strPathName[i]; + if (c == '\\' || c == '/' || c == ':') + start = i + 1; + } + SetTitle(m_strPathName.Mid(start)); + if (bAddToMRU && AfxGetApp()) + AfxGetApp()->AddToRecentFileList(lpszPathName); +} + +POSITION CDocument::GetFirstViewPosition() const { + return m_viewList.empty() ? nullptr : reinterpret_cast(static_cast(1)); +} + +CView* CDocument::GetNextView(POSITION& rPosition) const { + size_t i = static_cast(reinterpret_cast(rPosition)) - 1; + CView* v = i < m_viewList.size() ? m_viewList[i] : nullptr; + rPosition = i + 1 < m_viewList.size() ? reinterpret_cast(static_cast(i + 2)) : nullptr; + return v; +} + +void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint) { + std::vector views = m_viewList; + for (CView* v : views) + if (v != pSender) + v->OnUpdate(pSender, lHint, pHint); +} + +void CDocument::AddView(CView* pView) { + if (std::find(m_viewList.begin(), m_viewList.end(), pView) == m_viewList.end()) { + m_viewList.push_back(pView); + pView->m_pDocument = this; + OnChangedViewList(); + } +} + +void CDocument::RemoveView(CView* pView) { + auto it = std::find(m_viewList.begin(), m_viewList.end(), pView); + if (it == m_viewList.end()) + return; + m_viewList.erase(it); + pView->m_pDocument = nullptr; + OnChangedViewList(); +} + +void CDocument::OnChangedViewList() { + if (m_viewList.empty() && m_bAutoDelete) + OnCloseDocument(); +} + +void CDocument::SendInitialUpdate() { + std::vector views = m_viewList; + for (CView* v : views) + v->OnInitialUpdate(); +} + +BOOL CDocument::OnNewDocument() { + DeleteContents(); + m_strPathName.Empty(); + SetModifiedFlag(FALSE); + return TRUE; +} + +CFile* CDocument::GetFile(const char* lpszFileName, UINT nOpenFlags, CFileException* pError) { + auto* f = new CFile; + if (!f->Open(lpszFileName, nOpenFlags, pError)) { + delete f; + return nullptr; + } + return f; +} + +void CDocument::ReleaseFile(CFile* pFile, BOOL bAbort) { + if (bAbort) + pFile->Abort(); + else + pFile->Close(); + delete pFile; +} + +BOOL CDocument::OnOpenDocument(const char* lpszPathName) { + CFileException fe; + CFile* pFile = GetFile(lpszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe); + if (!pFile) { + ReportSaveLoadException(lpszPathName, &fe, FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); + return FALSE; + } + DeleteContents(); + SetModifiedFlag(TRUE); + try { + CArchive ar(pFile, CArchive::load | CArchive::bNoFlushOnDelete); + ar.m_pDocument = this; + ar.m_strFileName = lpszPathName; + Serialize(ar); + ar.Close(); + ReleaseFile(pFile, FALSE); + } catch (CException* e) { + ReleaseFile(pFile, TRUE); + DeleteContents(); + ReportSaveLoadException(lpszPathName, e, FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); + e->Delete(); + return FALSE; + } + SetModifiedFlag(FALSE); + return TRUE; +} + +BOOL CDocument::OnSaveDocument(const char* lpszPathName) { + CFileException fe; + CFile* pFile = GetFile(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive, &fe); + if (!pFile) { + ReportSaveLoadException(lpszPathName, &fe, TRUE, AFX_IDP_INVALID_FILENAME); + return FALSE; + } + try { + CArchive ar(pFile, CArchive::store | CArchive::bNoFlushOnDelete); + ar.m_pDocument = this; + ar.m_strFileName = lpszPathName; + Serialize(ar); + ar.Close(); + ReleaseFile(pFile, FALSE); + } catch (CException* e) { + ReleaseFile(pFile, TRUE); + ReportSaveLoadException(lpszPathName, e, TRUE, AFX_IDP_FAILED_TO_SAVE_DOC); + e->Delete(); + return FALSE; + } + SetModifiedFlag(FALSE); + return TRUE; +} + +void CDocument::ReportSaveLoadException(const char* lpszPathName, CException* e, BOOL bSaving, UINT nIDPDefault) { + char msg[512]; + if (e && e->GetErrorMessage(msg, sizeof msg)) { + AfxMessageBox(msg, MB_ICONEXCLAMATION); + return; + } + CString prompt; + AfxFormatString1(prompt, nIDPDefault, lpszPathName); + if (prompt.IsEmpty()) + prompt.Format(bSaving ? "Failed to save document %s." : "Failed to open document %s.", lpszPathName); + AfxMessageBox(prompt, MB_ICONEXCLAMATION); +} + +void CDocument::OnCloseDocument() { + BOOL autoDelete = m_bAutoDelete; + m_bAutoDelete = FALSE; + std::vector views = m_viewList; + for (CView* v : views) { + CFrameWnd* frame = v->GetParentFrame(); + if (frame) { + PreCloseFrame(frame); + frame->DestroyWindow(); + } + } + m_bAutoDelete = autoDelete; + DeleteContents(); + if (m_bAutoDelete) + delete this; +} + +BOOL CDocument::CanCloseFrame(CFrameWnd* pFrame) { + int views = 0; + for (CView* v : m_viewList) + if (v->GetParentFrame() == pFrame) + ++views; + if (static_cast(views) < m_viewList.size()) + return TRUE; + return SaveModified(); +} + +BOOL CDocument::SaveModified() { + if (!IsModified()) + return TRUE; + CString name = m_strPathName.IsEmpty() ? m_strTitle : m_strPathName; + CString prompt; + AfxFormatString1(prompt, AFX_IDP_ASK_TO_SAVE, name); + if (prompt.IsEmpty()) + prompt.Format("Save changes to %s?", name.GetString()); + switch (AfxMessageBox(prompt, MB_YESNOCANCEL | MB_ICONQUESTION)) { + case IDCANCEL: + return FALSE; + case IDYES: + return DoFileSave(); + default: + return TRUE; + } +} + +BOOL CDocument::DoFileSave() { + if (m_strPathName.IsEmpty() || access(NativePath(m_strPathName).c_str(), W_OK) != 0 && access(NativePath(m_strPathName).c_str(), F_OK) == 0) + return DoSave(nullptr); + return DoSave(m_strPathName); +} + +BOOL CDocument::DoSave(const char* lpszPathName, BOOL bReplace) { + CString newName = lpszPathName ? lpszPathName : ""; + if (newName.IsEmpty()) { + newName = m_strPathName.IsEmpty() ? m_strTitle : m_strPathName; + if (!AfxGetApp()->DoPromptFileName(newName, AFX_IDS_SAVEFILE, OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, + FALSE, m_pDocTemplate)) + return FALSE; + } + if (!OnSaveDocument(newName)) + return FALSE; + if (bReplace) + SetPathName(newName); + return TRUE; +} + +void CDocument::OnFileClose() { + if (!SaveModified()) + return; + OnCloseDocument(); +} + +void CDocument::OnFileSave() { DoFileSave(); } +void CDocument::OnFileSaveAs() { DoSave(nullptr); } + +BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { + if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) + return TRUE; + return m_pDocTemplate && m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +// --------------------------------------------------------------------------------------------- +// CView + +IMPLEMENT_DYNAMIC(CView, CWnd) + +BEGIN_MESSAGE_MAP(CView, CWnd) + ON_WM_PAINT() + ON_WM_CREATE() + ON_WM_DESTROY() + ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) + ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint) + ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview) +END_MESSAGE_MAP() + +CView::CView() : m_pDocument(nullptr) {} + +CView::~CView() { + if (m_pDocument) + m_pDocument->RemoveView(this); +} + +BOOL CView::PreCreateWindow(CREATESTRUCT& cs) { + cs.style |= WS_CLIPSIBLINGS; + return TRUE; +} + +int CView::OnCreate(LPCREATESTRUCT lpcs) { + auto* context = static_cast(lpcs->lpCreateParams); + if (context && context->m_pCurrentDoc) + context->m_pCurrentDoc->AddView(this); + return 0; +} + +void CView::OnDestroy() { + CFrameWnd* frame = GetParentFrame(); + if (frame && frame->GetActiveView() == this) + frame->SetActiveView(nullptr, FALSE); +} + +void CView::PostNcDestroy() { delete this; } + +void CView::OnPaint() { + CPaintDC dc(this); + OnPrepareDC(&dc); + OnDraw(&dc); +} + +BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { + if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) + return TRUE; + return m_pDocument && m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +void CView::OnInitialUpdate() { OnUpdate(nullptr, 0, nullptr); } +void CView::OnUpdate(CView*, LPARAM, CObject*) { Invalidate(TRUE); } +void CView::OnPrepareDC(CDC*, CPrintInfo*) {} +void CView::OnActivateView(BOOL bActivate, CView*, CView*) { + if (bActivate && m_hWnd) + SetFocus(); +} +BOOL CView::OnPreparePrinting(CPrintInfo* pInfo) { return DoPreparePrinting(pInfo); } +void CView::OnBeginPrinting(CDC*, CPrintInfo*) {} +void CView::OnPrint(CDC* pDC, CPrintInfo*) { OnDraw(pDC); } +void CView::OnEndPrinting(CDC*, CPrintInfo*) {} +BOOL CView::DoPreparePrinting(CPrintInfo*) { return FALSE; } + +void CView::OnFilePrint() { + AfxMessageBox("Printing is not supported in this version.", MB_ICONINFORMATION); +} + +void CView::OnFilePrintPreview() { OnFilePrint(); } + +IMPLEMENT_DYNAMIC(CScrollView, CView) + +const SIZE CScrollView::sizeDefault = {0, 0}; + +CScrollView::CScrollView() : m_nMapMode(MM_TEXT) {} + +void CScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage, const SIZE& sizeLine) { + m_nMapMode = nMapMode; + m_totalLog = sizeTotal; + m_totalDev = sizeTotal; + m_pageDev = sizePage; + m_lineDev = sizeLine; + if (!m_hWnd) + return; + SCROLLINFO si; + memset(&si, 0, sizeof si); + si.fMask = SIF_RANGE | SIF_PAGE; + CRect rc; + GetClientRect(&rc); + si.nMax = m_totalDev.cx - 1; + si.nPage = static_cast(rc.Width()); + SetScrollInfo(SB_HORZ, &si, TRUE); + si.nMax = m_totalDev.cy - 1; + si.nPage = static_cast(rc.Height()); + SetScrollInfo(SB_VERT, &si, TRUE); +} + +void CScrollView::SetScaleToFitSize(SIZE sizeTotal) { SetScrollSizes(MM_TEXT, sizeTotal); } +CPoint CScrollView::GetScrollPosition() const { return CPoint(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT)); } +CPoint CScrollView::GetDeviceScrollPosition() const { return GetScrollPosition(); } +void CScrollView::ScrollToPosition(POINT pt) { + SetScrollPos(SB_HORZ, pt.x); + SetScrollPos(SB_VERT, pt.y); + Invalidate(); +} +void CScrollView::FillOutsideRect(CDC*, CBrush*) {} +void CScrollView::ResizeParentToFit(BOOL) {} +void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { + CView::OnPrepareDC(pDC, pInfo); + CPoint pos = GetScrollPosition(); + pDC->SetViewportOrg(-pos.x, -pos.y); +} + +IMPLEMENT_DYNAMIC(CFormView, CScrollView) +CFormView::CFormView(UINT nIDTemplate) : m_nIDTemplate(nIDTemplate) {} +CFormView::CFormView(const char* lpszTemplateName) : m_nIDTemplate(static_cast(ResRef::From(lpszTemplateName).id)) {} +void CFormView::OnInitialUpdate() { + const rc::Dialog* tmpl = FindDialog(ResRef::FromId(m_nIDTemplate)); + if (tmpl && m_hWnd && GetWx()->GetChildren().empty()) { + EnsureState(GetWx()).baseUnits = DialogUnitsToPixels(nullptr, 0, 0, 4, 8).GetSize(); + CreateDialogControls(GetWx(), *tmpl); + ApplyDlgInit(this, tmpl->id); + } + UpdateData(FALSE); + CScrollView::OnInitialUpdate(); +} + +// --------------------------------------------------------------------------------------------- +// CFrameWnd + +IMPLEMENT_DYNCREATE(CFrameWnd, CWnd) + +BEGIN_MESSAGE_MAP(CFrameWnd, CWnd) + ON_WM_CREATE() + ON_WM_CLOSE() + ON_WM_DESTROY() + ON_WM_SIZE() + ON_WM_SETFOCUS() + ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, &CFrameWnd::OnUpdateControlBarMenu) + ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, &CFrameWnd::OnUpdateControlBarMenu) + ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, &CFrameWnd::OnUpdateKeyIndicator) + ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, &CFrameWnd::OnUpdateKeyIndicator) + ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, &CFrameWnd::OnUpdateKeyIndicator) + ON_COMMAND_EX(ID_VIEW_STATUS_BAR, &CFrameWnd::OnBarCheck) + ON_COMMAND_EX(ID_VIEW_TOOLBAR, &CFrameWnd::OnBarCheck) + ON_COMMAND(ID_HELP, &CFrameWnd::OnHelp) + ON_COMMAND(ID_CONTEXT_HELP, &CFrameWnd::OnContextHelp) +END_MESSAGE_MAP() + +const CRect CFrameWnd::rectDefault(CW_USEDEFAULT, CW_USEDEFAULT, 0, 0); + +CFrameWnd::CFrameWnd() + : m_nIDHelp(0), m_hMenuDefault(nullptr), m_hAccelTable(nullptr), m_bAutoMenuEnable(TRUE), m_nIdleFlags(0), + m_pViewActive(nullptr), m_pStatusBar(nullptr) {} + +CFrameWnd::~CFrameWnd() {} + +BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT&) { return TRUE; } + +void CFrameWnd::PostNcDestroy() { delete this; } + +BOOL CFrameWnd::Create(const char*, const char* lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, + const char* lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) { + return OnMain([&]() -> BOOL { + CREATESTRUCT cs; + memset(&cs, 0, sizeof cs); + cs.style = static_cast(dwStyle); + cs.dwExStyle = dwExStyle; + cs.lpszName = lpszWindowName; + cs.x = rect.left; + cs.y = rect.top; + cs.cx = rect.right - rect.left; + cs.cy = rect.bottom - rect.top; + cs.lpCreateParams = pContext; + if (!PreCreateWindow(cs)) + return FALSE; + long style = wxDEFAULT_FRAME_STYLE; + wxPoint pos = cs.x == CW_USEDEFAULT ? wxDefaultPosition : wxPoint(cs.x, cs.y); + wxSize size = cs.cx <= 0 ? wxSize(1000, 720) : wxSize(cs.cx, cs.cy); + auto* frame = new MfcFrame(pParentWnd && pParentWnd->m_hWnd ? pParentWnd->GetWx() : nullptr, + ToWx(lpszWindowName ? lpszWindowName : ""), pos, size, style); + HookWindow(frame, ControlKind::Frame, 0, static_cast(cs.style), dwExStyle); + EnsureState(frame).text = ToWx(lpszWindowName ? lpszWindowName : ""); + AttachWx(frame); + if (lpszMenuName) { + const rc::Menu* menu = FindMenu(ResRef::From(lpszMenuName)); + if (menu) { + wxMenuBar* bar = BuildMenuBar(*menu); + frame->SetMenuBar(bar); + m_hMenuDefault = HandleFromWxMenuBar(bar); + } + } + if (SendMessage(WM_CREATE, 0, reinterpret_cast(&cs)) == -1) { + DestroyWindow(); + return FALSE; + } + return m_hWnd != nullptr; + }); +} + +BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) { + CString title = ResourceString(nIDResource); + int nl = title.Find('\n'); + if (nl >= 0) + title = title.Left(nl); + m_strTitle = title; + const rc::AccelTable* accel = FindAccelTable(ResRef::FromId(nIDResource)); + SetMenuAccelerators(accel); + BOOL ok = Create(nullptr, title, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0, pContext); + SetMenuAccelerators(nullptr); + if (!ok) + return FALSE; + m_nIDHelp = nIDResource; + m_hAccelTable = reinterpret_cast(const_cast(accel)); + OnMain([&] { + wxIcon icon = LoadIconResource(ResRef::FromId(nIDResource)); + if (icon.IsOk()) + static_cast(GetWx())->SetIcon(icon); + if (accel) { + std::vector entries; + wxMenuBar* bar = static_cast(GetWx())->GetMenuBar(); + for (int i = 0; i < accel->itemCount; ++i) { + const rc::Accel& a = accel->items[i]; + if (bar && bar->FindItem(MenuWxId(a.id))) + continue; + int flags = (a.flags & FCONTROL ? wxACCEL_CTRL : 0) | (a.flags & FALT ? wxACCEL_ALT : 0) | + (a.flags & FSHIFT ? wxACCEL_SHIFT : 0); + int key = a.flags & FVIRTKEY ? WxKeyFromVirtual(static_cast(a.key)) : a.key; + if (!(a.flags & FVIRTKEY) && a.key > 0 && a.key < 32) { + flags |= wxACCEL_CTRL; + key = 'A' + a.key - 1; + } + if (key) + entries.emplace_back(flags, key, MenuWxId(a.id)); + } + if (!entries.empty()) + GetWx()->SetAcceleratorTable(wxAcceleratorTable(static_cast(entries.size()), entries.data())); + } + }); + OnUpdateFrameTitle(TRUE); + return TRUE; +} + +int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs) { + auto* context = static_cast(lpcs->lpCreateParams); + return OnCreateClient(lpcs, context) ? 0 : -1; +} + +BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) { + if (pContext && pContext->m_pNewViewClass) + return CreateView(pContext, AFX_IDW_PANE_FIRST) != nullptr; + return TRUE; +} + +CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID) { + CObject* obj = pContext->m_pNewViewClass->CreateObject(); + auto* view = dynamic_cast(obj); + if (!view) { + delete obj; + return nullptr; + } + CRect rc; + GetClientRect(&rc); + if (!view->Create(nullptr, nullptr, WS_CHILD | WS_VISIBLE | WS_BORDER, rc, this, nID, pContext)) + return nullptr; + RecalcLayout(); + return view; +} + +void CFrameWnd::OnClose() { + CWinApp* app = AfxGetApp(); + if (app && app->m_pMainWnd == this) { + if (!app->SaveAllModified()) + return; + app->CloseAllDocuments(FALSE); + DestroyWindow(); + return; + } + CDocument* doc = GetActiveDocument(); + if (doc && !doc->CanCloseFrame(this)) + return; + if (doc && doc->m_viewList.size() == 1) { + doc->OnCloseDocument(); + return; + } + DestroyWindow(); +} + +void CFrameWnd::OnDestroy() { + CWinApp* app = AfxGetApp(); + if (app && app->m_pMainWnd == this) { + app->m_pMainWnd = nullptr; + PostToMainThread([] { + if (wxTheApp) + wxTheApp->ExitMainLoop(); + }); + } +} + +void CFrameWnd::OnSize(UINT, int, int) { RecalcLayout(); } + +void CFrameWnd::OnSetFocus(CWnd*) { + if (m_pViewActive && m_pViewActive->m_hWnd) + m_pViewActive->SetFocus(); +} + +void CFrameWnd::RecalcLayout(BOOL) { + OnMain([&] { + if (!m_hWnd) + return; + wxWindow* frame = GetWx(); + wxSize client = frame->GetClientSize(); + for (wxWindow* c : frame->GetChildren()) { + WindowState* st = GetState(c); + if (st && st->winId == AFX_IDW_PANE_FIRST) + c->SetSize(0, 0, client.x, client.y); + } + }); +} + +BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { + CView* view = GetActiveView(); + if (view && view->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) + return TRUE; + if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) + return TRUE; + CWinApp* app = AfxGetApp(); + return app && app->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam) { return CWnd::OnCommand(wParam, lParam); } + +BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg) { return CWnd::PreTranslateMessage(pMsg); } + +CFrameWnd* CFrameWnd::GetActiveFrame() { return this; } + +CView* CFrameWnd::GetActiveView() const { + if (m_pViewActive) + return m_pViewActive; + if (!m_hWnd) + return nullptr; + for (wxWindow* c : GetWx()->GetChildren()) { + CWnd* p = PermanentWnd(c); + if (p && p->IsKindOf(RUNTIME_CLASS(CView))) + return static_cast(p); + } + return nullptr; +} + +void CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify) { + CView* old = m_pViewActive; + if (old == pViewNew) + return; + m_pViewActive = pViewNew; + if (bNotify) { + if (old) + old->OnActivateView(FALSE, pViewNew, old); + if (pViewNew) + pViewNew->OnActivateView(TRUE, pViewNew, old); + } +} + +CDocument* CFrameWnd::GetActiveDocument() { + CView* v = GetActiveView(); + return v ? v->GetDocument() : nullptr; +} + +void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible) { + CView* view = GetActiveView(); + if (m_hWnd) + SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); + std::vector views; + if (pDoc) + views = pDoc->m_viewList; + else if (view) + views.push_back(view); + for (CView* v : views) + if (v->GetParentFrame() == this) + v->OnInitialUpdate(); + if (view) + SetActiveView(view, TRUE); + if (bMakeVisible) + ActivateFrame(); + OnUpdateFrameTitle(TRUE); +} + +void CFrameWnd::ActivateFrame(int nCmdShow) { + ShowWindow(nCmdShow == -1 ? SW_SHOW : nCmdShow); + BringWindowToTop(); +} + +void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle) { + CDocument* doc = GetActiveDocument(); + if (bAddToTitle && doc) + UpdateFrameTitleForDocument(doc->GetTitle()); + else + UpdateFrameTitleForDocument(nullptr); +} + +void CFrameWnd::UpdateFrameTitleForDocument(const char* lpszDocName) { + CString title = m_strTitle; + if (lpszDocName && *lpszDocName) + title = title.IsEmpty() ? CString(lpszDocName) : title + " - " + lpszDocName; + SetWindowText(title); +} + +void CFrameWnd::OnUpdateFrameMenu(HMENU) {} + +void CFrameWnd::GetMessageString(UINT nID, CString& rMessage) const { + rMessage.LoadString(nID); + int nl = rMessage.Find('\n'); + if (nl >= 0) + rMessage = rMessage.Left(nl); +} + +void CFrameWnd::SetMessageText(const char* lpszText) { + OnMain([&] { + auto* frame = wxDynamicCast(GetTopLevelFrame() && GetTopLevelFrame()->m_hWnd ? GetTopLevelFrame()->GetWx() : nullptr, wxFrame); + if (frame && frame->GetStatusBar()) + frame->GetStatusBar()->SetStatusText(ToWx(lpszText ? lpszText : ""), 0); + }); +} + +void CFrameWnd::SetMessageText(UINT nID) { + CString s; + GetMessageString(nID, s); + SetMessageText(s); +} + +void CFrameWnd::EnableDocking(DWORD) {} +void CFrameWnd::DockControlBar(CControlBar*, UINT, LPCRECT) {} + +void CFrameWnd::ShowControlBar(CControlBar* pBar, BOOL bShow, BOOL) { + if (pBar && pBar->m_hWnd) { + pBar->ShowWindow(bShow ? SW_SHOW : SW_HIDE); + OnMain([&] { + if (m_hWnd) + GetWx()->SendSizeEvent(); + }); + } +} + +CControlBar* CFrameWnd::GetControlBar(UINT nID) { + for (CControlBar* b : m_listControlBars) + if (static_cast(b->GetDlgCtrlID()) == nID) + return b; + return nullptr; +} + +void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI) { + CControlBar* bar = GetControlBar(pCmdUI->m_nID); + if (!bar) { + pCmdUI->ContinueRouting(); + return; + } + pCmdUI->SetCheck(bar->IsWindowVisible()); +} + +void CFrameWnd::OnUpdateKeyIndicator(CCmdUI* pCmdUI) { + int vk = 0; + switch (pCmdUI->m_nID) { + case ID_INDICATOR_CAPS: vk = VK_CAPITAL; break; + case ID_INDICATOR_NUM: vk = VK_NUMLOCK; break; + case ID_INDICATOR_SCRL: vk = VK_SCROLL; break; + } + pCmdUI->Enable(vk && (::GetKeyState(vk) & 1)); +} + +BOOL CFrameWnd::OnBarCheck(UINT nID) { + CControlBar* bar = GetControlBar(nID); + if (!bar) + return FALSE; + ShowControlBar(bar, !bar->IsWindowVisible(), FALSE); + return TRUE; +} + +void CFrameWnd::OnHelp() { + CWinApp* app = AfxGetApp(); + if (app) + app->WinHelpInternal(0, HELP_FINDER); +} + +void CFrameWnd::OnContextHelp() { OnHelp(); } + +// --------------------------------------------------------------------------------------------- +// MDI + +IMPLEMENT_DYNAMIC(CMDIFrameWnd, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMDIFrameWnd, CFrameWnd) + ON_COMMAND(ID_WINDOW_NEW, &CMDIFrameWnd::OnWindowNew) + ON_COMMAND(ID_WINDOW_CASCADE, &CMDIFrameWnd::OnWindowCascade) + ON_COMMAND(ID_WINDOW_TILE_HORZ, &CMDIFrameWnd::OnWindowTile) + ON_COMMAND(ID_WINDOW_TILE_VERT, &CMDIFrameWnd::OnWindowTile) + ON_COMMAND(ID_WINDOW_ARRANGE, &CMDIFrameWnd::OnWindowCascade) + ON_UPDATE_COMMAND_UI(ID_WINDOW_CASCADE, &CMDIFrameWnd::OnUpdateMDIWindowCmd) + ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_HORZ, &CMDIFrameWnd::OnUpdateMDIWindowCmd) + ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_VERT, &CMDIFrameWnd::OnUpdateMDIWindowCmd) + ON_UPDATE_COMMAND_UI(ID_WINDOW_ARRANGE, &CMDIFrameWnd::OnUpdateMDIWindowCmd) + ON_UPDATE_COMMAND_UI(ID_WINDOW_NEW, &CMDIFrameWnd::OnUpdateMDIWindowCmd) +END_MESSAGE_MAP() + +CMDIFrameWnd::CMDIFrameWnd() : m_hWndMDIClient(nullptr) {} + +BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) { + if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext)) + return FALSE; + return TRUE; +} + +BOOL CMDIFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext*) { + return OnMain([&]() -> BOOL { + wxWindow* frame = GetWx(); + auto* book = new wxAuiNotebook(frame, ToWxId(AFX_IDW_PANE_FIRST), wxDefaultPosition, frame->GetClientSize(), + wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_CLOSE_ON_ALL_TABS | wxAUI_NB_WINDOWLIST_BUTTON); + HookWindow(book, ControlKind::Generic, AFX_IDW_PANE_FIRST, WS_CHILD | WS_VISIBLE, 0); + m_hWndMDIClient = ToHwnd(book); + auto* sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add(book, 1, wxEXPAND); + frame->SetSizer(sizer); + book->Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED, [this](wxAuiNotebookEvent& e) { + e.Skip(); + OnChildActivated(); + }); + book->Bind(wxEVT_AUINOTEBOOK_PAGE_CLOSE, [book](wxAuiNotebookEvent& e) { + e.Veto(); + wxWindow* page = book->GetPage(static_cast(e.GetSelection())); + if (page && IsManagedWindow(page)) + DispatchMessageTo(ToHwnd(page), WM_CLOSE, 0, 0); + }); + return TRUE; + }); +} + +void CMDIFrameWnd::OnChildActivated() { + CMDIChildWnd* active = MDIGetActive(); + for (CMDIChildWnd* child : m_children) { + bool now = child == active; + if (child->m_bActive != now) { + child->m_bActive = now; + CView* view = child->GetActiveView(); + if (view) + view->OnActivateView(now, now ? view : nullptr, now ? nullptr : view); + child->SendMessage(WM_MDIACTIVATE, reinterpret_cast(now ? nullptr : child->m_hWnd), + reinterpret_cast(now ? child->m_hWnd : nullptr)); + } + } + OnUpdateFrameMenu(active ? active->m_hMenuShared : nullptr); + OnUpdateFrameTitle(TRUE); +} + +BOOL CMDIFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { + CMDIChildWnd* child = MDIGetActive(); + if (child && child->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) + return TRUE; + return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +CFrameWnd* CMDIFrameWnd::GetActiveFrame() { + CMDIChildWnd* child = MDIGetActive(); + return child ? static_cast(child) : this; +} + +void CMDIFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle) { + CMDIChildWnd* child = MDIGetActive(); + CDocument* doc = child ? child->GetActiveDocument() : nullptr; + UpdateFrameTitleForDocument(bAddToTitle && doc ? doc->GetTitle().GetString() : nullptr); +} + +void CMDIFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt) { + OnMain([&] { + auto* frame = wxDynamicCast(GetWx(), wxFrame); + if (!frame) + return; + wxMenuBar* bar = WxMenuBarFromHandle(hMenuAlt ? hMenuAlt : m_hMenuDefault); + if (bar && frame->GetMenuBar() != bar) + frame->SetMenuBar(bar); + }); +} + +void CMDIFrameWnd::RecalcLayout(BOOL) { + OnMain([&] { + if (m_hWnd) + GetWx()->Layout(); + }); +} + +void CMDIFrameWnd::MDIActivate(CWnd* pWndActivate) { + if (!pWndActivate || !pWndActivate->m_hWnd) + return; + OnMain([&] { + wxAuiNotebook* book = ClientNotebook(this); + if (!book) + return; + int index = book->GetPageIndex(pWndActivate->GetWx()); + if (index != wxNOT_FOUND && book->GetSelection() != index) + book->SetSelection(static_cast(index)); + else + OnChildActivated(); + }); +} + +CMDIChildWnd* CMDIFrameWnd::MDIGetActive(BOOL* pbMaximized) const { + if (pbMaximized) + *pbMaximized = TRUE; + return OnMain([&]() -> CMDIChildWnd* { + wxAuiNotebook* book = ClientNotebook(const_cast(this)); + if (!book || book->GetSelection() == wxNOT_FOUND) + return nullptr; + CWnd* p = PermanentWnd(book->GetPage(static_cast(book->GetSelection()))); + return p && p->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)) ? static_cast(p) : nullptr; + }); +} + +void CMDIFrameWnd::MDIMaximize(CWnd* pWnd) { MDIActivate(pWnd); } +void CMDIFrameWnd::MDIRestore(CWnd* pWnd) { MDIActivate(pWnd); } + +void CMDIFrameWnd::MDINext() { + OnMain([&] { + if (wxAuiNotebook* book = ClientNotebook(this)) + book->AdvanceSelection(true); + }); +} + +void CMDIFrameWnd::MDIPrev() { + OnMain([&] { + if (wxAuiNotebook* book = ClientNotebook(this)) + book->AdvanceSelection(false); + }); +} + +CMenu* CMDIFrameWnd::MDISetMenu(CMenu* pFrameMenu, CMenu*) { + if (pFrameMenu) + OnUpdateFrameMenu(pFrameMenu->m_hMenu); + return nullptr; +} + +void CMDIFrameWnd::MDITile() {} +void CMDIFrameWnd::MDICascade() {} + +CMDIChildWnd* CMDIFrameWnd::CreateNewChild(CRuntimeClass* pClass, UINT nResource, HMENU hMenu, HACCEL hAccel) { + auto* child = static_cast(pClass->CreateObject()); + if (!child->LoadFrame(nResource, WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, this, nullptr)) + return nullptr; + child->SetHandles(hMenu, hAccel); + child->InitialUpdateFrame(nullptr, TRUE); + return child; +} + +void CMDIFrameWnd::OnWindowNew() {} +void CMDIFrameWnd::OnWindowCascade() {} +void CMDIFrameWnd::OnWindowTile() {} +void CMDIFrameWnd::OnUpdateMDIWindowCmd(CCmdUI* pCmdUI) { pCmdUI->Enable(MDIGetActive() != nullptr); } + +IMPLEMENT_DYNCREATE(CMDIChildWnd, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMDIChildWnd, CFrameWnd) +END_MESSAGE_MAP() + +CMDIChildWnd::CMDIChildWnd() : m_hMenuShared(nullptr), m_pMDIFrame(nullptr), m_bActive(false) {} + +CMDIChildWnd::~CMDIChildWnd() { + if (m_pMDIFrame) { + auto& kids = m_pMDIFrame->m_children; + kids.erase(std::remove(kids.begin(), kids.end(), this), kids.end()); + } +} + +BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT&) { return TRUE; } + +BOOL CMDIChildWnd::Create(const char*, const char* lpszWindowName, DWORD dwStyle, const RECT&, CMDIFrameWnd* pParentWnd, + CCreateContext* pContext) { + CMDIFrameWnd* mdi = pParentWnd ? pParentWnd : MainMDIFrame(); + if (!mdi) + return FALSE; + return OnMain([&]() -> BOOL { + wxAuiNotebook* book = ClientNotebook(mdi); + if (!book) + return FALSE; + CREATESTRUCT cs; + memset(&cs, 0, sizeof cs); + cs.style = static_cast(dwStyle); + cs.lpszName = lpszWindowName; + cs.lpCreateParams = pContext; + if (!PreCreateWindow(cs)) + return FALSE; + auto* panel = new MfcChildPanel(book); + HookWindow(panel, ControlKind::MDIChild, 0, static_cast(cs.style), 0); + EnsureState(panel).text = ToWx(lpszWindowName ? lpszWindowName : ""); + EnsureState(panel).owner = mdi->m_hWnd; + AttachWx(panel); + m_pMDIFrame = mdi; + mdi->m_children.push_back(this); + panel->Bind(wxEVT_CLOSE_WINDOW, [panel](wxCloseEvent& e) { + if (IsManagedWindow(panel) && PermanentWnd(panel)) { + e.Veto(); + DispatchMessageTo(ToHwnd(panel), WM_CLOSE, 0, 0); + } else { + e.Skip(); + } + }); + if (SendMessage(WM_CREATE, 0, reinterpret_cast(&cs)) == -1) { + DestroyWindow(); + return FALSE; + } + book->AddPage(panel, ToWx(lpszWindowName ? lpszWindowName : ""), false); + return m_hWnd != nullptr; + }); +} + +BOOL CMDIChildWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) { + m_nIDHelp = nIDResource; + CString title = ResourceString(nIDResource); + int nl = title.Find('\n'); + if (nl >= 0) + title = title.Left(nl); + CMDIFrameWnd* mdi = pParentWnd && pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)) ? static_cast(pParentWnd) + : MainMDIFrame(); + return Create(nullptr, title, dwDefaultStyle, rectDefault, mdi, pContext); +} + +BOOL CMDIChildWnd::DestroyWindow() { + CMDIFrameWnd* mdi = m_pMDIFrame; + if (mdi) { + auto& kids = mdi->m_children; + kids.erase(std::remove(kids.begin(), kids.end(), this), kids.end()); + m_pMDIFrame = nullptr; + } + if (!m_hWnd) + return FALSE; + return OnMain([&]() -> BOOL { + wxWindow* panel = GetWx(); + wxAuiNotebook* book = ClientNotebook(mdi); + WindowState* st = GetState(panel); + if (st && !st->destroyNotified) { + st->destroyNotified = true; + SendMessage(WM_DESTROY); + } + if (book) { + int index = book->GetPageIndex(panel); + if (index != wxNOT_FOUND) + book->RemovePage(static_cast(index)); + } + DestroyWxWindow(panel); + if (mdi) + PostToMainThread([mdi] { + if (mdi->m_hWnd) + mdi->OnChildActivated(); + }); + return TRUE; + }); +} + +void CMDIChildWnd::ActivateFrame(int nCmdShow) { + if (nCmdShow == SW_HIDE) { + ShowWindow(SW_HIDE); + return; + } + CMDIFrameWnd* mdi = GetMDIFrame(); + if (mdi) + mdi->MDIActivate(this); +} + +void CMDIChildWnd::OnUpdateFrameMenu(BOOL bActive, CWnd*, HMENU hMenuAlt) { + CMDIFrameWnd* mdi = GetMDIFrame(); + if (mdi) + mdi->OnUpdateFrameMenu(bActive ? (hMenuAlt ? hMenuAlt : m_hMenuShared) : nullptr); +} + +void CMDIChildWnd::OnUpdateFrameTitle(BOOL bAddToTitle) { + CDocument* doc = GetActiveDocument(); + CString title = doc && bAddToTitle ? doc->GetTitle() : m_strTitle; + OnMain([&] { + if (!m_hWnd) + return; + EnsureState(GetWx()).text = ToWx(title); + if (wxAuiNotebook* book = ClientNotebook(GetMDIFrame())) { + int index = book->GetPageIndex(GetWx()); + if (index != wxNOT_FOUND) + book->SetPageText(static_cast(index), ToWx(title)); + } + }); + if (CMDIFrameWnd* mdi = GetMDIFrame()) + if (mdi->MDIGetActive() == this) + mdi->OnUpdateFrameTitle(TRUE); +} + +CMDIFrameWnd* CMDIChildWnd::GetMDIFrame() const { return m_pMDIFrame ? m_pMDIFrame : MainMDIFrame(); } +void CMDIChildWnd::MDIDestroy() { DestroyWindow(); } +void CMDIChildWnd::MDIActivate() { ActivateFrame(); } +void CMDIChildWnd::MDIMaximize() { ActivateFrame(); } +void CMDIChildWnd::MDIRestore() { ActivateFrame(); } +BOOL CMDIChildWnd::PreTranslateMessage(MSG* pMsg) { return CFrameWnd::PreTranslateMessage(pMsg); } + +// --------------------------------------------------------------------------------------------- +// Document templates + +IMPLEMENT_DYNAMIC(CDocTemplate, CCmdTarget) +IMPLEMENT_DYNAMIC(CMultiDocTemplate, CDocTemplate) +IMPLEMENT_DYNAMIC(CSingleDocTemplate, CDocTemplate) + +CDocTemplate::CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass) + : m_nIDResource(nIDResource), m_pDocClass(pDocClass), m_pFrameClass(pFrameClass), m_pViewClass(pViewClass), + m_bAutoDelete(TRUE) { + LoadTemplate(); +} + +CDocTemplate::~CDocTemplate() {} + +void CDocTemplate::LoadTemplate() { + if (m_strDocStrings.IsEmpty()) + m_strDocStrings.LoadString(m_nIDResource); +} + +void CDocTemplate::AddDocument(CDocument* pDoc) { pDoc->m_pDocTemplate = this; } + +void CDocTemplate::RemoveDocument(CDocument* pDoc) { + if (pDoc->m_pDocTemplate == this) + pDoc->m_pDocTemplate = nullptr; +} + +BOOL CDocTemplate::GetDocString(CString& rString, enum DocStringIndex index) const { + return AfxExtractSubString(rString, m_strDocStrings, static_cast(index), '\n'); +} + +CDocument* CDocTemplate::CreateNewDocument() { + if (!m_pDocClass) + return nullptr; + auto* doc = dynamic_cast(m_pDocClass->CreateObject()); + if (doc) + AddDocument(doc); + return doc; +} + +CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther) { + CCreateContext context; + context.m_pCurrentFrame = pOther; + context.m_pCurrentDoc = pDoc; + context.m_pNewViewClass = m_pViewClass; + context.m_pNewDocTemplate = this; + if (!m_pFrameClass) + return nullptr; + auto* frame = dynamic_cast(m_pFrameClass->CreateObject()); + if (!frame) + return nullptr; + if (!frame->LoadFrame(m_nIDResource, WS_OVERLAPPEDWINDOW, nullptr, &context)) + return nullptr; + return frame; +} + +void CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc, BOOL bMakeVisible) { + pFrame->InitialUpdateFrame(pDoc, bMakeVisible); +} + +BOOL CDocTemplate::SaveAllModified() { + POSITION pos = GetFirstDocPosition(); + while (pos) { + CDocument* doc = GetNextDoc(pos); + if (doc && !doc->SaveModified()) + return FALSE; + } + return TRUE; +} + +void CDocTemplate::CloseAllDocuments(BOOL) { + for (;;) { + POSITION pos = GetFirstDocPosition(); + if (!pos) + break; + CDocument* doc = GetNextDoc(pos); + if (!doc) + break; + doc->OnCloseDocument(); + } +} + +CDocTemplate::Confidence CDocTemplate::MatchDocType(const char* lpszPathName, CDocument*& rpDocMatch) { + rpDocMatch = nullptr; + POSITION pos = GetFirstDocPosition(); + while (pos) { + CDocument* doc = GetNextDoc(pos); + if (doc && doc->GetPathName().CompareNoCase(lpszPathName) == 0) { + rpDocMatch = doc; + return yesAlreadyOpen; + } + } + CString ext; + if (GetDocString(ext, filterExt) && !ext.IsEmpty()) { + CString path(lpszPathName); + if (path.GetLength() >= ext.GetLength() && path.Right(ext.GetLength()).CompareNoCase(ext) == 0) + return yesAttemptNative; + } + return yesAttemptForeign; +} + +CMultiDocTemplate::CMultiDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, + CRuntimeClass* pViewClass) + : CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass), m_hMenuShared(nullptr), m_hAccelTable(nullptr), + m_nUntitledCount(0) { + LoadTemplate(); +} + +CMultiDocTemplate::~CMultiDocTemplate() {} + +void CMultiDocTemplate::LoadTemplate() { + CDocTemplate::LoadTemplate(); + if (m_hMenuShared) + return; + const rc::Menu* menu = FindMenu(ResRef::FromId(m_nIDResource)); + if (menu && wxTheApp) { + SetMenuAccelerators(FindAccelTable(ResRef::FromId(m_nIDResource))); + if (!FindAccelTable(ResRef::FromId(m_nIDResource))) + SetMenuAccelerators(FindAccelTable(ResRef::FromId(128))); + m_hMenuShared = HandleFromWxMenuBar(BuildMenuBar(*menu)); + SetMenuAccelerators(nullptr); + } +} + +POSITION CMultiDocTemplate::GetFirstDocPosition() const { + return m_docList.empty() ? nullptr : reinterpret_cast(static_cast(1)); +} + +CDocument* CMultiDocTemplate::GetNextDoc(POSITION& rPos) const { + size_t i = static_cast(reinterpret_cast(rPos)) - 1; + CDocument* d = i < m_docList.size() ? m_docList[i] : nullptr; + rPos = i + 1 < m_docList.size() ? reinterpret_cast(static_cast(i + 2)) : nullptr; + return d; +} + +void CMultiDocTemplate::AddDocument(CDocument* pDoc) { + CDocTemplate::AddDocument(pDoc); + m_docList.push_back(pDoc); +} + +void CMultiDocTemplate::RemoveDocument(CDocument* pDoc) { + CDocTemplate::RemoveDocument(pDoc); + m_docList.erase(std::remove(m_docList.begin(), m_docList.end(), pDoc), m_docList.end()); +} + +CDocument* CMultiDocTemplate::OpenDocumentFile(const char* lpszPathName, BOOL bMakeVisible) { + LoadTemplate(); + CDocument* doc = CreateNewDocument(); + if (!doc) + return nullptr; + BOOL autoDelete = doc->m_bAutoDelete; + doc->m_bAutoDelete = FALSE; + CFrameWnd* frame = CreateNewFrame(doc, nullptr); + doc->m_bAutoDelete = autoDelete; + if (!frame) { + delete doc; + return nullptr; + } + if (frame->IsKindOf(RUNTIME_CLASS(CMDIChildWnd))) + static_cast(frame)->SetHandles(m_hMenuShared, m_hAccelTable); + if (!lpszPathName) { + SetDefaultTitle(doc); + if (!doc->OnNewDocument()) { + frame->DestroyWindow(); + return nullptr; + } + ++m_nUntitledCount; + } else { + CWaitCursor wait; + if (!doc->OnOpenDocument(lpszPathName)) { + frame->DestroyWindow(); + return nullptr; + } + doc->SetPathName(lpszPathName); + } + InitialUpdateFrame(frame, doc, bMakeVisible); + return doc; +} + +void CMultiDocTemplate::SetDefaultTitle(CDocument* pDocument) { + CString name; + if (!GetDocString(name, docName) || name.IsEmpty()) + name = "Untitled"; + CString title; + title.Format("%s%u", name.GetString(), m_nUntitledCount + 1); + pDocument->SetTitle(title); +} + +CSingleDocTemplate::CSingleDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, + CRuntimeClass* pViewClass) + : CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass), m_pOnlyDoc(nullptr) {} + +POSITION CSingleDocTemplate::GetFirstDocPosition() const { + return m_pOnlyDoc ? reinterpret_cast(static_cast(1)) : nullptr; +} + +CDocument* CSingleDocTemplate::GetNextDoc(POSITION& rPos) const { + CDocument* d = rPos ? m_pOnlyDoc : nullptr; + rPos = nullptr; + return d; +} + +void CSingleDocTemplate::AddDocument(CDocument* pDoc) { + CDocTemplate::AddDocument(pDoc); + m_pOnlyDoc = pDoc; +} + +void CSingleDocTemplate::RemoveDocument(CDocument* pDoc) { + CDocTemplate::RemoveDocument(pDoc); + if (m_pOnlyDoc == pDoc) + m_pOnlyDoc = nullptr; +} + +CDocument* CSingleDocTemplate::OpenDocumentFile(const char* lpszPathName, BOOL bMakeVisible) { + if (m_pOnlyDoc) { + if (!m_pOnlyDoc->SaveModified()) + return nullptr; + m_pOnlyDoc->OnCloseDocument(); + } + CDocument* doc = CreateNewDocument(); + if (!doc) + return nullptr; + CFrameWnd* frame = CreateNewFrame(doc, nullptr); + if (!frame) + return nullptr; + if (!lpszPathName) { + SetDefaultTitle(doc); + doc->OnNewDocument(); + } else if (!doc->OnOpenDocument(lpszPathName)) { + frame->DestroyWindow(); + return nullptr; + } else { + doc->SetPathName(lpszPathName); + } + InitialUpdateFrame(frame, doc, bMakeVisible); + return doc; +} + +void CSingleDocTemplate::SetDefaultTitle(CDocument* pDocument) { pDocument->SetTitle("Untitled"); } + +// --------------------------------------------------------------------------------------------- +// Control bars + +IMPLEMENT_DYNAMIC(CControlBar, CWnd) +IMPLEMENT_DYNAMIC(CToolBar, CControlBar) +IMPLEMENT_DYNAMIC(CStatusBar, CControlBar) + +CControlBar::CControlBar() : m_dwStyle(0), m_dwDockStyle(0) {} +CSize CControlBar::CalcFixedLayout(BOOL, BOOL) { return CSize(0, 0); } +void CControlBar::OnUpdateCmdUI(CFrameWnd*, BOOL) {} + +CToolBar::CToolBar() : m_nResourceID(0) {} + +BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID) { + if (!pParentWnd || !pParentWnd->m_hWnd) + return FALSE; + m_dwStyle = dwStyle; + return OnMain([&]() -> BOOL { + auto* frame = wxDynamicCast(pParentWnd->GetWx(), wxFrame); + if (!frame) + return FALSE; + wxToolBar* tb = frame->CreateToolBar(wxTB_HORIZONTAL | wxTB_FLAT | wxTB_NODIVIDER, ToWxId(static_cast(nID))); + HookWindow(tb, ControlKind::ToolBar, static_cast(nID), dwStyle, 0); + AttachWx(tb); + if (pParentWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) + static_cast(pParentWnd)->m_listControlBars.push_back(this); + return TRUE; + }); +} + +BOOL CToolBar::CreateEx(CWnd* pParentWnd, DWORD, DWORD dwStyle, CRect, UINT nID) { return Create(pParentWnd, dwStyle, nID); } + +BOOL CToolBar::LoadToolBar(UINT nIDResource) { return LoadToolBar(MAKEINTRESOURCE(nIDResource)); } + +BOOL CToolBar::LoadToolBar(const char* lpszResourceName) { + ResRef ref = ResRef::From(lpszResourceName); + const rc::Toolbar* res = FindToolbar(ref); + if (!res || !m_hWnd) + return FALSE; + m_nResourceID = static_cast(ref.id); + m_buttonIDs.assign(res->buttons, res->buttons + res->buttonCount); + return OnMain([&]() -> BOOL { + auto* tb = wxDynamicCast(GetWx(), wxToolBar); + wxBitmap strip = LoadBitmapResource(ref); + int w = res->buttonWidth; + int h = res->buttonHeight; + wxImage image = strip.IsOk() ? strip.ConvertToImage() : wxImage(); + if (image.IsOk()) + image.SetMaskColour(192, 192, 192); + int imageIndex = 0; + for (int i = 0; i < res->buttonCount; ++i) { + int id = res->buttons[i]; + if (id == 0) { + tb->AddSeparator(); + continue; + } + wxBitmap bmp; + if (image.IsOk() && (imageIndex + 1) * w <= image.GetWidth()) + bmp = wxBitmap(image.GetSubImage(wxRect(imageIndex * w, 0, w, std::min(h, image.GetHeight())))); + ++imageIndex; + CString prompt = ResourceString(static_cast(id)); + CString tip; + int nl = prompt.Find('\n'); + if (nl >= 0) { + tip = prompt.Mid(nl + 1); + prompt = prompt.Left(nl); + } + tb->AddTool(MenuWxId(id), ToWx(tip), bmp.IsOk() ? bmp : wxBitmap(w, h), ToWx(tip), wxITEM_NORMAL); + tb->SetToolLongHelp(MenuWxId(id), ToWx(prompt)); + } + tb->Realize(); + return TRUE; + }); +} + +BOOL CToolBar::LoadBitmap(const char*) { return TRUE; } +BOOL CToolBar::LoadBitmap(UINT) { return TRUE; } +BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount) { + m_buttonIDs.assign(lpIDArray, lpIDArray + nIDCount); + return TRUE; +} +void CToolBar::SetSizes(SIZE, SIZE) {} +int CToolBar::CommandToIndex(UINT nIDFind) const { + for (size_t i = 0; i < m_buttonIDs.size(); ++i) + if (m_buttonIDs[i] == nIDFind) + return static_cast(i); + return -1; +} +UINT CToolBar::GetItemID(int nIndex) const { + return nIndex >= 0 && static_cast(nIndex) < m_buttonIDs.size() ? m_buttonIDs[static_cast(nIndex)] : 0; +} +void CToolBar::GetItemRect(int, LPRECT lpRect) const { ::SetRectEmpty(lpRect); } +UINT CToolBar::GetButtonStyle(int nIndex) const { return GetItemID(nIndex) ? TBBS_BUTTON : TBBS_SEPARATOR; } +void CToolBar::SetButtonStyle(int, UINT) {} +int CToolBar::GetCount() const { return static_cast(m_buttonIDs.size()); } + +CStatusBar::CStatusBar() {} + +BOOL CStatusBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID) { + if (!pParentWnd || !pParentWnd->m_hWnd) + return FALSE; + m_dwStyle = dwStyle; + return OnMain([&]() -> BOOL { + auto* frame = wxDynamicCast(pParentWnd->GetWx(), wxFrame); + if (!frame) + return FALSE; + wxStatusBar* sb = frame->CreateStatusBar(1, wxSTB_DEFAULT_STYLE, ToWxId(static_cast(nID))); + HookWindow(sb, ControlKind::StatusBar, static_cast(nID), dwStyle, 0); + AttachWx(sb); + if (pParentWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { + static_cast(pParentWnd)->m_listControlBars.push_back(this); + static_cast(pParentWnd)->m_pStatusBar = this; + } + return TRUE; + }); +} + +BOOL CStatusBar::CreateEx(CWnd* pParentWnd, DWORD, DWORD dwStyle, UINT nID) { return Create(pParentWnd, dwStyle, nID); } + +BOOL CStatusBar::SetIndicators(const UINT* lpIDArray, int nIDCount) { + m_indicators.assign(lpIDArray, lpIDArray + nIDCount); + return OnMain([&]() -> BOOL { + auto* sb = wxDynamicCast(GetWx(), wxStatusBar); + if (!sb) + return FALSE; + std::vector widths(static_cast(nIDCount), -1); + sb->SetFieldsCount(nIDCount); + for (int i = 0; i < nIDCount; ++i) { + if (lpIDArray[i] == ID_SEPARATOR) + continue; + CString text = ResourceString(lpIDArray[i]); + widths[static_cast(i)] = sb->GetTextExtent(ToWx(text)).x + 16; + sb->SetStatusText(ToWx(text), i); + } + sb->SetStatusWidths(nIDCount, widths.data()); + m_paneStyles.assign(static_cast(nIDCount), SBPS_NORMAL); + m_paneTexts.assign(static_cast(nIDCount), CString()); + return TRUE; + }); +} + +int CStatusBar::CommandToIndex(UINT nIDFind) const { + for (size_t i = 0; i < m_indicators.size(); ++i) + if (m_indicators[i] == nIDFind) + return static_cast(i); + return -1; +} + +UINT CStatusBar::GetItemID(int nIndex) const { + return nIndex >= 0 && static_cast(nIndex) < m_indicators.size() ? m_indicators[static_cast(nIndex)] : 0; +} + +void CStatusBar::GetItemRect(int nIndex, LPRECT lpRect) const { + OnMain([&] { + wxRect r; + auto* sb = wxDynamicCast(GetWx(), wxStatusBar); + if (sb) + sb->GetFieldRect(nIndex, r); + lpRect->left = r.x; + lpRect->top = r.y; + lpRect->right = r.x + r.width; + lpRect->bottom = r.y + r.height; + }); +} + +CString CStatusBar::GetPaneText(int nIndex) const { + if (nIndex >= 0 && static_cast(nIndex) < m_paneStyles.size() && (m_paneStyles[static_cast(nIndex)] & SBPS_DISABLED)) + return m_paneTexts[static_cast(nIndex)]; + return OnMain([&]() -> CString { + auto* sb = wxDynamicCast(GetWx(), wxStatusBar); + return sb && nIndex >= 0 && nIndex < sb->GetFieldsCount() ? CStr(sb->GetStatusText(nIndex)) : CString(); + }); +} + +void CStatusBar::GetPaneText(int nIndex, CString& rString) const { rString = GetPaneText(nIndex); } + +BOOL CStatusBar::SetPaneText(int nIndex, const char* lpszNewText, BOOL) { + const char* text = lpszNewText ? lpszNewText : ""; + return OnMain([&]() -> BOOL { + auto* sb = wxDynamicCast(GetWx(), wxStatusBar); + if (!sb || nIndex < 0 || nIndex >= sb->GetFieldsCount()) + return FALSE; + size_t i = static_cast(nIndex); + if (i < m_paneStyles.size() && (m_paneStyles[i] & SBPS_DISABLED)) { + m_paneTexts[i] = text; + return TRUE; + } + wxString wxText = ToWx(text); + if (sb->GetStatusText(nIndex) != wxText) + sb->SetStatusText(wxText, nIndex); + return TRUE; + }); +} + +void CStatusBar::GetPaneInfo(int nIndex, UINT& nID, UINT& nStyle, int& cxWidth) const { + nID = GetItemID(nIndex); + nStyle = SBPS_NORMAL; + CRect r; + GetItemRect(nIndex, &r); + cxWidth = r.Width(); +} + +void CStatusBar::SetPaneInfo(int nIndex, UINT nID, UINT nStyle, int cxWidth) { + if (nIndex < 0) + return; + if (static_cast(nIndex) < m_indicators.size()) + m_indicators[static_cast(nIndex)] = nID; + OnMain([&] { + auto* sb = wxDynamicCast(GetWx(), wxStatusBar); + if (!sb || nIndex >= sb->GetFieldsCount()) + return; + std::vector widths(static_cast(sb->GetFieldsCount())); + for (int i = 0; i < sb->GetFieldsCount(); ++i) + widths[static_cast(i)] = sb->GetStatusWidth(i); + widths[static_cast(nIndex)] = (nStyle & SBPS_STRETCH) ? -1 : cxWidth + 8; + sb->SetStatusWidths(sb->GetFieldsCount(), widths.data()); + }); +} + +UINT CStatusBar::GetPaneStyle(int nIndex) const { + return nIndex >= 0 && static_cast(nIndex) < m_paneStyles.size() ? m_paneStyles[static_cast(nIndex)] : SBPS_NORMAL; +} + +void CStatusBar::SetPaneStyle(int nIndex, UINT nStyle) { + if (nIndex < 0 || static_cast(nIndex) >= m_paneStyles.size()) + return; + size_t i = static_cast(nIndex); + bool wasDisabled = (m_paneStyles[i] & SBPS_DISABLED) != 0; + bool disabled = (nStyle & SBPS_DISABLED) != 0; + if (wasDisabled == disabled) { + m_paneStyles[i] = nStyle; + return; + } + CString text = GetPaneText(nIndex); + m_paneStyles[i] = nStyle & ~SBPS_DISABLED; + if (disabled) { + SetPaneText(nIndex, ""); + m_paneTexts[i] = text; + m_paneStyles[i] = nStyle; + } else { + SetPaneText(nIndex, text); + } +} + +namespace { + +class CStatusCmdUI : public CCmdUI { +public: + void Enable(BOOL bOn) override { + m_bEnableChanged = TRUE; + auto* bar = static_cast(m_pOther); + UINT style = bar->GetPaneStyle(static_cast(m_nIndex)) & ~static_cast(SBPS_DISABLED); + if (!bOn) + style |= SBPS_DISABLED; + bar->SetPaneStyle(static_cast(m_nIndex), style); + } + + void SetCheck(int nCheck) override { + auto* bar = static_cast(m_pOther); + UINT style = bar->GetPaneStyle(static_cast(m_nIndex)) & ~static_cast(SBPS_POPOUT); + if (nCheck) + style |= SBPS_POPOUT; + bar->SetPaneStyle(static_cast(m_nIndex), style); + } + + void SetText(const char* lpszText) override { static_cast(m_pOther)->SetPaneText(static_cast(m_nIndex), lpszText); } +}; + +} // namespace + +void CStatusBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) { + if (!pTarget || !m_hWnd) + return; + CStatusCmdUI state; + state.m_pOther = this; + state.m_nIndexMax = static_cast(m_indicators.size()); + for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; ++state.m_nIndex) { + state.m_nID = m_indicators[state.m_nIndex]; + if (state.m_nID == 0) + continue; + if (CWnd::OnCmdMsg(state.m_nID, static_cast(CN_UPDATE_COMMAND_UI), &state, nullptr)) + continue; + state.DoUpdate(pTarget, bDisableIfNoHndler); + } +} + +// --------------------------------------------------------------------------------------------- +// Rich edit view/document + +IMPLEMENT_DYNAMIC(CRichEditDoc, CDocument) +IMPLEMENT_DYNCREATE(CRichEditView, CView) + +BEGIN_MESSAGE_MAP(CRichEditView, CView) + ON_WM_CREATE() +END_MESSAGE_MAP() + +CRichEditDoc::CRichEditDoc() : m_bRTF(FALSE) {} +CRichEditCntrItem* CRichEditDoc::CreateClientItem(void*) const { return nullptr; } +CRichEditView* CRichEditDoc::GetView() const { + for (CView* v : m_viewList) + if (v->IsKindOf(RUNTIME_CLASS(CRichEditView))) + return static_cast(v); + return nullptr; +} + +void CRichEditDoc::Serialize(CArchive& ar) { + CRichEditView* view = GetView(); + if (view) + view->Serialize(ar); +} + +CRichEditView::CRichEditView() : m_nWordWrap(WrapToWindow) {} + +int CRichEditView::OnCreate(LPCREATESTRUCT lpcs) { return CView::OnCreate(lpcs); } + +void CRichEditView::OnInitialUpdate() { CView::OnInitialUpdate(); } + +void CRichEditView::Serialize(CArchive& ar) { + CFile* f = ar.GetFile(); + if (!f) + return; + if (ar.IsLoading()) { + ULONGLONG len = f->GetLength(); + std::string data(static_cast(len), '\0'); + if (len) + ar.Read(&data[0], static_cast(len)); + SetWindowText(data.c_str()); + } else { + CString text; + GetWindowText(text); + ar.Write(text.GetString(), static_cast(text.GetLength())); + } +} + +long CRichEditView::GetTextLength() const { return GetWindowTextLength(); } + +void CRichEditView::SetCharFormat(CHARFORMAT2 cf) { + SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast(&cf)); +} + +CHARFORMAT2& CRichEditView::GetCharFormatSelection() { + static CHARFORMAT2 cf; + memset(&cf, 0, sizeof cf); + cf.cbSize = sizeof cf; + SendMessage(EM_GETCHARFORMAT, SCF_SELECTION, reinterpret_cast(&cf)); + return cf; +} + +// --------------------------------------------------------------------------------------------- +// Recent file list and command line + +CRecentFileList::CRecentFileList(UINT nStart, const char* lpszSection, const char* lpszEntryFormat, int nSize, + int nMaxDispLen) + : m_nSize(nSize), m_arrNames(static_cast(nSize)), m_strSectionName(lpszSection), + m_strEntryFormat(lpszEntryFormat), m_nStart(nStart), m_nMaxDisplayLength(nMaxDispLen) {} + +void CRecentFileList::Remove(int nIndex) { + if (nIndex < 0 || nIndex >= m_nSize) + return; + m_arrNames.erase(m_arrNames.begin() + nIndex); + m_arrNames.push_back(CString()); +} + +void CRecentFileList::Add(const char* lpszPathName) { + CString path(lpszPathName); + for (int i = 0; i < m_nSize; ++i) + if (m_arrNames[static_cast(i)].CompareNoCase(path) == 0) { + Remove(i); + break; + } + m_arrNames.insert(m_arrNames.begin(), path); + m_arrNames.resize(static_cast(m_nSize)); + WriteList(); +} + +BOOL CRecentFileList::GetDisplayName(CString& strName, int nIndex, const char*, int, BOOL) const { + if (nIndex < 0 || nIndex >= m_nSize || m_arrNames[static_cast(nIndex)].IsEmpty()) + return FALSE; + strName = m_arrNames[static_cast(nIndex)]; + int slash = strName.ReverseFind('\\'); + if (slash >= 0) + strName = strName.Mid(slash + 1); + return TRUE; +} + +void CRecentFileList::UpdateMenu(CCmdUI* pCmdUI) { pCmdUI->Enable(!m_arrNames.empty() && !m_arrNames[0].IsEmpty()); } + +void CRecentFileList::ReadList() { + CWinApp* app = AfxGetApp(); + if (!app) + return; + for (int i = 0; i < m_nSize; ++i) { + CString entry; + entry.Format(m_strEntryFormat, i + 1); + m_arrNames[static_cast(i)] = app->GetProfileString(m_strSectionName, entry, ""); + } +} + +void CRecentFileList::WriteList() { + CWinApp* app = AfxGetApp(); + if (!app) + return; + for (int i = 0; i < m_nSize; ++i) { + CString entry; + entry.Format(m_strEntryFormat, i + 1); + app->WriteProfileString(m_strSectionName, entry, m_arrNames[static_cast(i)]); + } +} + +CCommandLineInfo::CCommandLineInfo() + : m_bShowSplash(TRUE), m_bRunEmbedded(FALSE), m_bRunAutomated(FALSE), m_nShellCommand(FileNew) {} + +void CCommandLineInfo::ParseParam(const char* pszParam, BOOL bFlag, BOOL) { + if (bFlag) + return; + if (m_strFileName.IsEmpty()) { + m_strFileName = pszParam; + m_nShellCommand = FileOpen; + } +} diff --git a/port/mfcwx/src/file.cpp b/port/mfcwx/src/file.cpp new file mode 100644 index 000000000..84bf7d854 --- /dev/null +++ b/port/mfcwx/src/file.cpp @@ -0,0 +1,945 @@ +#include "afx.h" +#include "runtime.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#endif + +#undef fopen +#undef rename +#undef remove + +namespace mfcwx { + +std::string GetDataDirectory(); + +namespace { + +#ifdef __APPLE__ +inline const struct timespec& MTime(const struct stat& st) { return st.st_mtimespec; } +inline const struct timespec& ATime(const struct stat& st) { return st.st_atimespec; } +inline const struct timespec& BirthTime(const struct stat& st) { return st.st_birthtimespec; } +#else +inline const struct timespec& MTime(const struct stat& st) { return st.st_mtim; } +inline const struct timespec& ATime(const struct stat& st) { return st.st_atim; } +inline const struct timespec& BirthTime(const struct stat& st) { return st.st_ctim; } +#endif + +std::string Join(const std::string& a, const std::string& b) { + if (a.empty()) + return b; + if (a.back() == '/') + return a + b; + return a + "/" + b; +} + +bool Exists(const std::string& p) { + struct stat st; + return lstat(p.c_str(), &st) == 0; +} + +std::vector SplitComponents(const std::string& p) { + std::vector parts; + size_t start = 0; + while (start <= p.size()) { + size_t slash = p.find('/', start); + std::string part = p.substr(start, slash == std::string::npos ? std::string::npos : slash - start); + if (!part.empty()) + parts.push_back(part); + if (slash == std::string::npos) + break; + start = slash + 1; + } + return parts; +} + +std::string ResolveCase(const std::string& native) { + bool absolute = native[0] == '/'; + std::vector parts = SplitComponents(native); + std::string out = absolute ? "/" : ""; + for (size_t i = 0; i < parts.size(); ++i) { + const std::string& part = parts[i]; + std::string candidate = Join(out, part); + if (part == "." || part == ".." || Exists(candidate)) { + out = candidate; + continue; + } + bool found = false; + if (DIR* d = opendir(out.empty() ? "." : out.c_str())) { + while (dirent* e = readdir(d)) { + if (strcasecmp(e->d_name, part.c_str()) == 0) { + out = Join(out, e->d_name); + found = true; + break; + } + } + closedir(d); + } + if (!found) { + for (size_t j = i; j < parts.size(); ++j) + out = Join(out, parts[j]); + break; + } + } + if (native.size() > 1 && native.back() == '/' && (out.empty() || out.back() != '/')) + out += '/'; + return out; +} + +std::string ResolveNative(const std::string& native) { + if (native.empty() || Exists(native)) + return native; + return ResolveCase(native); +} + +std::string CurrentDirectory() { + char buf[PATH_MAX]; + if (getcwd(buf, sizeof buf)) + return buf; + return "/"; +} + +std::string NormalizeNative(const std::string& native) { + std::string full = !native.empty() && native[0] == '/' ? native : Join(CurrentDirectory(), native); + std::vector out; + for (const std::string& part : SplitComponents(full)) { + if (part == ".") + continue; + if (part == "..") { + if (!out.empty()) + out.pop_back(); + continue; + } + out.push_back(part); + } + std::string result; + for (const std::string& part : out) + result += "/" + part; + return result.empty() ? "/" : result; +} + +DWORD CopyResult(const std::string& s, LPSTR buffer, DWORD size) { + if (!buffer || size <= s.size()) + return static_cast(s.size() + 1); + memcpy(buffer, s.c_str(), s.size() + 1); + return static_cast(s.size()); +} + +DWORD AttributesFromStat(const struct stat& st, const std::string& path, const char* name) { + DWORD attrs = 0; + if (S_ISDIR(st.st_mode)) + attrs |= FILE_ATTRIBUTE_DIRECTORY; + else + attrs |= FILE_ATTRIBUTE_ARCHIVE; + if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) || access(path.c_str(), W_OK) != 0) + attrs |= FILE_ATTRIBUTE_READONLY; + if (name && name[0] == '.' && strcmp(name, ".") != 0 && strcmp(name, "..") != 0) + attrs |= FILE_ATTRIBUTE_HIDDEN; + return attrs ? attrs : FILE_ATTRIBUTE_NORMAL; +} + +bool MatchGlob(const char* name, const char* mask) { + while (*mask) { + if (*mask == '*') { + while (*mask == '*') + ++mask; + if (!*mask) + return true; + for (const char* p = name; *p; ++p) + if (MatchGlob(p, mask)) + return true; + return MatchGlob(name + strlen(name), mask); + } + if (!*name) + return false; + if (*mask != '?' && tolower(static_cast(*mask)) != tolower(static_cast(*name))) + return false; + ++mask; + ++name; + } + return *name == 0; +} + +bool MatchMask(const char* name, const std::string& mask) { + if (mask == "*" || mask == "*.*") + return true; + if (MatchGlob(name, mask.c_str())) + return true; + // DOS semantics: "name.*" also matches "name"; "name." matches names without extension. + if (mask.size() > 2 && mask.compare(mask.size() - 2, 2, ".*") == 0 && !strchr(name, '.')) + return MatchGlob(name, mask.substr(0, mask.size() - 2).c_str()); + if (mask.size() > 1 && mask.back() == '.' && mask != "." && mask != ".." && !strchr(name, '.')) + return MatchGlob(name, mask.substr(0, mask.size() - 1).c_str()); + return false; +} + +struct FindObj { + std::string dir; + std::vector names; + size_t index = 0; +}; + +std::mutex& FindLock() { + static std::mutex* m = new std::mutex; + return *m; +} + +std::set& Finds() { + static auto* s = new std::set; + return *s; +} + +void FillFindData(const FindObj& f, const std::string& name, LPWIN32_FIND_DATA data) { + memset(data, 0, sizeof *data); + std::string path = Join(f.dir, name); + struct stat st; + if (stat(path.c_str(), &st) == 0 || lstat(path.c_str(), &st) == 0) { + data->dwFileAttributes = AttributesFromStat(st, path, name.c_str()); + data->ftCreationTime = MakeFileTime(BirthTime(st).tv_sec, BirthTime(st).tv_nsec); + data->ftLastAccessTime = MakeFileTime(ATime(st).tv_sec, ATime(st).tv_nsec); + data->ftLastWriteTime = MakeFileTime(MTime(st).tv_sec, MTime(st).tv_nsec); + if (!S_ISDIR(st.st_mode)) { + data->nFileSizeHigh = static_cast(static_cast(st.st_size) >> 32); + data->nFileSizeLow = static_cast(st.st_size); + } + } else { + data->dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + } + std::string ansi = Utf8ToAnsi(name.c_str()); + strncpy(data->cFileName, ansi.c_str(), sizeof data->cFileName - 1); +} + +bool CopyFileContents(const std::string& src, const std::string& dst) { + int in = open(src.c_str(), O_RDONLY | O_CLOEXEC); + if (in < 0) + return false; + struct stat st; + if (fstat(in, &st) != 0 || S_ISDIR(st.st_mode)) { + int err = S_ISDIR(st.st_mode) ? EACCES : errno; + close(in); + errno = err; + return false; + } + int out = open(dst.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, st.st_mode & 0777); + if (out < 0) { + int err = errno; + close(in); + errno = err; + return false; + } + char buf[65536]; + bool ok = true; + for (;;) { + ssize_t n = read(in, buf, sizeof buf); + if (n < 0 && errno == EINTR) + continue; + if (n <= 0) { + ok = n == 0; + break; + } + for (ssize_t done = 0; done < n;) { + ssize_t w = write(out, buf + done, static_cast(n - done)); + if (w < 0 && errno == EINTR) + continue; + if (w <= 0) { + ok = false; + break; + } + done += w; + } + if (!ok) + break; + } + int err = errno; + if (ok) { + struct timespec times[2] = {ATime(st), MTime(st)}; + futimens(out, times); + fchmod(out, st.st_mode & 07777); + } + close(in); + if (close(out) != 0 && ok) { + ok = false; + err = errno; + } + errno = err; + return ok; +} + +} // namespace + +std::string FsPath(const char* appPath) { return ResolveNative(NativePath(appPath)); } + +std::string AbsoluteNativePath(const char* appPath) { return NormalizeNative(NativePath(appPath)); } + +std::string FullAppPath(const char* appPath) { return AppPath(AbsoluteNativePath(appPath).c_str()); } + +std::string ExecutablePath() { + static const std::string path = []() { +#ifdef __APPLE__ + uint32_t size = 0; + _NSGetExecutablePath(nullptr, &size); + std::string buf(size + 1, '\0'); + if (_NSGetExecutablePath(&buf[0], &size) != 0) + return std::string(); + buf.resize(strlen(buf.c_str())); + char real[PATH_MAX]; + return realpath(buf.c_str(), real) ? std::string(real) : buf; +#else + char buf[PATH_MAX]; + ssize_t n = readlink("/proc/self/exe", buf, sizeof buf - 1); + if (n <= 0) + return std::string(); + buf[n] = 0; + return std::string(buf); +#endif + }(); + return path; +} + +std::string TempDirectory() { + static std::mutex* m = new std::mutex; + std::lock_guard lk(*m); + const char* env = getenv("TMPDIR"); + std::string base = env && *env ? env : "/tmp"; + while (base.size() > 1 && base.back() == '/') + base.pop_back(); + std::string dir = base + "/cryptool1-" + std::to_string(static_cast(getuid())); + struct stat st; + if (lstat(dir.c_str(), &st) != 0) { + mkdir(dir.c_str(), 0700); + if (lstat(dir.c_str(), &st) != 0) + return base; + } + if (!S_ISDIR(st.st_mode) || st.st_uid != getuid()) + return base; + return dir; +} + +std::string UserConfigDirectory() { + const char* home = getenv("HOME"); + std::string h; + if (home && *home) { + h = home; + } else if (struct passwd* pw = getpwuid(getuid())) { + h = pw->pw_dir; + } +#ifdef __APPLE__ + return h + "/Library/Preferences"; +#else + const char* xdg = getenv("XDG_CONFIG_HOME"); + if (xdg && *xdg == '/') + return xdg; + return h + "/.config"; +#endif +} + +DWORD ErrnoToWin32(int err) { + switch (err) { + case 0: + return ERROR_SUCCESS; + case ENOENT: + return ERROR_FILE_NOT_FOUND; + case ENOTDIR: + return ERROR_PATH_NOT_FOUND; + case EACCES: + case EPERM: + case EISDIR: + return ERROR_ACCESS_DENIED; + case EBADF: + return ERROR_INVALID_HANDLE; + case ENOMEM: + return ERROR_NOT_ENOUGH_MEMORY; + case EEXIST: + return ERROR_ALREADY_EXISTS; + case EMFILE: + case ENFILE: + return 4; + case ENOSPC: + return 112; + case EINVAL: + return 87; + case ENOTEMPTY: + return 145; + case EXDEV: + return 17; + case EROFS: + return 19; + case EBUSY: + case ETXTBSY: + return 32; + case ENAMETOOLONG: + return 206; + case ENOEXEC: + return 193; + case EIO: + return 1117; + case ESPIPE: + return 131; + default: + return 31; + } +} + +void SetLastErrorFromErrno(int err) { ::SetLastError(ErrnoToWin32(err)); } + +} // namespace mfcwx + +using namespace mfcwx; + +HANDLE CreateFileA(LPCSTR name, DWORD access, DWORD, LPSECURITY_ATTRIBUTES, DWORD disposition, DWORD flags, HANDLE) { + if (!name || !*name) { + SetLastError(ERROR_PATH_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + const DWORD readBits = 0x80000000u | 0x10000000u | FILE_READ_DATA; + const DWORD writeBits = 0x40000000u | 0x10000000u | FILE_WRITE_DATA | FILE_APPEND_DATA; + bool rd = (access & readBits) != 0; + bool wr = (access & writeBits) != 0; + int oflags = O_CLOEXEC | (rd && wr ? O_RDWR : wr ? O_WRONLY : O_RDONLY); + if ((access & FILE_APPEND_DATA) && !(access & (0x40000000u | 0x10000000u | FILE_WRITE_DATA))) + oflags |= O_APPEND; + switch (disposition) { + case CREATE_NEW: + oflags |= O_CREAT | O_EXCL; + break; + case CREATE_ALWAYS: + oflags |= O_CREAT | O_TRUNC; + break; + case OPEN_EXISTING: + break; + case OPEN_ALWAYS: + oflags |= O_CREAT; + break; + case TRUNCATE_EXISTING: + oflags |= O_TRUNC; + break; + default: + SetLastError(87); + return INVALID_HANDLE_VALUE; + } + std::string path = FsPath(name); + struct stat st; + bool existed = stat(path.c_str(), &st) == 0; + if (existed && S_ISDIR(st.st_mode)) { + SetLastError(ERROR_ACCESS_DENIED); + return INVALID_HANDLE_VALUE; + } + int fd = open(path.c_str(), oflags, (flags & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666); + if (fd < 0) { + SetLastError(errno == EEXIST ? 80 : ErrnoToWin32(errno)); + return INVALID_HANDLE_VALUE; + } + if (flags & 0x04000000u) + unlink(path.c_str()); + HANDLE h = HandleFromFd(fd, path); + SetLastError(existed && (disposition == CREATE_ALWAYS || disposition == OPEN_ALWAYS) ? ERROR_ALREADY_EXISTS : 0); + return h; +} + +BOOL ReadFile(HANDLE f, LPVOID buffer, DWORD toRead, LPDWORD readCount, LPOVERLAPPED ov) { + if (readCount) + *readCount = 0; + int fd = FdFromHandle(f); + if (fd < 0) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + char* p = static_cast(buffer); + off_t offset = ov ? static_cast((static_cast(ov->OffsetHigh) << 32) | ov->Offset) : 0; + DWORD total = 0; + while (total < toRead) { + ssize_t n = ov ? pread(fd, p + total, toRead - total, offset + total) : read(fd, p + total, toRead - total); + if (n < 0 && errno == EINTR) + continue; + if (n < 0) { + SetLastErrorFromErrno(errno); + if (readCount) + *readCount = total; + return FALSE; + } + if (n == 0) + break; + total += static_cast(n); + struct stat st; + if (fstat(fd, &st) == 0 && !S_ISREG(st.st_mode)) + break; + } + if (readCount) + *readCount = total; + return TRUE; +} + +BOOL WriteFile(HANDLE f, LPCVOID buffer, DWORD toWrite, LPDWORD written, LPOVERLAPPED ov) { + if (written) + *written = 0; + int fd = FdFromHandle(f); + if (fd < 0) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + const char* p = static_cast(buffer); + off_t offset = ov ? static_cast((static_cast(ov->OffsetHigh) << 32) | ov->Offset) : 0; + DWORD total = 0; + while (total < toWrite) { + ssize_t n = ov ? pwrite(fd, p + total, toWrite - total, offset + total) : write(fd, p + total, toWrite - total); + if (n < 0 && errno == EINTR) + continue; + if (n <= 0) { + SetLastErrorFromErrno(n < 0 ? errno : ENOSPC); + if (written) + *written = total; + return FALSE; + } + total += static_cast(n); + } + if (written) + *written = total; + return TRUE; +} + +DWORD SetFilePointer(HANDLE f, LONG distance, PLONG distanceHigh, DWORD method) { + int fd = FdFromHandle(f); + if (fd < 0) { + SetLastError(ERROR_INVALID_HANDLE); + return INVALID_SET_FILE_POINTER; + } + LONGLONG off = distanceHigh + ? static_cast((static_cast(static_cast(*distanceHigh)) << 32) | + static_cast(distance)) + : distance; + int whence = method == FILE_CURRENT ? SEEK_CUR : method == FILE_END ? SEEK_END : SEEK_SET; + off_t pos = lseek(fd, static_cast(off), whence); + if (pos < 0) { + SetLastError(errno == EINVAL ? 131 : ErrnoToWin32(errno)); + return INVALID_SET_FILE_POINTER; + } + if (distanceHigh) + *distanceHigh = static_cast(static_cast(pos) >> 32); + SetLastError(0); + return static_cast(pos); +} + +BOOL SetEndOfFile(HANDLE f) { + int fd = FdFromHandle(f); + off_t pos = fd >= 0 ? lseek(fd, 0, SEEK_CUR) : -1; + if (pos < 0 || ftruncate(fd, pos) != 0) { + SetLastError(fd < 0 ? ERROR_INVALID_HANDLE : ErrnoToWin32(errno)); + return FALSE; + } + return TRUE; +} + +DWORD GetFileSize(HANDLE f, LPDWORD high) { + int fd = FdFromHandle(f); + struct stat st; + if (fd < 0 || fstat(fd, &st) != 0) { + SetLastError(fd < 0 ? ERROR_INVALID_HANDLE : ErrnoToWin32(errno)); + return INVALID_FILE_SIZE; + } + if (high) + *high = static_cast(static_cast(st.st_size) >> 32); + SetLastError(0); + return static_cast(st.st_size); +} + +BOOL GetFileSizeEx(HANDLE f, PLARGE_INTEGER size) { + int fd = FdFromHandle(f); + struct stat st; + if (fd < 0 || fstat(fd, &st) != 0) { + SetLastError(fd < 0 ? ERROR_INVALID_HANDLE : ErrnoToWin32(errno)); + return FALSE; + } + size->QuadPart = st.st_size; + return TRUE; +} + +BOOL FlushFileBuffers(HANDLE f) { + int fd = FdFromHandle(f); + if (fd < 0) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + fsync(fd); + return TRUE; +} + +BOOL GetFileTime(HANDLE f, LPFILETIME creation, LPFILETIME accessTime, LPFILETIME writeTime) { + int fd = FdFromHandle(f); + struct stat st; + if (fd < 0 || fstat(fd, &st) != 0) { + SetLastError(fd < 0 ? ERROR_INVALID_HANDLE : ErrnoToWin32(errno)); + return FALSE; + } + if (creation) + *creation = MakeFileTime(BirthTime(st).tv_sec, BirthTime(st).tv_nsec); + if (accessTime) + *accessTime = MakeFileTime(ATime(st).tv_sec, ATime(st).tv_nsec); + if (writeTime) + *writeTime = MakeFileTime(MTime(st).tv_sec, MTime(st).tv_nsec); + return TRUE; +} + +BOOL DeleteFileA(LPCSTR name) { + std::string path = FsPath(name); + struct stat st; + if (lstat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + if (unlink(path.c_str()) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + return TRUE; +} + +BOOL CopyFileA(LPCSTR from, LPCSTR to, BOOL failIfExists) { + std::string src = FsPath(from); + std::string dst = FsPath(to); + if (failIfExists && Exists(dst)) { + SetLastError(80); + return FALSE; + } + if (!CopyFileContents(src, dst)) { + SetLastErrorFromErrno(errno); + return FALSE; + } + return TRUE; +} + +BOOL MoveFileA(LPCSTR from, LPCSTR to) { return MoveFileExA(from, to, 0); } + +BOOL MoveFileExA(LPCSTR from, LPCSTR to, DWORD flags) { + std::string src = FsPath(from); + if (!to) + return DeleteFileA(from); + std::string dst = FsPath(to); + struct stat a, b; + if (lstat(src.c_str(), &a) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + if (!(flags & MOVEFILE_REPLACE_EXISTING) && lstat(dst.c_str(), &b) == 0 && + !(a.st_dev == b.st_dev && a.st_ino == b.st_ino)) { + SetLastError(ERROR_ALREADY_EXISTS); + return FALSE; + } + if (rename(src.c_str(), dst.c_str()) == 0) + return TRUE; + if (errno == EXDEV && (flags & MOVEFILE_COPY_ALLOWED) && !S_ISDIR(a.st_mode)) { + if (CopyFileContents(src, dst) && unlink(src.c_str()) == 0) + return TRUE; + } + SetLastErrorFromErrno(errno); + return FALSE; +} + +BOOL CreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES) { + if (mkdir(FsPath(path).c_str(), 0777) != 0) { + SetLastError(errno == ENOENT ? ERROR_PATH_NOT_FOUND : ErrnoToWin32(errno)); + return FALSE; + } + return TRUE; +} + +BOOL RemoveDirectoryA(LPCSTR path) { + if (rmdir(FsPath(path).c_str()) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + return TRUE; +} + +BOOL SetCurrentDirectoryA(LPCSTR path) { + if (!path || chdir(FsPath(path).c_str()) != 0) { + SetLastError(path ? ErrnoToWin32(errno) : 87); + return FALSE; + } + return TRUE; +} + +DWORD GetCurrentDirectoryA(DWORD size, LPSTR buffer) { + return CopyResult(AppPath(CurrentDirectory().c_str()), buffer, size); +} + +DWORD GetTempPathA(DWORD size, LPSTR buffer) { + return CopyResult(AppPath(TempDirectory().c_str()) + "\\", buffer, size); +} + +UINT GetTempFileNameA(LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer) { + std::string dir = path && *path ? path : "."; + while (dir.size() > 1 && (dir.back() == '\\' || dir.back() == '/')) + dir.pop_back(); + std::string pre = prefix ? std::string(prefix).substr(0, 3) : std::string(); + auto makeName = [&](UINT u) { + char hex[16]; + snprintf(hex, sizeof hex, "%X", u & 0xFFFF); + return dir + "\\" + pre + hex + ".tmp"; + }; + if (unique) { + std::string name = makeName(unique); + if (buffer) + strncpy(buffer, name.c_str(), MAX_PATH - 1), buffer[MAX_PATH - 1] = 0; + return unique & 0xFFFF; + } + UINT start = (static_cast(GetTickCount()) ^ static_cast(getpid()) * 2654435761u) & 0xFFFF; + for (UINT i = 0; i < 0x10000; ++i) { + UINT u = (start + i) & 0xFFFF; + if (!u) + continue; + std::string name = makeName(u); + int fd = open(FsPath(name.c_str()).c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0666); + if (fd >= 0) { + close(fd); + if (buffer) + strncpy(buffer, name.c_str(), MAX_PATH - 1), buffer[MAX_PATH - 1] = 0; + return u; + } + if (errno != EEXIST) { + SetLastError(errno == ENOENT ? ERROR_PATH_NOT_FOUND : ErrnoToWin32(errno)); + return 0; + } + } + SetLastError(80); + return 0; +} + +DWORD GetFileAttributesA(LPCSTR name) { + std::string path = FsPath(name); + struct stat st; + if (stat(path.c_str(), &st) != 0) { + SetLastErrorFromErrno(errno); + return INVALID_FILE_ATTRIBUTES; + } + size_t slash = path.rfind('/'); + return AttributesFromStat(st, path, path.c_str() + (slash == std::string::npos ? 0 : slash + 1)); +} + +BOOL SetFileAttributesA(LPCSTR name, DWORD attrs) { + std::string path = FsPath(name); + struct stat st; + if (stat(path.c_str(), &st) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + mode_t mode = st.st_mode & 07777; + if (attrs & FILE_ATTRIBUTE_READONLY) + mode &= ~static_cast(S_IWUSR | S_IWGRP | S_IWOTH); + else + mode |= S_IWUSR; + if (mode != (st.st_mode & 07777) && chmod(path.c_str(), mode) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + return TRUE; +} + +DWORD GetFullPathNameA(LPCSTR name, DWORD size, LPSTR buffer, LPSTR* filePart) { + if (!name || !*name) { + SetLastError(87); + return 0; + } + std::string full = FullAppPath(name); + char last = name[strlen(name) - 1]; + if ((last == '\\' || last == '/') && full.back() != '\\') + full += '\\'; + DWORD r = CopyResult(full, buffer, size); + if (filePart) { + *filePart = nullptr; + if (buffer && r < size) { + char* slash = strrchr(buffer, '\\'); + if (slash && slash[1]) + *filePart = slash + 1; + } + } + return r; +} + +DWORD GetShortPathNameA(LPCSTR longPath, LPSTR shortPath, DWORD size) { + if (!longPath || !Exists(FsPath(longPath))) { + SetLastError(ERROR_FILE_NOT_FOUND); + return 0; + } + std::string s = longPath; + return CopyResult(s, shortPath, size); +} + +DWORD GetLongPathNameA(LPCSTR shortPath, LPSTR longPath, DWORD size) { return GetShortPathNameA(shortPath, longPath, size); } + +HANDLE FindFirstFileA(LPCSTR pattern, LPWIN32_FIND_DATA data) { + std::string native = NativePath(pattern); + size_t slash = native.rfind('/'); + std::string dir = slash == std::string::npos ? "." : (slash == 0 ? "/" : native.substr(0, slash)); + std::string mask = slash == std::string::npos ? native : native.substr(slash + 1); + if (mask.empty()) { + SetLastError(ERROR_FILE_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + dir = ResolveNative(dir); + DIR* d = opendir(dir.c_str()); + if (!d) { + SetLastError(errno == ENOENT || errno == ENOTDIR ? ERROR_PATH_NOT_FOUND : ErrnoToWin32(errno)); + return INVALID_HANDLE_VALUE; + } + auto* f = new FindObj; + f->dir = dir; + while (dirent* e = readdir(d)) + if (MatchMask(e->d_name, mask)) + f->names.push_back(e->d_name); + closedir(d); + if (f->names.empty()) { + delete f; + SetLastError(ERROR_FILE_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + std::sort(f->names.begin(), f->names.end(), + [](const std::string& a, const std::string& b) { return strcasecmp(a.c_str(), b.c_str()) < 0; }); + FillFindData(*f, f->names[0], data); + f->index = 1; + { + std::lock_guard lk(FindLock()); + Finds().insert(f); + } + SetLastError(0); + return f; +} + +BOOL FindNextFileA(HANDLE find, LPWIN32_FIND_DATA data) { + std::lock_guard lk(FindLock()); + auto* f = static_cast(find); + if (!Finds().count(f)) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (f->index >= f->names.size()) { + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; + } + FillFindData(*f, f->names[f->index++], data); + return TRUE; +} + +BOOL FindClose(HANDLE find) { + auto* f = static_cast(find); + { + std::lock_guard lk(FindLock()); + if (!Finds().erase(f)) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + } + delete f; + return TRUE; +} + +UINT GetWindowsDirectoryA(LPSTR buffer, UINT size) { + return CopyResult(AppPath(GetDataDirectory().c_str()), buffer, size); +} + +UINT GetSystemDirectoryA(LPSTR buffer, UINT size) { return GetWindowsDirectoryA(buffer, size); } + +UINT GetDriveTypeA(LPCSTR root) { + if (root && *root && !Exists(FsPath(root))) + return 1; + return 3; +} + +BOOL GetDiskFreeSpaceExA(LPCSTR dir, PULARGE_INTEGER freeToCaller, PULARGE_INTEGER total, PULARGE_INTEGER totalFree) { + struct statvfs vfs; + std::string path = dir && *dir ? FsPath(dir) : std::string("."); + if (statvfs(path.c_str(), &vfs) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + ULONGLONG unit = vfs.f_frsize ? vfs.f_frsize : vfs.f_bsize; + if (freeToCaller) + freeToCaller->QuadPart = unit * vfs.f_bavail; + if (total) + total->QuadPart = unit * vfs.f_blocks; + if (totalFree) + totalFree->QuadPart = unit * vfs.f_bfree; + return TRUE; +} + +DWORD SearchPathA(const char* lpPath, const char* lpFileName, const char* lpExtension, DWORD nBufferLength, + char* lpBuffer, char** lpFilePart) { + if (!lpFileName || !*lpFileName) { + SetLastError(87); + return 0; + } + std::string name = lpFileName; + size_t slash = name.find_last_of("\\/"); + if (lpExtension && *lpExtension && name.find('.', slash == std::string::npos ? 0 : slash) == std::string::npos) + name += lpExtension; + std::vector dirs; + bool absolute = name[0] == '\\' || name[0] == '/' || (name.size() > 1 && name[1] == ':'); + if (absolute) { + dirs.push_back(std::string()); + } else if (lpPath && *lpPath) { + std::string list = lpPath; + for (size_t start = 0; start <= list.size();) { + size_t sep = list.find(';', start); + std::string dir = list.substr(start, sep == std::string::npos ? std::string::npos : sep - start); + if (!dir.empty()) + dirs.push_back(dir); + if (sep == std::string::npos) + break; + start = sep + 1; + } + } else { + std::string exe = ExecutablePath(); + size_t s = exe.rfind('/'); + if (s != std::string::npos) + dirs.push_back(AppPath(exe.substr(0, s).c_str())); + dirs.push_back(AppPath(CurrentDirectory().c_str())); + dirs.push_back(AppPath(GetDataDirectory().c_str())); + const char* env = getenv("PATH"); + std::string list = env ? env : ""; + for (size_t start = 0; start <= list.size();) { + size_t sep = list.find(':', start); + std::string dir = list.substr(start, sep == std::string::npos ? std::string::npos : sep - start); + if (!dir.empty()) + dirs.push_back(AppPath(dir.c_str())); + if (sep == std::string::npos) + break; + start = sep + 1; + } + } + for (const std::string& dir : dirs) { + std::string candidate = dir.empty() ? name : dir + "\\" + name; + struct stat st; + if (stat(FsPath(candidate.c_str()).c_str(), &st) != 0 || S_ISDIR(st.st_mode)) + continue; + std::string full = FullAppPath(candidate.c_str()); + DWORD r = CopyResult(full, lpBuffer, nBufferLength); + if (lpFilePart) { + *lpFilePart = nullptr; + if (lpBuffer && r < nBufferLength) { + char* sep = strrchr(lpBuffer, '\\'); + *lpFilePart = sep ? sep + 1 : lpBuffer; + } + } + return r; + } + SetLastError(ERROR_FILE_NOT_FOUND); + return 0; +} + +DWORD SearchPath(const char* lpPath, const char* lpFileName, const char* lpExtension, DWORD nBufferLength, + char* lpBuffer, char** lpFilePart) { + return SearchPathA(lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart); +} diff --git a/port/mfcwx/src/gdi.cpp b/port/mfcwx/src/gdi.cpp new file mode 100644 index 000000000..853702798 --- /dev/null +++ b/port/mfcwx/src/gdi.cpp @@ -0,0 +1,1443 @@ +#include "gdi_internal.h" + +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_DYNCREATE(CGdiObject, CObject) +IMPLEMENT_DYNAMIC(CPen, CGdiObject) +IMPLEMENT_DYNAMIC(CBrush, CGdiObject) +IMPLEMENT_DYNAMIC(CFont, CGdiObject) +IMPLEMENT_DYNAMIC(CBitmap, CGdiObject) +IMPLEMENT_DYNAMIC(CRgn, CGdiObject) +IMPLEMENT_DYNAMIC(CPalette, CGdiObject) + +namespace mfcwx { + +void PurgeTemporaryDCs(); + +namespace { + +std::unordered_set& Objects() { + static auto* objects = new std::unordered_set; + return *objects; +} + +std::unordered_map& TempObjects() { + static auto* temps = new std::unordered_map; + return *temps; +} + +std::vector& DetachedTemps() { + static auto* detached = new std::vector; + return *detached; +} + +void DetachWrappers(GdiObjectImpl* impl) { + HGDIOBJ h = reinterpret_cast(impl); + if (impl->permanent) { + impl->permanent->m_hObject = nullptr; + impl->permanent = nullptr; + } + auto it = TempObjects().find(h); + if (it != TempObjects().end()) { + it->second->m_hObject = nullptr; + DetachedTemps().push_back(it->second); + TempObjects().erase(it); + } +} + +void FreeImpl(GdiObjectImpl* impl) { + DetachWrappers(impl); + Objects().erase(impl); + delete impl; +} + +double ScreenDpi() { +#ifdef __WXOSX__ + return 72.0; +#else + static double dpi = [] { + wxSize ppi = wxGetDisplayPPI(); + return ppi.y > 0 ? static_cast(ppi.y) : 96.0; + }(); + return dpi; +#endif +} + +double PointsToPixels(double pt) { return pt * ScreenDpi() / 72.0; } + +void SetFontPixels(wxFont& f, double px) { + if (px < 1) + px = 1; +#ifdef __WXOSX__ + f.SetFractionalPointSize(PixelsToPoints(px)); +#else + f.SetPixelSize(wxSize(0, static_cast(std::lround(px)))); +#endif +} + +std::string Lower(std::string s) { + for (char& c : s) + c = static_cast(tolower(static_cast(c))); + return s; +} + +enum class FaceBase { Gui, Mono, Serif, Named }; + +bool IsValidFace(const wxString& name) { + static std::map cache; + auto it = cache.find(name); + if (it != cache.end()) + return it->second; + bool ok = wxFontEnumerator::IsValidFacename(name); + cache[name] = ok; + return ok; +} + +FaceBase ResolveFace(const std::string& face, BYTE pitchAndFamily, wxString& named) { + static const char* const gui[] = {"ms sans serif", "microsoft sans serif", "ms shell dlg", "ms shell dlg 2", + "tahoma", "arial", "helvetica", "system", "segoe ui", "small fonts"}; + static const char* const mono[] = {"courier new", "courier", "fixedsys", "terminal", "lucida console", + "consolas", "lucida sans typewriter", "monospace"}; + static const char* const serif[] = {"times new roman", "times", "ms serif"}; + std::string l = Lower(face); + while (!l.empty() && l.back() == ' ') + l.pop_back(); + if (!l.empty()) { + for (const char* g : gui) + if (l == g) + return FaceBase::Gui; + for (const char* m : mono) + if (l == m) + return FaceBase::Mono; + for (const char* s : serif) + if (l == s) + return FaceBase::Serif; + named = ToWx(face.c_str()); + if (l == "symbol" || l == "wingdings" || l == "webdings" || IsValidFace(named)) + return FaceBase::Named; + } + int family = pitchAndFamily & 0xF0; + if ((pitchAndFamily & 3) == FIXED_PITCH || family == FF_MODERN) + return FaceBase::Mono; + if (family == FF_ROMAN && l.empty()) + return FaceBase::Serif; + return FaceBase::Gui; +} + +wxFont GuiFont() { + wxFont f = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + if (!f.IsOk()) + f = *wxNORMAL_FONT; + return f; +} + +wxFont BaseFont(FaceBase base, const wxString& named) { + switch (base) { + case FaceBase::Mono: +#ifdef __WXOSX__ + return wxFont(wxFontInfo(12).FaceName("Menlo")); +#else + return wxFont(wxFontInfo(10).Family(wxFONTFAMILY_TELETYPE)); +#endif + case FaceBase::Serif: +#ifdef __WXOSX__ + if (IsValidFace("Times New Roman")) + return wxFont(wxFontInfo(12).FaceName("Times New Roman")); +#endif + return wxFont(wxFontInfo(12).Family(wxFONTFAMILY_ROMAN)); + case FaceBase::Named: + return wxFont(wxFontInfo(12).FaceName(named)); + case FaceBase::Gui: + break; + } + return GuiFont(); +} + +double GuiEmPixels() { + static double em = [] { + wxFont f = GuiFont(); +#ifdef __WXGTK__ + if (f.GetPixelSize().y > 0 && f.GetPointSize() <= 0) + return static_cast(f.GetPixelSize().y); +#endif + return PointsToPixels(f.GetFractionalPointSize()); + }(); + return em; +} + +std::string FaceOf(const LOGFONT& lf) { return std::string(lf.lfFaceName, strnlen(lf.lfFaceName, LF_FACESIZE)); } + +void SetFace(LOGFONT& lf, const char* face) { + memset(lf.lfFaceName, 0, sizeof lf.lfFaceName); + if (face) + strncpy(lf.lfFaceName, face, LF_FACESIZE - 1); +} + +LOGFONT LogFontFromWx(const wxFont& f, double em) { + LOGFONT lf; + memset(&lf, 0, sizeof lf); + lf.lfHeight = -static_cast(std::lround(em)); + lf.lfWeight = f.GetNumericWeight(); + lf.lfItalic = f.GetStyle() != wxFONTSTYLE_NORMAL; + lf.lfUnderline = f.GetUnderlined(); + lf.lfStrikeOut = f.GetStrikethrough(); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfQuality = DEFAULT_QUALITY; + bool fixed = f.IsFixedWidth(); + lf.lfPitchAndFamily = static_cast(fixed ? (FIXED_PITCH | FF_MODERN) : (VARIABLE_PITCH | FF_SWISS)); + wxString face = f.GetFaceName(); + if (face.empty() || face.StartsWith(".") || face == GuiFont().GetFaceName()) + SetFace(lf, fixed ? "Courier New" : "MS Shell Dlg"); + else + SetFace(lf, FromWx(face).c_str()); + return lf; +} + +GdiObjectImpl* NewImpl(GdiKind kind) { return new GdiObjectImpl(kind); } + +GdiObjectImpl* MakeStock(int index) { + auto brush = [](BYTE v, bool null) { + auto* b = NewImpl(GdiKind::Brush); + if (null) { + b->logBrush.lbStyle = BS_NULL; + b->brush = *wxTRANSPARENT_BRUSH; + } else { + b->logBrush.lbStyle = BS_SOLID; + b->logBrush.lbColor = RGB(v, v, v); + b->brush = wxBrush(wxColour(v, v, v)); + } + return b; + }; + auto pen = [](int style, BYTE v) { + auto* p = NewImpl(GdiKind::Pen); + p->penStyle = static_cast(style); + p->logPen.lopnStyle = static_cast(style); + p->logPen.lopnWidth.x = 0; + p->logPen.lopnColor = RGB(v, v, v); + return p; + }; + auto font = [](bool fixed, const char* face, int weight) { + auto* f = NewImpl(GdiKind::Font); + wxString named; + f->font = BaseFont(fixed ? FaceBase::Mono : FaceBase::Gui, named); + double em = GuiEmPixels(); + SetFontPixels(f->font, em); + f->emPx = em; + f->logFont = LogFontFromWx(f->font, em); + f->logFont.lfWeight = weight; + SetFace(f->logFont, face); + return f; + }; + switch (index) { + case WHITE_BRUSH: + return brush(255, false); + case LTGRAY_BRUSH: + return brush(192, false); + case GRAY_BRUSH: + return brush(128, false); + case DKGRAY_BRUSH: + return brush(64, false); + case BLACK_BRUSH: + return brush(0, false); + case NULL_BRUSH: + return brush(0, true); + case DC_BRUSH: + return brush(255, false); + case WHITE_PEN: + return pen(PS_SOLID, 255); + case BLACK_PEN: + case DC_PEN: + return pen(PS_SOLID, 0); + case NULL_PEN: + return pen(PS_NULL, 0); + case OEM_FIXED_FONT: + return font(true, "Terminal", FW_NORMAL); + case ANSI_FIXED_FONT: + return font(true, "Courier", FW_NORMAL); + case SYSTEM_FIXED_FONT: + return font(true, "Fixedsys", FW_NORMAL); + case ANSI_VAR_FONT: + return font(false, "MS Sans Serif", FW_NORMAL); + case SYSTEM_FONT: + return font(false, "System", FW_NORMAL); + case DEVICE_DEFAULT_FONT: + return font(false, "System", FW_NORMAL); + case DEFAULT_GUI_FONT: + return font(false, "MS Shell Dlg", FW_NORMAL); + case DEFAULT_PALETTE: + return NewImpl(GdiKind::Palette); + default: + return nullptr; + } +} + +constexpr int kStockCount = 21; +constexpr int kDefaultBitmapIndex = 20; + +GdiObjectImpl* Stock(int index) { + static GdiObjectImpl* stock[kStockCount] = {}; + if (index < 0 || index >= kStockCount) + return nullptr; + if (!stock[index]) { + GdiObjectImpl* impl = nullptr; + if (index == kDefaultBitmapIndex) { + impl = NewImpl(GdiKind::Bitmap); + impl->bitmap = wxBitmap(1, 1, 24); + impl->bitsPixel = 1; + } else { + impl = MakeStock(index); + } + if (!impl) + return nullptr; + impl->stock = true; + Objects().insert(impl); + stock[index] = impl; + } + return stock[index]; +} + +wxColour ClassicSysColor(int index) { + static const COLORREF table[] = { + RGB(212, 208, 200), RGB(58, 110, 165), RGB(10, 36, 106), RGB(128, 128, 128), RGB(212, 208, 200), + RGB(255, 255, 255), RGB(0, 0, 0), RGB(0, 0, 0), RGB(0, 0, 0), RGB(255, 255, 255), + RGB(212, 208, 200), RGB(212, 208, 200), RGB(128, 128, 128), RGB(10, 36, 106), RGB(255, 255, 255), + RGB(212, 208, 200), RGB(128, 128, 128), RGB(128, 128, 128), RGB(0, 0, 0), RGB(212, 208, 200), + RGB(255, 255, 255), RGB(64, 64, 64), RGB(212, 208, 200), RGB(0, 0, 0), RGB(255, 255, 225), + RGB(181, 181, 181), RGB(0, 0, 128), RGB(166, 202, 240), RGB(192, 192, 192), RGB(49, 106, 197), + RGB(236, 233, 216)}; + if (index < 0 || index >= static_cast(sizeof table / sizeof table[0])) + return *wxBLACK; + return ToWxColour(table[index]); +} + +bool WxSysColorIndex(int index, wxSystemColour& out) { + static const int map[] = {wxSYS_COLOUR_SCROLLBAR, + wxSYS_COLOUR_DESKTOP, + wxSYS_COLOUR_ACTIVECAPTION, + wxSYS_COLOUR_INACTIVECAPTION, + wxSYS_COLOUR_MENU, + wxSYS_COLOUR_WINDOW, + wxSYS_COLOUR_WINDOWFRAME, + wxSYS_COLOUR_MENUTEXT, + wxSYS_COLOUR_WINDOWTEXT, + wxSYS_COLOUR_CAPTIONTEXT, + wxSYS_COLOUR_ACTIVEBORDER, + wxSYS_COLOUR_INACTIVEBORDER, + wxSYS_COLOUR_APPWORKSPACE, + wxSYS_COLOUR_HIGHLIGHT, + wxSYS_COLOUR_HIGHLIGHTTEXT, + wxSYS_COLOUR_BTNFACE, + wxSYS_COLOUR_BTNSHADOW, + wxSYS_COLOUR_GRAYTEXT, + wxSYS_COLOUR_BTNTEXT, + wxSYS_COLOUR_INACTIVECAPTIONTEXT, + wxSYS_COLOUR_BTNHIGHLIGHT, + wxSYS_COLOUR_3DDKSHADOW, + wxSYS_COLOUR_3DLIGHT, + wxSYS_COLOUR_INFOTEXT, + wxSYS_COLOUR_INFOBK, + -1, + wxSYS_COLOUR_HOTLIGHT, + wxSYS_COLOUR_GRADIENTACTIVECAPTION, + wxSYS_COLOUR_GRADIENTINACTIVECAPTION, + wxSYS_COLOUR_MENUHILIGHT, + wxSYS_COLOUR_MENUBAR}; + if (index < 0 || index >= static_cast(sizeof map / sizeof map[0]) || map[index] < 0) + return false; + out = static_cast(map[index]); + return true; +} + +const wxDash* InternDashes(const std::vector& dashes) { + static auto* pool = new std::set>; + return pool->insert(dashes).first->data(); +} + +CGdiObject* NewWrapper(GdiKind kind) { + switch (kind) { + case GdiKind::Pen: + return new CPen; + case GdiKind::Brush: + return new CBrush; + case GdiKind::Font: + return new CFont; + case GdiKind::Bitmap: + return new CBitmap; + case GdiKind::Region: + return new CRgn; + case GdiKind::Palette: + return new CPalette; + } + return new CGdiObject; +} + +HGDIOBJ NewPen(int style, int width, COLORREF color, const LOGBRUSH* lb, int styleCount, const DWORD* userStyle) { + auto* impl = NewImpl(GdiKind::Pen); + impl->penStyle = static_cast(style); + impl->logPen.lopnStyle = static_cast(style); + impl->logPen.lopnWidth.x = width; + impl->logPen.lopnColor = lb ? lb->lbColor : color; + if ((style & PS_STYLE_MASK) == PS_USERSTYLE && userStyle) { + for (int i = 0; i < styleCount; ++i) + impl->dashes.push_back(static_cast(std::max(1, std::min(userStyle[i], 255)))); + } + return RegisterGdiObject(impl); +} + +wxBrushStyle HatchStyle(int index) { + switch (index) { + case HS_HORIZONTAL: + return wxBRUSHSTYLE_HORIZONTAL_HATCH; + case HS_VERTICAL: + return wxBRUSHSTYLE_VERTICAL_HATCH; + case HS_FDIAGONAL: + return wxBRUSHSTYLE_FDIAGONAL_HATCH; + case HS_BDIAGONAL: + return wxBRUSHSTYLE_BDIAGONAL_HATCH; + case HS_CROSS: + return wxBRUSHSTYLE_CROSS_HATCH; + default: + return wxBRUSHSTYLE_CROSSDIAG_HATCH; + } +} + +HGDIOBJ NewSolidBrush(COLORREF c) { + auto* impl = NewImpl(GdiKind::Brush); + impl->logBrush.lbStyle = BS_SOLID; + impl->logBrush.lbColor = c; + impl->brush = wxBrush(ToWxColour(c)); + return RegisterGdiObject(impl); +} + +HGDIOBJ NewHatchBrush(int index, COLORREF c) { + auto* impl = NewImpl(GdiKind::Brush); + impl->logBrush.lbStyle = BS_HATCHED; + impl->logBrush.lbColor = c; + impl->logBrush.lbHatch = static_cast(index); + impl->brush = wxBrush(ToWxColour(c), HatchStyle(index)); + return RegisterGdiObject(impl); +} + +HGDIOBJ NewPatternBrush(HBITMAP hbm) { + GdiObjectImpl* bmp = GdiImpl(hbm, GdiKind::Bitmap); + if (!bmp || !bmp->bitmap.IsOk()) + return nullptr; + SyncBitmap(bmp); + auto* impl = NewImpl(GdiKind::Brush); + impl->logBrush.lbStyle = BS_PATTERN; + impl->logBrush.lbHatch = reinterpret_cast(hbm); + wxBitmap copy = bmp->bitmap.GetSubBitmap(wxRect(0, 0, bmp->bitmap.GetLogicalWidth(), bmp->bitmap.GetLogicalHeight())); + impl->brush = wxBrush(copy.IsOk() ? copy : bmp->bitmap); + return RegisterGdiObject(impl); +} + +HGDIOBJ NewBrushIndirect(const LOGBRUSH* lb) { + if (!lb) + return nullptr; + switch (lb->lbStyle) { + case BS_SOLID: + return NewSolidBrush(lb->lbColor); + case BS_HATCHED: + return NewHatchBrush(static_cast(lb->lbHatch), lb->lbColor); + case BS_PATTERN: + return NewPatternBrush(reinterpret_cast(lb->lbHatch)); + case BS_NULL: { + auto* impl = NewImpl(GdiKind::Brush); + impl->logBrush.lbStyle = BS_NULL; + impl->brush = *wxTRANSPARENT_BRUSH; + return RegisterGdiObject(impl); + } + default: + return NewSolidBrush(lb->lbColor); + } +} + +HGDIOBJ NewFont(const LOGFONT* lf) { + if (!lf) + return nullptr; + auto* impl = NewImpl(GdiKind::Font); + impl->logFont = *lf; + impl->logFont.lfFaceName[LF_FACESIZE - 1] = 0; + // Fonts created by static initializers wait for the toolkit, which GTK needs before any font query. + if (wxTheApp) + impl->font = MakeFont(impl->logFont, &impl->emPx); + else + impl->fontPending = true; + return RegisterGdiObject(impl); +} + +HGDIOBJ NewRegion(const wxRegion& r) { + auto* impl = NewImpl(GdiKind::Region); + impl->region = r; + return RegisterGdiObject(impl); +} + +wxRegion RectRegion(int x1, int y1, int x2, int y2) { + int l = std::min(x1, x2), r = std::max(x1, x2), t = std::min(y1, y2), b = std::max(y1, y2); + if (r <= l || b <= t) + return wxRegion(); + return wxRegion(l, t, r - l, b - t); +} + +wxRegion EllipseRegion(int x1, int y1, int x2, int y2) { + int l = std::min(x1, x2), r = std::max(x1, x2), t = std::min(y1, y2), b = std::max(y1, y2); + if (r <= l || b <= t) + return wxRegion(); + double cx = (l + r) / 2.0, cy = (t + b) / 2.0, rx = (r - l) / 2.0, ry = (b - t) / 2.0; + int n = std::max(16, static_cast(rx + ry)); + std::vector pts(n); + for (int i = 0; i < n; ++i) { + double a = 2 * M_PI * i / n; + pts[i] = wxPoint(static_cast(std::lround(cx + rx * cos(a))), static_cast(std::lround(cy + ry * sin(a)))); + } + return wxRegion(pts.size(), pts.data()); +} + +wxRegion RoundRectRegion(int x1, int y1, int x2, int y2, int w, int h) { + int l = std::min(x1, x2), r = std::max(x1, x2), t = std::min(y1, y2), b = std::max(y1, y2); + if (r <= l || b <= t) + return wxRegion(); + double rx = std::min(std::abs(w) / 2.0, (r - l) / 2.0), ry = std::min(std::abs(h) / 2.0, (b - t) / 2.0); + if (rx < 1 || ry < 1) + return wxRegion(l, t, r - l, b - t); + std::vector pts; + const double cxs[4] = {r - rx, l + rx, l + rx, r - rx}; + const double cys[4] = {t + ry, t + ry, b - ry, b - ry}; + int seg = std::max(4, static_cast((rx + ry) / 2)); + for (int q = 0; q < 4; ++q) { + for (int i = 0; i <= seg; ++i) { + double a = -M_PI / 2 * (q + static_cast(i) / seg); + pts.emplace_back(static_cast(std::lround(cxs[q] + rx * cos(a))), + static_cast(std::lround(cys[q] + ry * sin(a)))); + } + } + return wxRegion(pts.size(), pts.data()); +} + +int RegionType(const wxRegion& r) { + if (!r.IsOk() || r.IsEmpty()) + return NULLREGION; + int n = 0; + for (wxRegionIterator it(r); it && n < 2; ++it) + ++n; + return n <= 1 ? SIMPLEREGION : COMPLEXREGION; +} + +int GetObjectImpl(HGDIOBJ h, int c, void* pv) { + GdiLock lock; + int sys = SysColorBrushIndex(h); + if (sys >= 0) { + LOGBRUSH lb{BS_SOLID, SysColor(sys), 0}; + if (!pv) + return sizeof lb; + int n = std::min(c, sizeof lb); + memcpy(pv, &lb, static_cast(n)); + return n; + } + GdiObjectImpl* impl = GdiImpl(h); + if (!impl) + return 0; + const void* src = nullptr; + size_t size = 0; + BITMAP bm; + WORD entries = 0; + switch (impl->kind) { + case GdiKind::Pen: + src = &impl->logPen; + size = sizeof impl->logPen; + break; + case GdiKind::Brush: + src = &impl->logBrush; + size = sizeof impl->logBrush; + break; + case GdiKind::Font: + src = &impl->logFont; + size = sizeof impl->logFont; + break; + case GdiKind::Bitmap: { + memset(&bm, 0, sizeof bm); + if (impl->bitmap.IsOk()) { + bm.bmWidth = static_cast(std::lround(impl->bitmap.GetLogicalWidth())); + bm.bmHeight = static_cast(std::lround(impl->bitmap.GetLogicalHeight())); + } + bm.bmBitsPixel = static_cast(impl->bitsPixel); + bm.bmPlanes = 1; + bm.bmWidthBytes = ((bm.bmWidth * impl->bitsPixel + 15) / 16) * 2; + src = &bm; + size = sizeof bm; + break; + } + case GdiKind::Palette: + entries = 256; + src = &entries; + size = sizeof entries; + break; + case GdiKind::Region: + return 0; + } + if (!pv) + return static_cast(size); + int n = std::min(c, static_cast(size)); + if (n <= 0) + return 0; + memcpy(pv, src, static_cast(n)); + return n; +} + +} // namespace + +std::recursive_mutex& GdiMutex() { + static auto* m = new std::recursive_mutex; + return *m; +} + +double PixelsToPoints(double px) { return px * 72.0 / ScreenDpi(); } + +GdiObjectImpl* GdiImpl(HGDIOBJ h) { + if (!h || SysColorBrushIndex(h) >= 0) + return nullptr; + GdiLock lock; + auto* impl = reinterpret_cast(h); + return Objects().count(impl) ? impl : nullptr; +} + +GdiObjectImpl* GdiImpl(HGDIOBJ h, GdiKind kind) { + GdiObjectImpl* impl = GdiImpl(h); + return impl && impl->kind == kind ? impl : nullptr; +} + +HGDIOBJ RegisterGdiObject(GdiObjectImpl* impl) { + GdiLock lock; + Objects().insert(impl); + return reinterpret_cast(impl); +} + +void GdiAddRef(HGDIOBJ h) { + GdiLock lock; + if (GdiObjectImpl* impl = GdiImpl(h)) + if (!impl->stock) + ++impl->refs; +} + +void GdiRelease(HGDIOBJ h) { + GdiLock lock; + GdiObjectImpl* impl = GdiImpl(h); + if (!impl || impl->stock) + return; + if (--impl->refs <= 0) + FreeImpl(impl); +} + +int SysColorBrushIndex(HGDIOBJ h) { + auto v = reinterpret_cast(h); + return v >= 1 && v <= 31 ? static_cast(v) - 1 : -1; +} + +HGDIOBJ DefaultBitmapHandle() { return reinterpret_cast(Stock(kDefaultBitmapIndex)); } + +bool IsStockFont(HFONT h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Font); + return !impl || impl->stock; +} + +wxFont MakeFont(const LOGFONT& lfIn, double* emPx) { + LOGFONT lf = lfIn; + lf.lfFaceName[LF_FACESIZE - 1] = 0; + LONG height = lf.lfHeight; + if (height > 2000 || height < -2000) + height = 0; + wxString named; + FaceBase base = ResolveFace(FaceOf(lf), lf.lfPitchAndFamily, named); + wxFont f = BaseFont(base, named); + double em = height < 0 ? -static_cast(height) : (height > 0 ? height : GuiEmPixels()); + SetFontPixels(f, em); + LONG weight = lf.lfWeight; + if (weight > 0 && weight <= 1000) + f.SetNumericWeight(static_cast(weight)); + else + f.SetNumericWeight(wxFONTWEIGHT_NORMAL); + f.SetStyle(lf.lfItalic ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL); + f.SetUnderlined(lf.lfUnderline != 0); + f.SetStrikethrough(lf.lfStrikeOut != 0); + if (height > 0) { + GdiLock lock; + wxDC& dc = MeasureDC(); + dc.SetFont(f); + wxFontMetrics fm = dc.GetFontMetrics(); + int cell = fm.height - fm.externalLeading; + if (cell > 0) { + em = em * height / cell; + SetFontPixels(f, em); + } + } + if (emPx) + *emPx = em; + return f; +} + +wxPen DevicePen(HPEN h, double widthScale) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Pen); + if (!impl) + return *wxBLACK_PEN; + int style = static_cast(impl->penStyle & PS_STYLE_MASK); + if (style == PS_NULL) + return *wxTRANSPARENT_PEN; + bool geometric = (impl->penStyle & PS_GEOMETRIC) != 0; + int w = impl->logPen.lopnWidth.x; + int dw = w <= 0 ? 1 : std::max(1, static_cast(std::lround(w * widthScale))); + if (!geometric && dw > 1 && style >= PS_DASH && style <= PS_DASHDOTDOT) + style = PS_SOLID; + wxPen pen(ToWxColour(impl->logPen.lopnColor), dw, wxPENSTYLE_SOLID); + static const wxDash dash[] = {18, 6}, dot[] = {3, 3}, dashDot[] = {9, 6, 3, 6}, dashDotDot[] = {9, 3, 3, 3, 3, 3}, + alternate[] = {1, 1}; + bool dashed = true; + switch (style) { + case PS_DASH: + pen.SetDashes(2, dash); + break; + case PS_DOT: + pen.SetDashes(2, dot); + break; + case PS_DASHDOT: + pen.SetDashes(4, dashDot); + break; + case PS_DASHDOTDOT: + pen.SetDashes(6, dashDotDot); + break; + case PS_ALTERNATE: + pen.SetDashes(2, alternate); + break; + case PS_USERSTYLE: + if (!impl->dashes.empty()) { + pen.SetDashes(static_cast(impl->dashes.size()), InternDashes(impl->dashes)); + break; + } + dashed = false; + break; + default: + dashed = false; + break; + } + if (dashed) + pen.SetStyle(wxPENSTYLE_USER_DASH); + if (geometric) { + DWORD cap = impl->penStyle & 0x00000F00; + pen.SetCap(cap == PS_ENDCAP_SQUARE ? wxCAP_PROJECTING : cap == PS_ENDCAP_FLAT ? wxCAP_BUTT : wxCAP_ROUND); + DWORD join = impl->penStyle & 0x0000F000; + pen.SetJoin(join == PS_JOIN_BEVEL ? wxJOIN_BEVEL : join == PS_JOIN_MITER ? wxJOIN_MITER : wxJOIN_ROUND); + } else if (dw == 1) { + pen.SetCap(dashed ? wxCAP_BUTT : wxCAP_PROJECTING); + pen.SetJoin(wxJOIN_MITER); + } + return pen; +} + +wxBrush DeviceBrush(HBRUSH h) { + int sys = SysColorBrushIndex(h); + if (sys >= 0) + return wxBrush(ToWxColour(SysColor(sys))); + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Brush); + if (!impl) + return *wxTRANSPARENT_BRUSH; + if (impl->sysColor >= 0) { + COLORREF c = SysColor(impl->sysColor); + if (c != impl->logBrush.lbColor) { + impl->logBrush.lbColor = c; + impl->brush = wxBrush(ToWxColour(c)); + } + } + return impl->brush; +} + +void RealizeFont(GdiObjectImpl* impl) { + if (impl && impl->fontPending) { + impl->fontPending = false; + impl->font = MakeFont(impl->logFont, &impl->emPx); + } +} + +wxFont DeviceFont(HFONT h, double scale) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Font); + if (!impl) + impl = Stock(SYSTEM_FONT); + RealizeFont(impl); + if (impl->stock || std::fabs(scale - 1.0) < 1e-6 || scale <= 0) + return impl->font; + if (!impl->scaledFont.IsOk() || std::fabs(impl->scaledFor - scale) > 1e-6) { + impl->scaledFont = impl->font; + SetFontPixels(impl->scaledFont, impl->emPx * scale); + impl->scaledFor = scale; + } + return impl->scaledFont; +} + +double FontEmPixels(HFONT h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Font); + if (!impl) + impl = Stock(SYSTEM_FONT); + RealizeFont(impl); + return impl->emPx; +} + +bool BrushIsHatched(HBRUSH h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Brush); + return impl && impl->logBrush.lbStyle == BS_HATCHED; +} + +COLORREF BrushColor(HBRUSH h) { + int sys = SysColorBrushIndex(h); + if (sys >= 0) + return SysColor(sys); + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Brush); + if (!impl) + return 0; + if (impl->sysColor >= 0) + return SysColor(impl->sysColor); + return impl->logBrush.lbColor; +} + +bool PenIsNull(HPEN h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Pen); + return !impl || (impl->penStyle & PS_STYLE_MASK) == PS_NULL; +} + +int PenStyle(HPEN h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Pen); + return impl ? static_cast(impl->penStyle & PS_STYLE_MASK) : PS_SOLID; +} + +int PenWidth(HPEN h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Pen); + return impl ? std::max(1, impl->logPen.lopnWidth.x) : 1; +} + +COLORREF PenColor(HPEN h) { + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Pen); + return impl ? impl->logPen.lopnColor : 0; +} + +wxBitmap NewBitmap(int width, int height, double scale, const wxColour& fill) { + width = std::max(1, width); + height = std::max(1, height); + if (scale <= 0) + scale = 1; + int pw = std::max(1, static_cast(std::lround(width * scale))); + int ph = std::max(1, static_cast(std::lround(height * scale))); + wxImage img(pw, ph, false); + unsigned char* data = img.GetData(); + for (int i = 0; i < pw * ph; ++i) { + data[i * 3] = fill.Red(); + data[i * 3 + 1] = fill.Green(); + data[i * 3 + 2] = fill.Blue(); + } + return wxBitmap(img, -1, scale); +} + +HBITMAP NewBitmapHandle(const wxBitmap& bmp, int bitsPixel) { + if (!bmp.IsOk()) + return nullptr; + auto* impl = NewImpl(GdiKind::Bitmap); + impl->bitmap = bmp; + impl->bitsPixel = bitsPixel; + return RegisterGdiObject(impl); +} + +wxPen PenFromHandle(HPEN h) { + GdiLock lock; + return DevicePen(h, 1.0); +} + +wxBrush BrushFromHandle(HBRUSH h) { + GdiLock lock; + if (!h) + return wxNullBrush; + return DeviceBrush(h); +} + +wxFont FontFromHandle(HFONT h) { + GdiLock lock; + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Font); + RealizeFont(impl); + return impl ? impl->font : wxNullFont; +} + +wxBitmap* BitmapFromHandle(HBITMAP h) { + GdiLock lock; + GdiObjectImpl* impl = GdiImpl(h, GdiKind::Bitmap); + if (!impl || !impl->bitmap.IsOk()) + return nullptr; + SyncBitmap(impl); + return &impl->bitmap; +} + +HFONT DefaultGuiFont() { + GdiLock lock; + return reinterpret_cast(Stock(DEFAULT_GUI_FONT)); +} + +HBITMAP CreateBitmapHandle(const wxBitmap& bmp) { + GdiLock lock; + return NewBitmapHandle(bmp, bmp.IsOk() && bmp.GetDepth() == 1 ? 1 : 32); +} + +HFONT FontHandleFor(const wxFont& font) { + GdiLock lock; + if (!font.IsOk()) + return DefaultGuiFont(); + static auto* cache = new std::map; + wxString key = font.GetNativeFontInfoDesc(); + auto it = cache->find(key); + if (it != cache->end()) + return reinterpret_cast(it->second); + auto* impl = NewImpl(GdiKind::Font); + impl->font = font; +#ifdef __WXGTK__ + impl->emPx = font.GetPixelSize().y > 0 ? font.GetPixelSize().y : PointsToPixels(font.GetFractionalPointSize()); +#else + impl->emPx = PointsToPixels(font.GetFractionalPointSize()); +#endif + impl->logFont = LogFontFromWx(font, impl->emPx); + impl->stock = true; + Objects().insert(impl); + (*cache)[key] = impl; + return reinterpret_cast(impl); +} + +wxColour ToWxColour(COLORREF c) { + if (c == CLR_INVALID) + return wxTransparentColour; + if ((c & 0xFF000000) == 0x01000000) + return *wxBLACK; + return wxColour(GetRValue(c), GetGValue(c), GetBValue(c)); +} + +COLORREF FromWxColour(const wxColour& c) { + if (!c.IsOk()) + return 0; + return RGB(c.Red(), c.Green(), c.Blue()); +} + +COLORREF SysColor(int index) { + wxSystemColour sc; + if (WxSysColorIndex(index, sc)) { + wxColour c = wxSystemSettings::GetColour(sc); + if (c.IsOk() && c.IsSolid()) + return FromWxColour(c); + } + return FromWxColour(ClassicSysColor(index)); +} + +void PurgeTemporaryGdiWrappers() { + std::vector doomed; + { + GdiLock lock; + for (auto& kv : TempObjects()) { + kv.second->m_hObject = nullptr; + doomed.push_back(kv.second); + } + TempObjects().clear(); + doomed.insert(doomed.end(), DetachedTemps().begin(), DetachedTemps().end()); + DetachedTemps().clear(); + } + for (CGdiObject* o : doomed) + delete o; + PurgeTemporaryDCs(); +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CGdiObject and derived classes + +CGdiObject::CGdiObject() : m_hObject(nullptr) {} + +CGdiObject::~CGdiObject() { DeleteObject(); } + +CGdiObject* CGdiObject::FromHandle(HGDIOBJ hObject) { + if (!hObject) + return nullptr; + GdiLock lock; + GdiObjectImpl* impl = GdiImpl(hObject); + if (impl && impl->permanent) + return impl->permanent; + auto it = TempObjects().find(hObject); + if (it != TempObjects().end()) + return it->second; + CGdiObject* wrapper = nullptr; + if (impl) + wrapper = NewWrapper(impl->kind); + else if (SysColorBrushIndex(hObject) >= 0) + wrapper = new CBrush; + else + return nullptr; + wrapper->m_hObject = hObject; + TempObjects()[hObject] = wrapper; + return wrapper; +} + +BOOL CGdiObject::Attach(HGDIOBJ hObject) { + if (!hObject) + return FALSE; + GdiLock lock; + if (m_hObject && m_hObject != hObject) + DeleteObject(); + GdiObjectImpl* impl = GdiImpl(hObject); + if (!impl && SysColorBrushIndex(hObject) < 0) + return FALSE; + auto it = TempObjects().find(hObject); + if (it != TempObjects().end()) { + it->second->m_hObject = nullptr; + DetachedTemps().push_back(it->second); + TempObjects().erase(it); + } + if (impl) + impl->permanent = this; + m_hObject = hObject; + return TRUE; +} + +HGDIOBJ CGdiObject::Detach() { + if (AfxIsNullThis(this)) + return nullptr; + GdiLock lock; + HGDIOBJ h = m_hObject; + if (GdiObjectImpl* impl = GdiImpl(h)) + if (impl->permanent == this) + impl->permanent = nullptr; + m_hObject = nullptr; + return h; +} + +BOOL CGdiObject::DeleteObject() { + if (AfxIsNullThis(this) || !m_hObject) + return FALSE; + return ::DeleteObject(Detach()); +} + +int CGdiObject::GetObject(int nCount, LPVOID lpObject) const { return GetObjectImpl(m_hObject, nCount, lpObject); } + +BOOL CGdiObject::CreateStockObject(int nIndex) { return Attach(::GetStockObject(nIndex)); } + +CPen::CPen(int nPenStyle, int nWidth, COLORREF crColor) { CreatePen(nPenStyle, nWidth, crColor); } + +CPen::CPen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount, const DWORD* lpStyle) { + CreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle); +} + +BOOL CPen::CreatePen(int nPenStyle, int nWidth, COLORREF crColor) { + return Attach(::CreatePen(nPenStyle, nWidth, crColor)); +} + +BOOL CPen::CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount, const DWORD* lpStyle) { + GdiLock lock; + return Attach(NewPen(nPenStyle, nWidth, 0, pLogBrush, nStyleCount, lpStyle)); +} + +BOOL CPen::CreatePenIndirect(LPLOGPEN lpLogPen) { + if (!lpLogPen) + return FALSE; + return Attach(::CreatePen(static_cast(lpLogPen->lopnStyle), lpLogPen->lopnWidth.x, lpLogPen->lopnColor)); +} + +int CPen::GetLogPen(LOGPEN* pLogPen) { return GetObject(sizeof(LOGPEN), pLogPen); } + +CBrush::CBrush(COLORREF crColor) { CreateSolidBrush(crColor); } + +CBrush::CBrush(int nIndex, COLORREF crColor) { CreateHatchBrush(nIndex, crColor); } + +CBrush::CBrush(CBitmap* pBitmap) { CreatePatternBrush(pBitmap); } + +BOOL CBrush::CreateSolidBrush(COLORREF crColor) { return Attach(::CreateSolidBrush(crColor)); } + +BOOL CBrush::CreateHatchBrush(int nIndex, COLORREF crColor) { return Attach(::CreateHatchBrush(nIndex, crColor)); } + +BOOL CBrush::CreatePatternBrush(CBitmap* pBitmap) { + return pBitmap ? Attach(::CreatePatternBrush(pBitmap->m_hObject)) : FALSE; +} + +BOOL CBrush::CreateSysColorBrush(int nIndex) { + GdiLock lock; + auto* impl = new GdiObjectImpl(GdiKind::Brush); + impl->logBrush.lbStyle = BS_SOLID; + impl->logBrush.lbColor = SysColor(nIndex); + impl->sysColor = nIndex; + impl->brush = wxBrush(ToWxColour(impl->logBrush.lbColor)); + return Attach(RegisterGdiObject(impl)); +} + +BOOL CBrush::CreateBrushIndirect(const LOGBRUSH* lpLogBrush) { + GdiLock lock; + return Attach(NewBrushIndirect(lpLogBrush)); +} + +int CBrush::GetLogBrush(LOGBRUSH* pLogBrush) { return GetObject(sizeof(LOGBRUSH), pLogBrush); } + +BOOL CFont::CreateFontIndirect(const LOGFONT* lpLogFont) { return Attach(::CreateFontIndirect(lpLogFont)); } + +BOOL CFont::CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, + BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, + BYTE nQuality, BYTE nPitchAndFamily, const char* lpszFacename) { + return Attach(::CreateFont(nHeight, nWidth, nEscapement, nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, + nCharSet, nOutPrecision, nClipPrecision, nQuality, nPitchAndFamily, lpszFacename)); +} + +BOOL CFont::CreatePointFont(int nPointSize, const char* lpszFaceName, CDC* pDC) { + LOGFONT lf; + memset(&lf, 0, sizeof lf); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfHeight = nPointSize; + SetFace(lf, lpszFaceName); + return CreatePointFontIndirect(&lf, pDC); +} + +BOOL CFont::CreatePointFontIndirect(const LOGFONT* lpLogFont, CDC* pDC) { + if (!lpLogFont) + return FALSE; + LOGFONT lf = *lpLogFont; + GdiLock lock; + DCState* s = pDC ? DCFromHandle(pDC->m_hAttribDC ? pDC->m_hAttribDC : pDC->m_hDC) : nullptr; + int dpi = s ? s->Dpi() : 96; + double py = static_cast(dpi) * lf.lfHeight / 720.0; + if (s) { + double x0 = 0, y0 = 0, x1 = 0, y1 = py; + s->ToLogical(x0, y0); + s->ToLogical(x1, y1); + py = y1 - y0; + } + lf.lfHeight = -static_cast(std::lround(std::fabs(py))); + return CreateFontIndirect(&lf); +} + +int CFont::GetLogFont(LOGFONT* pLogFont) { return GetObject(sizeof(LOGFONT), pLogFont); } + +BOOL CRgn::CreateRectRgn(int x1, int y1, int x2, int y2) { return Attach(::CreateRectRgn(x1, y1, x2, y2)); } + +BOOL CRgn::CreateRectRgnIndirect(LPCRECT lpRect) { + return lpRect ? CreateRectRgn(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom) : FALSE; +} + +BOOL CRgn::CreateEllipticRgn(int x1, int y1, int x2, int y2) { return Attach(::CreateEllipticRgn(x1, y1, x2, y2)); } + +BOOL CRgn::CreateEllipticRgnIndirect(LPCRECT lpRect) { + return lpRect ? CreateEllipticRgn(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom) : FALSE; +} + +BOOL CRgn::CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode) { + if (!lpPoints || nCount < 3) + return FALSE; + std::vector pts; + for (int i = 0; i < nCount; ++i) + pts.emplace_back(lpPoints[i].x, lpPoints[i].y); + GdiLock lock; + return Attach(NewRegion(wxRegion(pts.size(), pts.data(), nMode == WINDING ? wxWINDING_RULE : wxODDEVEN_RULE))); +} + +BOOL CRgn::CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3) { + GdiLock lock; + return Attach(NewRegion(RoundRectRegion(x1, y1, x2, y2, x3, y3))); +} + +int CRgn::CombineRgn(CRgn* pRgn1, CRgn* pRgn2, int nCombineMode) { + GdiLock lock; + GdiObjectImpl* self = GdiImpl(m_hObject, GdiKind::Region); + GdiObjectImpl* a = pRgn1 ? GdiImpl(pRgn1->m_hObject, GdiKind::Region) : nullptr; + GdiObjectImpl* b = pRgn2 ? GdiImpl(pRgn2->m_hObject, GdiKind::Region) : nullptr; + if (!self || !a) + return ERROR; + wxRegion r = a->region; + wxRegion other = b ? b->region : wxRegion(); + bool aEmpty = !r.IsOk() || r.IsEmpty(); + bool bEmpty = !other.IsOk() || other.IsEmpty(); + switch (nCombineMode) { + case RGN_AND: + if (aEmpty || bEmpty) + r = wxRegion(); + else + r.Intersect(other); + break; + case RGN_OR: + if (aEmpty) + r = other; + else if (!bEmpty) + r.Union(other); + break; + case RGN_XOR: + if (aEmpty) + r = other; + else if (!bEmpty) + r.Xor(other); + break; + case RGN_DIFF: + if (!aEmpty && !bEmpty) + r.Subtract(other); + break; + case RGN_COPY: + break; + default: + return ERROR; + } + self->region = r; + return RegionType(self->region); +} + +int CRgn::CopyRgn(CRgn* pRgnSrc) { return CombineRgn(pRgnSrc, nullptr, RGN_COPY); } + +BOOL CRgn::PtInRegion(int x, int y) const { + GdiLock lock; + GdiObjectImpl* self = GdiImpl(m_hObject, GdiKind::Region); + return self && self->region.IsOk() && !self->region.IsEmpty() && self->region.Contains(x, y) == wxInRegion; +} + +BOOL CRgn::RectInRegion(LPCRECT lpRect) const { + GdiLock lock; + GdiObjectImpl* self = GdiImpl(m_hObject, GdiKind::Region); + if (!self || !lpRect || !self->region.IsOk() || self->region.IsEmpty()) + return FALSE; + wxRect r(lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top); + return r.width > 0 && r.height > 0 && self->region.Contains(r) != wxOutRegion; +} + +int CRgn::GetRgnBox(LPRECT lpRect) const { + GdiLock lock; + GdiObjectImpl* self = GdiImpl(m_hObject, GdiKind::Region); + if (!self || !lpRect) + return ERROR; + wxRect b = self->region.IsOk() ? self->region.GetBox() : wxRect(); + lpRect->left = b.x; + lpRect->top = b.y; + lpRect->right = b.x + b.width; + lpRect->bottom = b.y + b.height; + return RegionType(self->region); +} + +void CRgn::SetRectRgn(int x1, int y1, int x2, int y2) { + GdiLock lock; + if (GdiObjectImpl* self = GdiImpl(m_hObject, GdiKind::Region)) + self->region = RectRegion(x1, y1, x2, y2); +} + +int CRgn::OffsetRgn(int x, int y) { + GdiLock lock; + GdiObjectImpl* self = GdiImpl(m_hObject, GdiKind::Region); + if (!self) + return ERROR; + if (self->region.IsOk() && !self->region.IsEmpty()) + self->region.Offset(x, y); + return RegionType(self->region); +} + +// --------------------------------------------------------------------------------------------- +// Win32 object functions + +HGDIOBJ GetStockObject(int i) { + GdiLock lock; + if (i == kDefaultBitmapIndex || i == 9) + return nullptr; + return reinterpret_cast(Stock(i)); +} + +BOOL DeleteObject(HGDIOBJ ho) { + GdiLock lock; + GdiObjectImpl* impl = GdiImpl(ho); + if (!impl) + return SysColorBrushIndex(ho) >= 0; + if (impl->stock) + return TRUE; + if (impl->deleted) + return FALSE; + impl->deleted = true; + DetachWrappers(impl); + GdiRelease(ho); + return TRUE; +} + +int GetObject(HANDLE h, int c, LPVOID pv) { return GetObjectImpl(reinterpret_cast(h), c, pv); } + +int GetObjectA(HANDLE h, int c, LPVOID pv) { return GetObjectImpl(reinterpret_cast(h), c, pv); } + +HBRUSH CreateSolidBrush(COLORREF color) { + GdiLock lock; + return NewSolidBrush(color); +} + +HBRUSH CreateHatchBrush(int iHatch, COLORREF color) { + GdiLock lock; + return NewHatchBrush(iHatch, color); +} + +HBRUSH CreatePatternBrush(HBITMAP hbm) { + GdiLock lock; + return NewPatternBrush(hbm); +} + +HPEN CreatePen(int iStyle, int cWidth, COLORREF color) { + GdiLock lock; + return NewPen(iStyle, cWidth, color, nullptr, 0, nullptr); +} + +HFONT CreateFont(int cHeight, int cWidth, int cEscapement, int cOrientation, int cWeight, DWORD bItalic, + DWORD bUnderline, DWORD bStrikeOut, DWORD iCharSet, DWORD iOutPrecision, DWORD iClipPrecision, + DWORD iQuality, DWORD iPitchAndFamily, const char* pszFaceName) { + LOGFONT lf; + memset(&lf, 0, sizeof lf); + lf.lfHeight = cHeight; + lf.lfWidth = cWidth; + lf.lfEscapement = cEscapement; + lf.lfOrientation = cOrientation; + lf.lfWeight = cWeight; + lf.lfItalic = static_cast(bItalic != 0); + lf.lfUnderline = static_cast(bUnderline != 0); + lf.lfStrikeOut = static_cast(bStrikeOut != 0); + lf.lfCharSet = static_cast(iCharSet); + lf.lfOutPrecision = static_cast(iOutPrecision); + lf.lfClipPrecision = static_cast(iClipPrecision); + lf.lfQuality = static_cast(iQuality); + lf.lfPitchAndFamily = static_cast(iPitchAndFamily); + SetFace(lf, pszFaceName); + return CreateFontIndirect(&lf); +} + +HFONT CreateFontA(int cHeight, int cWidth, int cEscapement, int cOrientation, int cWeight, DWORD bItalic, + DWORD bUnderline, DWORD bStrikeOut, DWORD iCharSet, DWORD iOutPrecision, DWORD iClipPrecision, + DWORD iQuality, DWORD iPitchAndFamily, const char* pszFaceName) { + return CreateFont(cHeight, cWidth, cEscapement, cOrientation, cWeight, bItalic, bUnderline, bStrikeOut, iCharSet, + iOutPrecision, iClipPrecision, iQuality, iPitchAndFamily, pszFaceName); +} + +HFONT CreateFontIndirect(const LOGFONT* lplf) { + GdiLock lock; + return NewFont(lplf); +} + +HFONT CreateFontIndirectA(const LOGFONT* lplf) { return CreateFontIndirect(lplf); } + +HRGN CreateRectRgn(int x1, int y1, int x2, int y2) { + GdiLock lock; + return NewRegion(RectRegion(x1, y1, x2, y2)); +} + +HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2) { + GdiLock lock; + return NewRegion(EllipseRegion(x1, y1, x2, y2)); +} + +DWORD GetSysColor(int nIndex) { return SysColor(nIndex); } + +HBRUSH GetSysColorBrush(int nIndex) { + GdiLock lock; + static std::map brushes; + GdiObjectImpl*& impl = brushes[nIndex]; + if (!impl) { + impl = new GdiObjectImpl(GdiKind::Brush); + impl->stock = true; + impl->sysColor = nIndex; + impl->logBrush.lbStyle = BS_SOLID; + impl->logBrush.lbColor = SysColor(nIndex); + impl->brush = wxBrush(ToWxColour(impl->logBrush.lbColor)); + Objects().insert(impl); + } + DeviceBrush(reinterpret_cast(impl)); + return reinterpret_cast(impl); +} + +// --------------------------------------------------------------------------------------------- +// Rectangles + +BOOL SetRect(LPRECT lprc, int xLeft, int yTop, int xRight, int yBottom) { + if (!lprc) + return FALSE; + lprc->left = xLeft; + lprc->top = yTop; + lprc->right = xRight; + lprc->bottom = yBottom; + return TRUE; +} + +BOOL SetRectEmpty(LPRECT lprc) { return SetRect(lprc, 0, 0, 0, 0); } + +BOOL CopyRect(LPRECT lprcDst, const RECT* lprcSrc) { + if (!lprcDst || !lprcSrc) + return FALSE; + *lprcDst = *lprcSrc; + return TRUE; +} + +BOOL InflateRect(LPRECT lprc, int dx, int dy) { + if (!lprc) + return FALSE; + lprc->left -= dx; + lprc->right += dx; + lprc->top -= dy; + lprc->bottom += dy; + return TRUE; +} + +BOOL OffsetRect(LPRECT lprc, int dx, int dy) { + if (!lprc) + return FALSE; + lprc->left += dx; + lprc->right += dx; + lprc->top += dy; + lprc->bottom += dy; + return TRUE; +} + +BOOL IsRectEmpty(const RECT* lprc) { return !lprc || lprc->left >= lprc->right || lprc->top >= lprc->bottom; } + +BOOL IntersectRect(LPRECT lprcDst, const RECT* lprcSrc1, const RECT* lprcSrc2) { + if (!lprcDst || !lprcSrc1 || !lprcSrc2) + return FALSE; + RECT r; + r.left = std::max(lprcSrc1->left, lprcSrc2->left); + r.top = std::max(lprcSrc1->top, lprcSrc2->top); + r.right = std::min(lprcSrc1->right, lprcSrc2->right); + r.bottom = std::min(lprcSrc1->bottom, lprcSrc2->bottom); + if (IsRectEmpty(&r)) { + SetRectEmpty(lprcDst); + return FALSE; + } + *lprcDst = r; + return TRUE; +} + +BOOL UnionRect(LPRECT lprcDst, const RECT* lprcSrc1, const RECT* lprcSrc2) { + if (!lprcDst || !lprcSrc1 || !lprcSrc2) + return FALSE; + bool e1 = IsRectEmpty(lprcSrc1), e2 = IsRectEmpty(lprcSrc2); + if (e1 && e2) { + SetRectEmpty(lprcDst); + return FALSE; + } + if (e1) { + *lprcDst = *lprcSrc2; + return TRUE; + } + if (e2) { + *lprcDst = *lprcSrc1; + return TRUE; + } + RECT r; + r.left = std::min(lprcSrc1->left, lprcSrc2->left); + r.top = std::min(lprcSrc1->top, lprcSrc2->top); + r.right = std::max(lprcSrc1->right, lprcSrc2->right); + r.bottom = std::max(lprcSrc1->bottom, lprcSrc2->bottom); + *lprcDst = r; + return TRUE; +} + +BOOL PtInRect(const RECT* lprc, POINT pt) { + return lprc && pt.x >= lprc->left && pt.x < lprc->right && pt.y >= lprc->top && pt.y < lprc->bottom; +} + +BOOL EqualRect(const RECT* lprc1, const RECT* lprc2) { + return lprc1 && lprc2 && lprc1->left == lprc2->left && lprc1->top == lprc2->top && + lprc1->right == lprc2->right && lprc1->bottom == lprc2->bottom; +} diff --git a/port/mfcwx/src/gdi_bits.cpp b/port/mfcwx/src/gdi_bits.cpp new file mode 100644 index 000000000..b4b227d4a --- /dev/null +++ b/port/mfcwx/src/gdi_bits.cpp @@ -0,0 +1,794 @@ +#include "gdi_internal.h" + +#include +#include +#include +#include + +namespace mfcwx { + +namespace { + +unsigned char Rop3Channel(unsigned rop3, unsigned char p, unsigned char s, unsigned char d) { + unsigned out = 0; + for (unsigned k = 0; k < 8; ++k) { + if (!((rop3 >> k) & 1)) + continue; + unsigned pm = (k & 4) ? p : static_cast(~p); + unsigned sm = (k & 2) ? s : static_cast(~s); + unsigned dm = (k & 1) ? d : static_cast(~d); + out |= pm & sm & dm & 0xFF; + } + return static_cast(out); +} + +bool RopUsesSource(DWORD rop) { + unsigned r = (rop >> 16) & 0xFF; + return ((r >> 2) & 0x33) != (r & 0x33); +} + +wxImage Opaque(wxImage img) { + if (img.HasAlpha()) + img.ClearAlpha(); + return img; +} + +wxRect PhysicalRect(const wxRect& r, double scale) { + return wxRect(static_cast(std::lround(r.x * scale)), static_cast(std::lround(r.y * scale)), + static_cast(std::lround(r.width * scale)), static_cast(std::lround(r.height * scale))); +} + +double TargetScale(DCState* s, wxDC* d) { + if (s->kind == DCKind::Memory) + return DCBitmapScale(s); + double scale = d ? d->GetContentScaleFactor() : 1.0; + return scale > 0 ? scale : 1.0; +} + +bool SourceImage(DCState* src, const wxRect& S, wxImage& out) { + if (!src || S.width <= 0 || S.height <= 0) + return false; + if (const wxImage* px = DCPixels(src)) { + double scale = DCBitmapScale(src); + wxRect P = PhysicalRect(S, scale); + wxRect clipped = P; + clipped.Intersect(wxRect(0, 0, px->GetWidth(), px->GetHeight())); + out = wxImage(std::max(1, P.width), std::max(1, P.height), true); + if (!clipped.IsEmpty()) + out.Paste(px->GetSubImage(clipped), clipped.x - P.x, clipped.y - P.y); + return true; + } + wxDC* d = src->Target(false); + if (!d) + return false; + wxBitmap b = d->GetAsBitmap(&S); + if (!b.IsOk()) + return false; + out = b.ConvertToImage(); + return out.IsOk(); +} + +void FitImage(wxImage& img, int w, int h, bool mirrorX, bool mirrorY, bool smooth) { + if (mirrorX) + img = img.Mirror(true); + if (mirrorY) + img = img.Mirror(false); + if (img.GetWidth() != w || img.GetHeight() != h) + img.Rescale(std::max(1, w), std::max(1, h), smooth ? wxIMAGE_QUALITY_BILINEAR : wxIMAGE_QUALITY_NEAREST); +} + +void Invert(wxImage& img) { + unsigned char* p = img.GetData(); + size_t n = static_cast(img.GetWidth()) * img.GetHeight() * 3; + for (size_t i = 0; i < n; ++i) + p[i] = static_cast(255 - p[i]); +} + +void DrawImageAt(wxDC* d, wxImage img, const wxRect& D, double scale) { + d->DrawBitmap(wxBitmap(Opaque(img), -1, scale), D.x, D.y, false); +} + +void DrawMasked(wxDC* d, wxImage img, const wxRect& D, double scale, unsigned char key) { + img = Opaque(img); + img.SetMaskColour(key, key, key); + d->DrawBitmap(wxBitmap(img, -1, scale), D.x, D.y, true); +} + +bool BlitImage(DCState* dst, wxDC* d, const wxRect& D, wxImage img, DWORD rop) { + double scale = TargetScale(dst, d); + switch (rop) { + case SRCCOPY: + DrawImageAt(d, img, D, scale); + return true; + case NOTSRCCOPY: + Invert(img); + DrawImageAt(d, img, D, scale); + return true; + default: + break; + } + if (dst->kind == DCKind::Memory) + return SoftwareRop(dst, D, &img, rop, BrushColor(dst->a.brush)); + switch (rop) { + case SRCAND: + DrawMasked(d, img, D, scale, 255); + return true; + case SRCPAINT: + case SRCINVERT: + DrawMasked(d, img, D, scale, 0); + return true; + case MERGEPAINT: + Invert(img); + DrawMasked(d, img, D, scale, 0); + return true; + case NOTSRCERASE: + Invert(img); + DrawImageAt(d, img, D, scale); + return true; + default: + DrawImageAt(d, img, D, scale); + return true; + } +} + +bool PatternOnly(DCState* dst, wxDC* d, const wxRect& D, DWORD rop) { + switch (rop) { + case BLACKNESS: + FillDeviceRectColor(d, D, *wxBLACK); + return true; + case WHITENESS: + FillDeviceRectColor(d, D, *wxWHITE); + return true; + case PATCOPY: + FillDeviceRect(dst, d, D, dst->a.brush); + return true; + default: + break; + } + if (rop == 0x00AA0029UL) + return true; + if (dst->kind == DCKind::Memory) + return SoftwareRop(dst, D, nullptr, rop, BrushColor(dst->a.brush)); + if (dst->SupportsLogicalOps(d)) { + wxRasterOperationMode mode = rop == DSTINVERT ? wxINVERT : wxXOR; + d->SetLogicalFunction(mode); + d->SetPen(*wxTRANSPARENT_PEN); + d->SetBrush(rop == DSTINVERT ? *wxBLACK_BRUSH : DeviceBrush(dst->a.brush)); + d->DrawRectangle(D); + d->SetLogicalFunction(wxCOPY); + return true; + } + return false; +} + +int MaskShift(DWORD mask) { + int s = 0; + if (!mask) + return 0; + while (!(mask & 1)) { + mask >>= 1; + ++s; + } + return s; +} + +unsigned char MaskValue(DWORD v, DWORD mask) { + if (!mask) + return 0; + int shift = MaskShift(mask); + DWORD m = mask >> shift; + DWORD x = (v & mask) >> shift; + return static_cast(m ? x * 255 / m : 0); +} + +int FloodImpl(DCState* s, int x, int y, COLORREF crColor, UINT type) { + const wxImage* px = DCPixels(s); + if (!px) + return FALSE; + double scale = DCBitmapScale(s); + wxPoint dp = s->ToDevice(x, y); + int sx = static_cast(std::lround(dp.x * scale)), sy = static_cast(std::lround(dp.y * scale)); + int w = px->GetWidth(), h = px->GetHeight(); + if (sx < 0 || sy < 0 || sx >= w || sy >= h) + return FALSE; + const unsigned char* data = px->GetData(); + auto colorAt = [&](int ix, int iy) { + const unsigned char* p = data + (static_cast(iy) * w + ix) * 3; + return RGB(p[0], p[1], p[2]); + }; + COLORREF target = crColor & 0xFFFFFF; + auto inside = [&](int ix, int iy) { + COLORREF c = colorAt(ix, iy); + return type == 1 ? c == target : c != target; + }; + if (!inside(sx, sy)) + return FALSE; + std::vector mask(static_cast(w) * h, 0); + std::vector stack{wxPoint(sx, sy)}; + int minX = sx, maxX = sx, minY = sy, maxY = sy; + while (!stack.empty()) { + wxPoint p = stack.back(); + stack.pop_back(); + if (p.x < 0 || p.y < 0 || p.x >= w || p.y >= h) + continue; + size_t i = static_cast(p.y) * w + p.x; + if (mask[i] || !inside(p.x, p.y)) + continue; + mask[i] = 1; + minX = std::min(minX, p.x); + maxX = std::max(maxX, p.x); + minY = std::min(minY, p.y); + maxY = std::max(maxY, p.y); + stack.emplace_back(p.x + 1, p.y); + stack.emplace_back(p.x - 1, p.y); + stack.emplace_back(p.x, p.y + 1); + stack.emplace_back(p.x, p.y - 1); + } + wxRect box(minX, minY, maxX - minX + 1, maxY - minY + 1); + wxImage sub = Opaque(px->GetSubImage(box)); + wxColour fill = DeviceBrush(s->a.brush).GetColour(); + unsigned char* out = sub.GetData(); + for (int iy = 0; iy < box.height; ++iy) + for (int ix = 0; ix < box.width; ++ix) + if (mask[static_cast(iy + box.y) * w + ix + box.x]) { + unsigned char* q = out + (static_cast(iy) * box.width + ix) * 3; + q[0] = fill.Red(); + q[1] = fill.Green(); + q[2] = fill.Blue(); + } + DrawScope ds(s); + if (!ds) + return FALSE; + ds.dc()->DestroyClippingRegion(); + s->ApplyClip(ds.dc()); + ds.dc()->DrawBitmap(wxBitmap(sub, -1, scale), static_cast(std::lround(box.x / scale)), + static_cast(std::lround(box.y / scale)), false); + return TRUE; +} + +GdiObjectImpl* BitmapImpl(HGDIOBJ h) { return GdiImpl(h, GdiKind::Bitmap); } + +} // namespace + +bool SoftwareRop(DCState* dst, const wxRect& r, const wxImage* src, DWORD rop, COLORREF pattern) { + const wxImage* px = DCPixels(dst); + if (!px) + return false; + double scale = DCBitmapScale(dst); + wxRect P = PhysicalRect(r, scale); + wxRect clipped = P; + clipped.Intersect(wxRect(0, 0, px->GetWidth(), px->GetHeight())); + if (clipped.IsEmpty()) + return true; + wxImage out = Opaque(px->GetSubImage(clipped)); + unsigned rop3 = (rop >> 16) & 0xFF; + unsigned char pr = GetRValue(pattern), pg = GetGValue(pattern), pb = GetBValue(pattern); + unsigned char* o = out.GetData(); + const unsigned char* sp = src ? src->GetData() : nullptr; + int sw = src ? src->GetWidth() : 0, sh = src ? src->GetHeight() : 0; + for (int y = 0; y < clipped.height; ++y) { + for (int x = 0; x < clipped.width; ++x) { + unsigned char* q = o + (static_cast(y) * clipped.width + x) * 3; + unsigned char s0 = 0, s1 = 0, s2 = 0; + int ix = x + clipped.x - P.x, iy = y + clipped.y - P.y; + if (sp && ix < sw && iy < sh) { + const unsigned char* t = sp + (static_cast(iy) * sw + ix) * 3; + s0 = t[0]; + s1 = t[1]; + s2 = t[2]; + } + q[0] = Rop3Channel(rop3, pr, s0, q[0]); + q[1] = Rop3Channel(rop3, pg, s1, q[1]); + q[2] = Rop3Channel(rop3, pb, s2, q[2]); + } + } + DrawScope ds(dst); + if (!ds) + return false; + ds.dc()->DrawBitmap(wxBitmap(out, -1, scale), static_cast(std::lround(clipped.x / scale)), + static_cast(std::lround(clipped.y / scale)), false); + return true; +} + +bool BlitImpl(DCState* dst, int x, int y, int w, int h, DCState* src, int xs, int ys, int ws, int hs, DWORD rop) { + if (!dst) + return false; + wxPoint p1 = dst->ToDevice(x, y), p2 = dst->ToDevice(x + w, y + h); + wxRect D(std::min(p1.x, p2.x), std::min(p1.y, p2.y), std::abs(p2.x - p1.x), std::abs(p2.y - p1.y)); + if (D.width <= 0 || D.height <= 0) + return true; + DrawScope ds(dst); + if (!ds) + return true; + wxDC* d = ds.dc(); + if (!RopUsesSource(rop)) + return PatternOnly(dst, d, D, rop); + if (!src) + return false; + wxPoint q1 = src->ToDevice(xs, ys), q2 = src->ToDevice(xs + ws, ys + hs); + wxRect S(std::min(q1.x, q2.x), std::min(q1.y, q2.y), std::abs(q2.x - q1.x), std::abs(q2.y - q1.y)); + if (S.width <= 0 || S.height <= 0) + return true; + bool mirrorX = (p2.x < p1.x) != (q2.x < q1.x); + bool mirrorY = (p2.y < p1.y) != (q2.y < q1.y); + if (rop == SRCCOPY && !mirrorX && !mirrorY && src->kind != DCKind::Memory) { + wxDC* sd = src->Target(false); + if (sd && d->StretchBlit(D.x, D.y, D.width, D.height, sd, S.x, S.y, S.width, S.height, wxCOPY)) + return true; + } + wxImage img; + if (!SourceImage(src, S, img)) + return false; + double scale = TargetScale(dst, d); + wxRect PD = PhysicalRect(D, scale); + bool smooth = dst->a.stretchMode == HALFTONE && (S.width != D.width || S.height != D.height); + FitImage(img, PD.width, PD.height, mirrorX, mirrorY, smooth); + return BlitImage(dst, d, D, img, rop); +} + +bool DrawImageImpl(DCState* dst, int x, int y, int w, int h, const wxImage& src, int xs, int ys, int ws, int hs, + DWORD rop) { + if (!dst || !src.IsOk() || ws == 0 || hs == 0) + return false; + wxPoint p1 = dst->ToDevice(x, y), p2 = dst->ToDevice(x + w, y + h); + wxRect D(std::min(p1.x, p2.x), std::min(p1.y, p2.y), std::abs(p2.x - p1.x), std::abs(p2.y - p1.y)); + if (D.width <= 0 || D.height <= 0) + return true; + DrawScope ds(dst); + if (!ds) + return true; + wxDC* d = ds.dc(); + if (!RopUsesSource(rop)) + return PatternOnly(dst, d, D, rop); + wxRect S(std::min(xs, xs + ws), std::min(ys, ys + hs), std::abs(ws), std::abs(hs)); + wxRect clipped = S; + clipped.Intersect(wxRect(0, 0, src.GetWidth(), src.GetHeight())); + wxImage img(S.width, S.height, true); + if (!clipped.IsEmpty()) + img.Paste(src.GetSubImage(clipped), clipped.x - S.x, clipped.y - S.y); + bool mirrorX = (p2.x < p1.x) != (ws < 0); + bool mirrorY = (p2.y < p1.y) != (hs < 0); + double scale = TargetScale(dst, d); + wxRect PD = PhysicalRect(D, scale); + bool smooth = dst->a.stretchMode == HALFTONE; + FitImage(img, PD.width, PD.height, mirrorX, mirrorY, smooth); + return BlitImage(dst, d, D, img, rop); +} + +bool DibToImage(const BITMAPINFO* bmi, const void* bits, UINT usage, wxImage& out, int startScan, int lines) { + if (!bmi || !bits) + return false; + const BITMAPINFOHEADER& hdr = bmi->bmiHeader; + int w = hdr.biWidth, h = std::abs(hdr.biHeight), bpp = hdr.biBitCount; + bool bottomUp = hdr.biHeight > 0; + if (w <= 0 || h <= 0 || (hdr.biCompression != BI_RGB && hdr.biCompression != 3)) + return false; + if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) + return false; + const unsigned char* base = reinterpret_cast(bmi) + hdr.biSize; + DWORD masks[3] = {0, 0, 0}; + if (hdr.biCompression == 3) { + memcpy(masks, base, sizeof masks); + } else if (bpp == 16) { + masks[0] = 0x7C00; + masks[1] = 0x03E0; + masks[2] = 0x001F; + } else if (bpp == 32) { + masks[0] = 0x00FF0000; + masks[1] = 0x0000FF00; + masks[2] = 0x000000FF; + } + const RGBQUAD* palette = reinterpret_cast(base); + int paletteSize = bpp <= 8 ? static_cast(hdr.biClrUsed ? hdr.biClrUsed : (1u << bpp)) : 0; + int stride = ((w * bpp + 31) / 32) * 4; + if (lines < 0) + lines = h; + out.Create(w, h, true); + unsigned char* data = out.GetData(); + const unsigned char* src = static_cast(bits); + for (int i = 0; i < lines; ++i) { + int dibRow = startScan + i; + if (dibRow < 0 || dibRow >= h) + continue; + int iy = bottomUp ? h - 1 - dibRow : dibRow; + const unsigned char* row = src + static_cast(i) * stride; + unsigned char* dstRow = data + static_cast(iy) * w * 3; + for (int x = 0; x < w; ++x) { + unsigned char r = 0, g = 0, b = 0; + if (bpp <= 8) { + int index = 0; + if (bpp == 1) + index = (row[x >> 3] >> (7 - (x & 7))) & 1; + else if (bpp == 4) + index = (row[x >> 1] >> ((x & 1) ? 0 : 4)) & 0xF; + else + index = row[x]; + if (usage == DIB_RGB_COLORS && index < paletteSize) { + r = palette[index].rgbRed; + g = palette[index].rgbGreen; + b = palette[index].rgbBlue; + } else { + r = g = b = static_cast(bpp == 1 ? index * 255 : bpp == 4 ? index * 17 : index); + } + } else if (bpp == 24) { + b = row[x * 3]; + g = row[x * 3 + 1]; + r = row[x * 3 + 2]; + } else { + DWORD v = bpp == 16 ? static_cast(row[x * 2] | (row[x * 2 + 1] << 8)) + : static_cast(row[x * 4] | (row[x * 4 + 1] << 8) | + (row[x * 4 + 2] << 16) | + (static_cast(row[x * 4 + 3]) << 24)); + r = MaskValue(v, masks[0]); + g = MaskValue(v, masks[1]); + b = MaskValue(v, masks[2]); + } + dstRow[x * 3] = r; + dstRow[x * 3 + 1] = g; + dstRow[x * 3 + 2] = b; + } + } + return true; +} + +bool DdbBitsToImage(int width, int height, int bpp, int stride, const void* bits, wxImage& out) { + if (width <= 0 || height <= 0) + return false; + out.Create(width, height, true); + if (!bits) + return true; + const unsigned char* src = static_cast(bits); + unsigned char* data = out.GetData(); + for (int y = 0; y < height; ++y) { + const unsigned char* row = src + static_cast(y) * stride; + unsigned char* d = data + static_cast(y) * width * 3; + for (int x = 0; x < width; ++x) { + unsigned char r = 0, g = 0, b = 0; + switch (bpp) { + case 1: + r = g = b = ((row[x >> 3] >> (7 - (x & 7))) & 1) ? 255 : 0; + break; + case 4: + r = g = b = static_cast(((row[x >> 1] >> ((x & 1) ? 0 : 4)) & 0xF) * 17); + break; + case 8: + r = g = b = row[x]; + break; + case 16: { + unsigned v = row[x * 2] | (row[x * 2 + 1] << 8); + r = static_cast(((v >> 10) & 31) * 255 / 31); + g = static_cast(((v >> 5) & 31) * 255 / 31); + b = static_cast((v & 31) * 255 / 31); + break; + } + case 24: + b = row[x * 3]; + g = row[x * 3 + 1]; + r = row[x * 3 + 2]; + break; + default: + b = row[x * 4]; + g = row[x * 4 + 1]; + r = row[x * 4 + 2]; + break; + } + d[x * 3] = r; + d[x * 3 + 1] = g; + d[x * 3 + 2] = b; + } + } + return true; +} + +bool ImageToDdbBits(const wxImage& img, int bpp, std::vector& out, int& stride) { + int w = img.GetWidth(), h = img.GetHeight(); + if (w <= 0 || h <= 0) + return false; + stride = ((w * bpp + 15) / 16) * 2; + out.assign(static_cast(stride) * h, 0); + const unsigned char* data = img.GetData(); + for (int y = 0; y < h; ++y) { + unsigned char* row = out.data() + static_cast(y) * stride; + const unsigned char* s = data + static_cast(y) * w * 3; + for (int x = 0; x < w; ++x) { + unsigned char r = s[x * 3], g = s[x * 3 + 1], b = s[x * 3 + 2]; + unsigned gray = (r * 30u + g * 59u + b * 11u) / 100u; + switch (bpp) { + case 1: + if (gray >= 128) + row[x >> 3] |= static_cast(0x80 >> (x & 7)); + break; + case 4: + row[x >> 1] |= static_cast((gray / 17) << ((x & 1) ? 0 : 4)); + break; + case 8: + row[x] = static_cast(gray); + break; + case 16: { + unsigned v = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); + row[x * 2] = static_cast(v & 0xFF); + row[x * 2 + 1] = static_cast(v >> 8); + break; + } + case 24: + row[x * 3] = b; + row[x * 3 + 1] = g; + row[x * 3 + 2] = r; + break; + default: + row[x * 4] = b; + row[x * 4 + 1] = g; + row[x * 4 + 2] = r; + row[x * 4 + 3] = 0; + break; + } + } + } + return true; +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CBitmap + +BOOL CBitmap::LoadBitmap(const char* lpszResourceName) { + wxBitmap bmp = LoadBitmapResource(ResRef::From(lpszResourceName)); + if (!bmp.IsOk()) + return FALSE; + GdiLock lock; + return Attach(NewBitmapHandle(bmp, 32)); +} + +BOOL CBitmap::LoadBitmap(UINT nIDResource) { + wxBitmap bmp = LoadBitmapResource(ResRef::FromId(nIDResource)); + if (!bmp.IsOk()) + return FALSE; + GdiLock lock; + return Attach(NewBitmapHandle(bmp, 32)); +} + +BOOL CBitmap::LoadOEMBitmap(UINT) { return FALSE; } + +BOOL CBitmap::LoadMappedBitmap(UINT nIDBitmap, UINT, void*, int) { return LoadBitmap(nIDBitmap); } + +BOOL CBitmap::CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits) { + return Attach(::CreateBitmap(nWidth, nHeight, nPlanes, nBitcount, lpBits)); +} + +BOOL CBitmap::CreateBitmapIndirect(LPBITMAP lpBitmap) { + if (!lpBitmap) + return FALSE; + int bpp = std::max(1, lpBitmap->bmBitsPixel * std::max(1, lpBitmap->bmPlanes)); + wxImage img; + int stride = lpBitmap->bmWidthBytes ? lpBitmap->bmWidthBytes : ((lpBitmap->bmWidth * bpp + 15) / 16) * 2; + if (!DdbBitsToImage(lpBitmap->bmWidth, lpBitmap->bmHeight, bpp, stride, lpBitmap->bmBits, img)) + return FALSE; + GdiLock lock; + return Attach(NewBitmapHandle(wxBitmap(img), bpp == 1 ? 1 : bpp)); +} + +BOOL CBitmap::CreateCompatibleBitmap(CDC* pDC, int nWidth, int nHeight) { + return Attach(::CreateCompatibleBitmap(pDC ? pDC->m_hDC : nullptr, nWidth, nHeight)); +} + +BOOL CBitmap::CreateDiscardableBitmap(CDC* pDC, int nWidth, int nHeight) { + return CreateCompatibleBitmap(pDC, nWidth, nHeight); +} + +int CBitmap::GetBitmap(BITMAP* pBitMap) { return GetObject(sizeof(BITMAP), pBitMap); } + +DWORD CBitmap::SetBitmapBits(DWORD dwCount, const void* lpBits) { + GdiLock lock; + GdiObjectImpl* impl = BitmapImpl(m_hObject); + if (!impl || !impl->bitmap.IsOk() || !lpBits) + return 0; + SyncBitmap(impl); + double scale = impl->bitmap.GetScaleFactor(); + int w = static_cast(std::lround(impl->bitmap.GetLogicalWidth())); + int h = static_cast(std::lround(impl->bitmap.GetLogicalHeight())); + int stride = ((w * impl->bitsPixel + 15) / 16) * 2; + std::vector buf(static_cast(stride) * h, 0); + DWORD n = std::min(dwCount, static_cast(buf.size())); + if (n < buf.size()) { + std::vector current; + int st = 0; + wxImage img = impl->bitmap.ConvertToImage(); + if (scale != 1.0) + img.Rescale(w, h, wxIMAGE_QUALITY_NEAREST); + if (ImageToDdbBits(img, impl->bitsPixel, current, st) && current.size() == buf.size()) + buf = current; + } + memcpy(buf.data(), lpBits, n); + wxImage img; + if (!DdbBitsToImage(w, h, impl->bitsPixel, stride, buf.data(), img)) + return 0; + if (scale != 1.0) + img.Rescale(static_cast(std::lround(w * scale)), static_cast(std::lround(h * scale)), + wxIMAGE_QUALITY_NEAREST); + impl->bitmap = wxBitmap(img, -1, scale); + if (impl->selectedIn) + impl->selectedIn->pixels.reset(); + return n; +} + +DWORD CBitmap::GetBitmapBits(DWORD dwCount, LPVOID lpBits) const { + GdiLock lock; + GdiObjectImpl* impl = BitmapImpl(m_hObject); + if (!impl || !impl->bitmap.IsOk() || !lpBits) + return 0; + SyncBitmap(impl); + wxImage img = impl->bitmap.ConvertToImage(); + int w = static_cast(std::lround(impl->bitmap.GetLogicalWidth())); + int h = static_cast(std::lround(impl->bitmap.GetLogicalHeight())); + if (img.GetWidth() != w || img.GetHeight() != h) + img.Rescale(w, h, wxIMAGE_QUALITY_NEAREST); + std::vector buf; + int stride = 0; + if (!ImageToDdbBits(img, impl->bitsPixel, buf, stride)) + return 0; + DWORD n = std::min(dwCount, static_cast(buf.size())); + memcpy(lpBits, buf.data(), n); + return n; +} + +CSize CBitmap::SetBitmapDimension(int nWidth, int nHeight) { + GdiLock lock; + GdiObjectImpl* impl = BitmapImpl(m_hObject); + if (!impl) + return CSize(); + CSize old(impl->dimension); + impl->dimension = SIZE{nWidth, nHeight}; + return old; +} + +CSize CBitmap::GetBitmapDimension() const { + GdiLock lock; + GdiObjectImpl* impl = BitmapImpl(m_hObject); + return impl ? CSize(impl->dimension) : CSize(); +} + +// --------------------------------------------------------------------------------------------- +// CDC raster operations + +BOOL CDC::PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop) { + GdiLock lock; + return BlitImpl(DCFromHandle(m_hDC), x, y, nWidth, nHeight, nullptr, 0, 0, 0, 0, dwRop); +} + +BOOL CDC::BitBlt(int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop) { + return ::BitBlt(m_hDC, x, y, nWidth, nHeight, pSrcDC ? pSrcDC->m_hDC : nullptr, xSrc, ySrc, dwRop); +} + +BOOL CDC::StretchBlt(int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, + int nSrcHeight, DWORD dwRop) { + return ::StretchBlt(m_hDC, x, y, nWidth, nHeight, pSrcDC ? pSrcDC->m_hDC : nullptr, xSrc, ySrc, nSrcWidth, + nSrcHeight, dwRop); +} + +BOOL CDC::TransparentBlt(int xDest, int yDest, int nDestWidth, int nDestHeight, CDC* pSrcDC, int xSrc, int ySrc, + int nSrcWidth, int nSrcHeight, UINT clrTransparent) { + GdiLock lock; + DCState* dst = DCFromHandle(m_hDC); + DCState* src = pSrcDC ? DCFromHandle(pSrcDC->m_hDC) : nullptr; + if (!dst || !src) + return FALSE; + wxRect D = dst->DeviceRect(xDest, yDest, xDest + nDestWidth, yDest + nDestHeight); + wxRect S = src->DeviceRect(xSrc, ySrc, xSrc + nSrcWidth, ySrc + nSrcHeight); + if (D.width <= 0 || D.height <= 0) + return TRUE; + wxImage img; + if (!SourceImage(src, S, img)) + return FALSE; + DrawScope ds(dst); + if (!ds) + return TRUE; + double scale = TargetScale(dst, ds.dc()); + wxRect PD = PhysicalRect(D, scale); + FitImage(img, PD.width, PD.height, false, false, false); + img = Opaque(img); + img.SetMaskColour(GetRValue(clrTransparent), GetGValue(clrTransparent), GetBValue(clrTransparent)); + ds.dc()->DrawBitmap(wxBitmap(img, -1, scale), D.x, D.y, true); + return TRUE; +} + +COLORREF CDC::GetPixel(int x, int y) const { return ::GetPixel(m_hDC, x, y); } + +COLORREF CDC::SetPixel(int x, int y, COLORREF crColor) { return ::SetPixel(m_hDC, x, y, crColor); } + +BOOL CDC::FloodFill(int x, int y, COLORREF crColor) { return ExtFloodFill(x, y, crColor, 0); } + +BOOL CDC::ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? FloodImpl(s, x, y, crColor, nFillType) : FALSE; +} + +// --------------------------------------------------------------------------------------------- +// Win32 bitmap functions + +HBITMAP CreateCompatibleBitmap(HDC hdc, int cx, int cy) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + double scale = s ? DCBitmapScale(s) : 1.0; + if (s && s->kind == DCKind::Window && s->window) + scale = s->window->GetContentScaleFactor(); + return NewBitmapHandle(NewBitmap(std::max(1, cx), std::max(1, cy), scale, *wxBLACK), 32); +} + +HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitCount, const void* lpBits) { + int bpp = static_cast(std::max(1, nBitCount) * std::max(1, nPlanes)); + wxImage img; + if (!DdbBitsToImage(std::max(1, nWidth), std::max(1, nHeight), bpp, ((std::max(1, nWidth) * bpp + 15) / 16) * 2, + lpBits, img)) + return nullptr; + GdiLock lock; + return NewBitmapHandle(wxBitmap(img), bpp); +} + +BOOL BitBlt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) { + GdiLock lock; + return BlitImpl(DCFromHandle(hdc), x, y, cx, cy, DCFromHandle(hdcSrc), x1, y1, cx, cy, rop); +} + +BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdcSrc, int xSrc, int ySrc, int wSrc, + int hSrc, DWORD rop) { + GdiLock lock; + return BlitImpl(DCFromHandle(hdcDest), xDest, yDest, wDest, hDest, DCFromHandle(hdcSrc), xSrc, ySrc, wSrc, hSrc, + rop); +} + +COLORREF SetPixel(HDC hdc, int x, int y, COLORREF color) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return CLR_INVALID; + DrawScope ds(s); + if (ds) + FillDeviceRectColor(ds.dc(), wxRect(s->ToDevice(x, y), wxSize(1, 1)), ToWxColour(color)); + return color & 0xFFFFFF; +} + +COLORREF GetPixel(HDC hdc, int x, int y) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + const wxImage* px = DCPixels(s); + if (!px) + return CLR_INVALID; + double scale = DCBitmapScale(s); + wxPoint p = s->ToDevice(x, y); + int ix = static_cast(std::floor(p.x * scale)), iy = static_cast(std::floor(p.y * scale)); + if (ix < 0 || iy < 0 || ix >= px->GetWidth() || iy >= px->GetHeight()) + return CLR_INVALID; + const unsigned char* d = px->GetData() + (static_cast(iy) * px->GetWidth() + ix) * 3; + return RGB(d[0], d[1], d[2]); +} + +int SetDIBitsToDevice(HDC hdc, int xDest, int yDest, DWORD w, DWORD h, int xSrc, int ySrc, UINT StartScan, + UINT cLines, const void* lpvBits, const BITMAPINFO* lpbmi, UINT ColorUse) { + wxImage img; + if (!DibToImage(lpbmi, lpvBits, ColorUse, img, static_cast(StartScan), static_cast(cLines))) + return 0; + int iw = static_cast(w), ih = static_cast(h); + int top = lpbmi->bmiHeader.biHeight > 0 ? img.GetHeight() - ySrc - ih : ySrc; + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || !DrawImageImpl(s, xDest, yDest, iw, ih, img, xSrc, top, iw, ih, SRCCOPY)) + return 0; + return static_cast(cLines); +} + +int StretchDIBits(HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc, int SrcWidth, + int SrcHeight, const void* lpBits, const BITMAPINFO* lpbmi, UINT iUsage, DWORD rop) { + wxImage img; + if (!DibToImage(lpbmi, lpBits, iUsage, img)) + return 0; + int ys = lpbmi->bmiHeader.biHeight > 0 ? img.GetHeight() - ySrc - SrcHeight : ySrc; + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || !DrawImageImpl(s, xDest, yDest, DestWidth, DestHeight, img, xSrc, ys, SrcWidth, SrcHeight, rop)) + return 0; + return std::abs(SrcHeight); +} diff --git a/port/mfcwx/src/gdi_dc.cpp b/port/mfcwx/src/gdi_dc.cpp new file mode 100644 index 000000000..4fa9f06c3 --- /dev/null +++ b/port/mfcwx/src/gdi_dc.cpp @@ -0,0 +1,2345 @@ +#include "gdi_internal.h" + +#include +#include +#include +#include +#include + +IMPLEMENT_DYNCREATE(CDC, CObject) +IMPLEMENT_DYNAMIC(CPaintDC, CDC) +IMPLEMENT_DYNAMIC(CClientDC, CDC) +IMPLEMENT_DYNAMIC(CWindowDC, CDC) + +namespace mfcwx { + +namespace { + +struct PaintSession { + wxDC* dc = nullptr; + std::unique_ptr own; + std::vector users; +}; + +struct Overlay { + wxBitmap bitmap; + std::unique_ptr dc; + std::vector users; +}; + +struct ClipInfo { + DCState* owner = nullptr; + bool clipped = false; +}; + +std::unordered_set& States() { + static auto* states = new std::unordered_set; + return *states; +} + +std::unordered_map& TempDCs() { + static auto* temps = new std::unordered_map; + return *temps; +} + +std::vector& DetachedTempDCs() { + static auto* detached = new std::vector; + return *detached; +} + +std::unordered_map& Sessions() { + static auto* sessions = new std::unordered_map; + return *sessions; +} + +std::unordered_map& Overlays() { + static auto* overlays = new std::unordered_map; + return *overlays; +} + +std::unordered_map& ClipOwners() { + static auto* owners = new std::unordered_map; + return *owners; +} + +std::unordered_set& HookedWindows() { + static auto* hooked = new std::unordered_set; + return *hooked; +} + +void Remove(std::vector& v, DCState* s) { v.erase(std::remove(v.begin(), v.end(), s), v.end()); } + +void ForgetDC(wxDC* d) { + if (d) + ClipOwners().erase(d); +} + +bool NativePainting(wxWindow* w) { +#if defined(__WXOSX__) + return w && w->MacGetCGContextRef() != nullptr; +#elif defined(__WXGTK3__) + return w && w->GTKPaintContext() != nullptr; +#else + (void)w; + return false; +#endif +} + +bool ClientDrawsDirectly() { +#if defined(__WXOSX__) + return false; +#elif defined(__WXGTK__) + static bool wayland = wxGetDisplayInfo().type == wxDisplayWayland; + return !wayland; +#else + return true; +#endif +} + +void OnWindowDestroyed(wxWindow* w); + +void HookDestroy(wxWindow* w) { + if (!w || !HookedWindows().insert(w).second) + return; + w->Bind(wxEVT_DESTROY, [w](wxWindowDestroyEvent& e) { + e.Skip(); + if (e.GetEventObject() == w) + OnWindowDestroyed(w); + }); +} + +void EndSession(wxWindow* w) { + auto it = Sessions().find(w); + if (it == Sessions().end()) + return; + PaintSession& ps = it->second; + for (DCState* u : ps.users) { + u->dc = nullptr; + u->target = WinTarget::None; + } + ForgetDC(ps.dc); + std::unique_ptr own = std::move(ps.own); + Sessions().erase(it); + own.reset(); +} + +void ReleaseOverlayDC(Overlay& ov) { + for (DCState* u : ov.users) { + u->dc = nullptr; + u->target = WinTarget::None; + } + ov.users.clear(); + if (ov.dc) { + ForgetDC(ov.dc.get()); + ov.dc->SelectObject(wxNullBitmap); + ov.dc.reset(); + } +} + +void ReleaseTarget(DCState* s) { + if (s->kind != DCKind::Window) + return; + if (s->dc) { + auto c = ClipOwners().find(s->dc); + if (c != ClipOwners().end() && c->second.owner == s) { + if (c->second.clipped && s->target != WinTarget::Client && s->target != WinTarget::OverlayPending) + s->dc->DestroyClippingRegion(); + ClipOwners().erase(c); + } + } + if (s->target == WinTarget::Paint && s->window) { + auto it = Sessions().find(s->window); + if (it != Sessions().end()) { + Remove(it->second.users, s); + if (it->second.own && it->second.users.empty()) + EndSession(s->window); + } + } else if (s->target == WinTarget::Overlay && s->window) { + auto it = Overlays().find(s->window); + if (it != Overlays().end()) { + Remove(it->second.users, s); + if (it->second.users.empty() && it->second.dc) { + ForgetDC(it->second.dc.get()); + it->second.dc->SelectObject(wxNullBitmap); + it->second.dc.reset(); + } + } + } else if (s->owned) { + ForgetDC(s->owned.get()); + s->owned.reset(); + } + s->dc = nullptr; + s->target = WinTarget::None; +} + +wxBitmap TransparentBitmap(wxSize size, double scale) { + int pw = std::max(1, static_cast(std::lround(size.x * scale))); + int ph = std::max(1, static_cast(std::lround(size.y * scale))); + wxImage img(pw, ph, true); + img.InitAlpha(); + memset(img.GetAlpha(), 0, static_cast(pw) * ph); + return wxBitmap(img, 32, scale); +} + +void AcquireWindowTarget(DCState* s) { + wxWindow* w = s->window; + auto it = Sessions().find(w); + if (it == Sessions().end() && NativePainting(w)) { + PaintSession ps; + ps.own.reset(new wxPaintDC(w)); + ps.dc = ps.own.get(); + it = Sessions().emplace(w, std::move(ps)).first; + HookDestroy(w); + } + if (it != Sessions().end()) { + s->dc = it->second.dc; + s->target = WinTarget::Paint; + it->second.users.push_back(s); + } else if (ClientDrawsDirectly()) { + if (s->wholeWindow) + s->owned.reset(new wxWindowDC(w)); + else + s->owned.reset(new wxClientDC(w)); + s->dc = s->owned.get(); + s->target = WinTarget::Client; + } else { + s->owned.reset(new wxClientDC(w)); + s->dc = s->owned.get(); + s->target = WinTarget::OverlayPending; + } + s->clipDirty = true; +} + +void SwitchToOverlay(DCState* s) { + wxWindow* w = s->window; + if (s->owned) { + ForgetDC(s->owned.get()); + s->owned.reset(); + } + s->dc = nullptr; + wxSize size = w->GetClientSize(); + size.x = std::max(1, size.x); + size.y = std::max(1, size.y); + double scale = w->GetContentScaleFactor(); + Overlay& ov = Overlays()[w]; + if (ov.bitmap.IsOk()) { + wxSize cur(static_cast(std::lround(ov.bitmap.GetLogicalWidth())), + static_cast(std::lround(ov.bitmap.GetLogicalHeight()))); + if (cur != size || std::fabs(ov.bitmap.GetScaleFactor() - scale) > 1e-6) { + ReleaseOverlayDC(ov); + ov.bitmap = wxBitmap(); + } + } + if (!ov.bitmap.IsOk()) + ov.bitmap = TransparentBitmap(size, scale); + if (!ov.dc) { + ov.dc.reset(new wxMemoryDC); + ov.dc->SelectObject(ov.bitmap); + } + ov.users.push_back(s); + s->dc = ov.dc.get(); + s->target = WinTarget::Overlay; + s->clipDirty = true; + HookDestroy(w); +} + +void OnWindowDestroyed(wxWindow* w) { + GdiLock lock; + for (DCState* s : States()) { + if (s->window != w) + continue; + if (s->kind == DCKind::Window) + ReleaseTarget(s); + s->window = nullptr; + } + EndSession(w); + auto it = Overlays().find(w); + if (it != Overlays().end()) { + ReleaseOverlayDC(it->second); + Overlays().erase(it); + } + HookedWindows().erase(w); +} + +double ScreenScale() { + wxWindow* top = wxTheApp ? wxTheApp->GetTopWindow() : nullptr; + return top ? top->GetContentScaleFactor() : 1.0; +} + +wxBitmap& CurrentBitmap(DCState* s) { + GdiObjectImpl* impl = s->SelectedBitmap(); + if (impl && impl->bitmap.IsOk()) + return impl->bitmap; + return s->defaultBitmap; +} + +void DeselectBitmap(DCState* s) { + if (s->kind != DCKind::Memory || s->bitmapOut || !s->dc) + return; + static_cast(s->dc)->SelectObject(wxNullBitmap); + s->bitmapOut = true; +} + +void ReselectBitmap(DCState* s) { + if (s->kind != DCKind::Memory || !s->dc) + return; + static_cast(s->dc)->SelectObject(CurrentBitmap(s)); + s->bitmapOut = false; + s->clipDirty = true; +} + +DCAttrs DefaultAttrs(bool memory) { + DCAttrs a; + a.pen = ::GetStockObject(BLACK_PEN); + a.brush = ::GetStockObject(WHITE_BRUSH); + a.font = ::GetStockObject(SYSTEM_FONT); + a.palette = ::GetStockObject(DEFAULT_PALETTE); + a.bitmap = memory ? DefaultBitmapHandle() : nullptr; + return a; +} + +void AddRefs(const DCAttrs& a) { + GdiAddRef(a.pen); + GdiAddRef(a.brush); + GdiAddRef(a.font); + GdiAddRef(a.bitmap); + GdiAddRef(a.palette); +} + +void ReleaseRefs(const DCAttrs& a) { + GdiRelease(a.pen); + GdiRelease(a.brush); + GdiRelease(a.font); + GdiRelease(a.bitmap); + GdiRelease(a.palette); +} + +DCState* NewState(DCKind kind) { + auto* s = new DCState; + s->kind = kind; + s->a = DefaultAttrs(kind == DCKind::Memory); + States().insert(s); + return s; +} + +DCState* NewWindowState(wxWindow* w, bool whole) { + if (!w) + return NewState(DCKind::Info); + DCState* s = NewState(DCKind::Window); + s->window = w; + s->wholeWindow = whole; + s->scale = w->GetContentScaleFactor(); + HookDestroy(w); + return s; +} + +DCState* NewMemoryState(DCState* src) { + DCState* s = NewState(DCKind::Memory); + if (src) + s->scale = src->kind == DCKind::Memory ? CurrentBitmap(src).GetScaleFactor() : src->scale; + else + s->scale = ScreenScale(); + if (s->scale <= 0) + s->scale = 1; + s->defaultBitmap = NewBitmap(1, 1, s->scale, *wxWHITE); + auto* mdc = new wxMemoryDC; + mdc->SelectObject(s->defaultBitmap); + s->owned.reset(mdc); + s->dc = mdc; + return s; +} + +void FreeState(DCState* s) { + if (!s || !States().count(s)) + return; + if (s->owner) { + s->owner->m_hDC = nullptr; + s->owner->m_hAttribDC = nullptr; + s->owner = nullptr; + } + auto it = TempDCs().find(ToHdc(s)); + if (it != TempDCs().end()) { + it->second->m_hDC = nullptr; + it->second->m_hAttribDC = nullptr; + DetachedTempDCs().push_back(it->second); + TempDCs().erase(it); + } + if (s->kind == DCKind::Window) { + ReleaseTarget(s); + } else if (s->kind == DCKind::Memory) { + if (GdiObjectImpl* b = s->SelectedBitmap()) + b->selectedIn = nullptr; + DeselectBitmap(s); + } else if (s->kind == DCKind::Borrowed && s->dc) { + auto c = ClipOwners().find(s->dc); + if (c != ClipOwners().end() && c->second.clipped) + s->dc->DestroyClippingRegion(); + } + if (s->sessionOwner && s->window) + EndSession(s->window); + for (auto c = ClipOwners().begin(); c != ClipOwners().end();) { + if (c->second.owner == s) + c = ClipOwners().erase(c); + else + ++c; + } + if (s->owned) { + ForgetDC(s->owned.get()); + s->owned.reset(); + } + ReleaseRefs(s->a); + for (const DCAttrs& saved : s->saved) + ReleaseRefs(saved); + States().erase(s); + delete s; +} + +int RegionType(const wxRegion& r) { + if (!r.IsOk() || r.IsEmpty()) + return NULLREGION; + int n = 0; + for (wxRegionIterator it(r); it && n < 2; ++it) + ++n; + return n <= 1 ? SIMPLEREGION : COMPLEXREGION; +} + +wxRasterOperationMode Rop2ToWx(int rop2) { + switch (rop2) { + case R2_BLACK: + return wxCLEAR; + case R2_NOTMERGEPEN: + return wxNOR; + case R2_MASKNOTPEN: + return wxAND_INVERT; + case R2_NOTCOPYPEN: + return wxSRC_INVERT; + case R2_MASKPENNOT: + return wxAND_REVERSE; + case R2_NOT: + return wxINVERT; + case R2_XORPEN: + return wxXOR; + case R2_NOTMASKPEN: + return wxNAND; + case R2_MASKPEN: + return wxAND; + case R2_NOTXORPEN: + return wxEQUIV; + case R2_NOP: + return wxNO_OP; + case R2_MERGENOTPEN: + return wxOR_INVERT; + case R2_MERGEPENNOT: + return wxOR_REVERSE; + case R2_MERGEPEN: + return wxOR; + case R2_WHITE: + return wxSET; + default: + return wxCOPY; + } +} + +wxColour Rop2Colour(int rop2, const wxColour& c) { + switch (rop2) { + case R2_BLACK: + return *wxBLACK; + case R2_WHITE: + return *wxWHITE; + case R2_NOTCOPYPEN: + return wxColour(255 - c.Red(), 255 - c.Green(), 255 - c.Blue()); + default: + return c; + } +} + +void SetRop(DCState* s, wxDC* d, int rop2) { + if (!s->SupportsLogicalOps(d)) + return; + wxRasterOperationMode m = Rop2ToWx(rop2); + if (d->GetLogicalFunction() != m) + d->SetLogicalFunction(m); +} + +HGDIOBJ SelectBitmapImpl(DCState* s, HGDIOBJ h, GdiObjectImpl* impl) { + if (s->kind != DCKind::Memory) + return nullptr; + if (!impl->stock && impl->selectedIn && impl->selectedIn != s) + return nullptr; + HGDIOBJ old = s->a.bitmap; + if (old == h) + return old; + if (GdiObjectImpl* cur = s->SelectedBitmap()) + cur->selectedIn = nullptr; + DeselectBitmap(s); + GdiAddRef(h); + s->a.bitmap = h; + if (!impl->stock) + impl->selectedIn = s; + ReselectBitmap(s); + s->pixels.reset(); + GdiRelease(old); + return old; +} + +int SelectClipImpl(DCState* s, const wxRegion* rgn) { + if (!rgn) { + s->a.hasClip = false; + s->a.clip = wxRegion(); + } else { + s->a.hasClip = true; + s->a.clip = *rgn; + } + s->clipDirty = true; + return s->a.hasClip ? RegionType(s->a.clip) : SIMPLEREGION; +} + +HGDIOBJ SelectImpl(DCState* s, HGDIOBJ h) { + if (!s || !h) + return nullptr; + HGDIOBJ old = nullptr; + if (SysColorBrushIndex(h) >= 0) { + old = s->a.brush; + s->a.brush = h; + GdiRelease(old); + return old; + } + GdiObjectImpl* impl = GdiImpl(h); + if (!impl) + return nullptr; + HGDIOBJ* slot = nullptr; + switch (impl->kind) { + case GdiKind::Pen: + slot = &s->a.pen; + break; + case GdiKind::Brush: + slot = &s->a.brush; + break; + case GdiKind::Font: + slot = &s->a.font; + break; + case GdiKind::Palette: + slot = &s->a.palette; + break; + case GdiKind::Bitmap: + return SelectBitmapImpl(s, h, impl); + case GdiKind::Region: + return reinterpret_cast(static_cast(SelectClipImpl(s, &impl->region))); + } + old = *slot; + if (old == h) + return old; + GdiAddRef(h); + *slot = h; + GdiRelease(old); + return old; +} + +void RestoreAttrs(DCState* s, const DCAttrs& saved) { + SelectImpl(s, saved.pen); + SelectImpl(s, saved.brush); + SelectImpl(s, saved.font); + SelectImpl(s, saved.palette); + if (s->kind == DCKind::Memory && saved.bitmap) + SelectImpl(s, saved.bitmap); + DCAttrs keep = s->a; + s->a = saved; + s->a.pen = keep.pen; + s->a.brush = keep.brush; + s->a.font = keep.font; + s->a.palette = keep.palette; + s->a.bitmap = keep.bitmap; + s->clipDirty = true; +} + +bool HasPen(DCState* s) { return !PenIsNull(s->a.pen) && s->a.rop2 != R2_NOP; } + +int DevicePenWidth(DCState* s) { + double sx, sy; + s->Scales(sx, sy); + return s->a.pen ? std::max(1, static_cast(std::lround(PenWidth(s->a.pen) * std::fabs(sx)))) : 1; +} + +void SetSolidBrush(wxDC* d, const wxColour& c) { + wxBrush b(c); + if (d->GetBrush() != b) + d->SetBrush(b); +} + +void SetNoPen(wxDC* d) { + if (d->GetPen().GetStyle() != wxPENSTYLE_TRANSPARENT) + d->SetPen(*wxTRANSPARENT_PEN); +} + +bool NeedsHatchBackground(DCState* s) { return s->a.bkMode == OPAQUE && BrushIsHatched(s->a.brush); } + +template +void DrawShape(DCState* s, wxDC* d, bool fill, F draw) { + if (fill && NeedsHatchBackground(s)) { + SetRop(s, d, R2_COPYPEN); + SetNoPen(d); + SetSolidBrush(d, ToWxColour(s->a.bkColor)); + draw(); + } + s->ApplyPen(d); + s->ApplyBrush(d, fill); + draw(); + SetRop(s, d, R2_COPYPEN); +} + +void DrawSegment(DCState* s, wxDC* d, wxPoint p1, wxPoint p2) { + if (p1 == p2) + return; + int width = DevicePenWidth(s); + bool solid = PenStyle(s->a.pen) == PS_SOLID || PenStyle(s->a.pen) == PS_INSIDEFRAME; + if (width <= 1 && solid && (p1.x == p2.x || p1.y == p2.y)) { + if (p1.x == p2.x) + p2.y += p2.y > p1.y ? -1 : 1; + else + p2.x += p2.x > p1.x ? -1 : 1; + if (p1 == p2) { + SetRop(s, d, s->a.rop2); + FillDeviceRectColor(d, wxRect(p1, wxSize(1, 1)), Rop2Colour(s->a.rop2, ToWxColour(PenColor(s->a.pen)))); + SetRop(s, d, R2_COPYPEN); + return; + } + } + s->ApplyPen(d); + d->DrawLine(p1, p2); + SetRop(s, d, R2_COPYPEN); +} + +void DrawPolyline(DCState* s, wxDC* d, const std::vector& pts) { + if (pts.size() < 2 || !HasPen(s)) + return; + bool solid = PenStyle(s->a.pen) == PS_SOLID || PenStyle(s->a.pen) == PS_INSIDEFRAME; + if (DevicePenWidth(s) <= 1 && solid) { + for (size_t i = 0; i + 1 < pts.size(); ++i) + DrawSegment(s, d, pts[i], pts[i + 1]); + return; + } + s->ApplyPen(d); + d->DrawLines(static_cast(pts.size()), pts.data()); + SetRop(s, d, R2_COPYPEN); +} + +std::vector DevicePoints(DCState* s, const POINT* p, int n) { + std::vector out; + out.reserve(static_cast(std::max(0, n))); + for (int i = 0; i < n; ++i) + out.push_back(s->ToDevice(p[i].x, p[i].y)); + return out; +} + +std::vector ArcPoints(const wxRect& r, wxPoint start, wxPoint end, bool full) { + double rx = (r.width - 1) / 2.0, ry = (r.height - 1) / 2.0; + double cx = r.x + rx, cy = r.y + ry; + if (rx <= 0 || ry <= 0) + return {}; + auto angle = [&](wxPoint p) { return std::atan2(-(p.y - cy) / ry, (p.x - cx) / rx); }; + double a0 = angle(start), a1 = angle(end); + if (full || a1 <= a0 + 1e-9) + a1 += 2 * M_PI; + int n = std::max(8, static_cast((rx + ry) * (a1 - a0) / 4)); + std::vector pts; + for (int i = 0; i <= n; ++i) { + double t = a0 + (a1 - a0) * i / n; + pts.emplace_back(static_cast(std::lround(cx + rx * std::cos(t))), + static_cast(std::lround(cy - ry * std::sin(t)))); + } + return pts; +} + +void FillRegionRects(DCState* s, wxDC* d, const wxRegion& logical, HBRUSH brush) { + if (!logical.IsOk() || logical.IsEmpty()) + return; + for (wxRegionIterator it(logical); it; ++it) { + wxRect r = it.GetRect(); + FillDeviceRect(s, d, s->DeviceRect(r.x, r.y, r.x + r.width, r.y + r.height), brush); + } +} + +void EdgeRect(wxDC* d, const wxRect& r, UINT flags, COLORREF lt, COLORREF rb) { + if (flags & BF_LEFT) + FillDeviceRectColor(d, wxRect(r.x, r.y, 1, r.height), ToWxColour(lt)); + if (flags & BF_TOP) + FillDeviceRectColor(d, wxRect(r.x, r.y, r.width, 1), ToWxColour(lt)); + if (flags & BF_RIGHT) + FillDeviceRectColor(d, wxRect(r.x + r.width - 1, r.y, 1, r.height), ToWxColour(rb)); + if (flags & BF_BOTTOM) + FillDeviceRectColor(d, wxRect(r.x, r.y + r.height - 1, r.width, 1), ToWxColour(rb)); +} + +wxRect ShrinkEdges(const wxRect& r, UINT flags) { + wxRect o = r; + if (flags & BF_LEFT) { + o.x += 1; + o.width -= 1; + } + if (flags & BF_TOP) { + o.y += 1; + o.height -= 1; + } + if (flags & BF_RIGHT) + o.width -= 1; + if (flags & BF_BOTTOM) + o.height -= 1; + return o; +} + +} // namespace + +// --------------------------------------------------------------------------------------------- +// DCState + +GdiObjectImpl* DCState::SelectedBitmap() const { + GdiObjectImpl* impl = GdiImpl(a.bitmap, GdiKind::Bitmap); + return impl && !impl->stock ? impl : nullptr; +} + +wxDC* DCState::Target(bool drawing) { + wxDC* d = nullptr; + switch (kind) { + case DCKind::Info: + return nullptr; + case DCKind::Borrowed: + d = dc; + break; + case DCKind::Memory: + if (bitmapOut) + ReselectBitmap(this); + d = dc; + break; + case DCKind::Window: + if (!window) + return nullptr; + if (target == WinTarget::Paint) { + auto it = Sessions().find(window); + if (it == Sessions().end()) + ReleaseTarget(this); + else if (it->second.own && !NativePainting(window)) + EndSession(window); + } + if (target == WinTarget::None) + AcquireWindowTarget(this); + if (drawing && target == WinTarget::OverlayPending) + SwitchToOverlay(this); + d = dc; + break; + } + if (d && drawing) { + auto it = ClipOwners().find(d); + bool mine = it != ClipOwners().end() && it->second.owner == this; + if (clipDirty || !mine) + ApplyClip(d); + } + return d; +} + +wxDC* DCState::Measure() { + wxDC* d = Target(false); + if (!d) + d = &MeasureDC(); + ApplyFont(d); + return d; +} + +void DCState::Finish() { + if (kind == DCKind::Memory) + pixels.reset(); + else if (kind == DCKind::Window && target == WinTarget::Overlay && window) + window->Refresh(false); +} + +void DCState::Scales(double& sx, double& sy) const { + if (a.mapMode == MM_TEXT) { + sx = sy = 1.0; + return; + } + sx = a.winExt.cx ? static_cast(a.vpExt.cx) / a.winExt.cx : 1.0; + sy = a.winExt.cy ? static_cast(a.vpExt.cy) / a.winExt.cy : 1.0; + if (sx == 0) + sx = 1; + if (sy == 0) + sy = 1; +} + +wxPoint DCState::ToDevice(double x, double y) const { + double sx, sy; + Scales(sx, sy); + return wxPoint(static_cast(std::lround((x - a.winOrg.x) * sx + a.vpOrg.x)), + static_cast(std::lround((y - a.winOrg.y) * sy + a.vpOrg.y))); +} + +void DCState::ToLogical(double& x, double& y) const { + double sx, sy; + Scales(sx, sy); + x = (x - a.vpOrg.x) / sx + a.winOrg.x; + y = (y - a.vpOrg.y) / sy + a.winOrg.y; +} + +wxRect DCState::DeviceRect(int l, int t, int r, int b) const { + wxPoint p1 = ToDevice(l, t), p2 = ToDevice(r, b); + return wxRect(std::min(p1.x, p2.x), std::min(p1.y, p2.y), std::abs(p2.x - p1.x), std::abs(p2.y - p1.y)); +} + +int DCState::LogicalWidth(int deviceCx) const { + double sx, sy; + Scales(sx, sy); + return static_cast(std::lround(deviceCx / std::fabs(sx))); +} + +int DCState::LogicalHeight(int deviceCy) const { + double sx, sy; + Scales(sx, sy); + return static_cast(std::lround(deviceCy / std::fabs(sy))); +} + +int DCState::DeviceWidth(int logicalCx) const { + double sx, sy; + Scales(sx, sy); + return static_cast(std::lround(logicalCx * std::fabs(sx))); +} + +int DCState::DeviceHeight(int logicalCy) const { + double sx, sy; + Scales(sx, sy); + return static_cast(std::lround(logicalCy * std::fabs(sy))); +} + +int DCState::Dpi() const { + if (owner && owner->m_bPrinting && dc) { + int ppi = dc->GetPPI().y; + if (ppi > 0) + return ppi; + } + return 96; +} + +bool DCState::SupportsLogicalOps(wxDC* d) const { return d && d->GetGraphicsContext() == nullptr; } + +void DCState::ApplyPen(wxDC* d) { + double sx, sy; + Scales(sx, sy); + wxPen p = DevicePen(a.pen, std::fabs(sx)); + if (a.rop2 == R2_NOP) { + p = *wxTRANSPARENT_PEN; + } else if (a.rop2 != R2_COPYPEN) { + if (SupportsLogicalOps(d)) + SetRop(this, d, a.rop2); + else if (p.GetStyle() != wxPENSTYLE_TRANSPARENT) + p.SetColour(Rop2Colour(a.rop2, p.GetColour())); + } + if (d->GetPen() != p) + d->SetPen(p); +} + +void DCState::ApplyBrush(wxDC* d, bool fill) { + wxBrush b = fill ? DeviceBrush(a.brush) : *wxTRANSPARENT_BRUSH; + if (fill && a.rop2 != R2_COPYPEN && !SupportsLogicalOps(d) && b.GetStyle() == wxBRUSHSTYLE_SOLID) + b = wxBrush(Rop2Colour(a.rop2, b.GetColour())); + if (d->GetBrush() != b) + d->SetBrush(b); +} + +void DCState::ApplyFont(wxDC* d) { + double sx, sy; + Scales(sx, sy); + wxFont f = DeviceFont(a.font, std::fabs(sy)); + if (f.IsOk() && d->GetFont() != f) + d->SetFont(f); + wxColour fg = ToWxColour(a.textColor); + if (d->GetTextForeground() != fg) + d->SetTextForeground(fg); + if (d->GetBackgroundMode() != wxBRUSHSTYLE_TRANSPARENT) + d->SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT); +} + +void DCState::ApplyClip(wxDC* d, const wxRect* extra) { + ClipInfo& info = ClipOwners()[d]; + wxRegion r; + bool any = false; + if (a.hasClip) { + r = a.clip; + any = true; + } + if (extra) { + if (any) { + if (r.IsOk() && !r.IsEmpty()) + r.Intersect(*extra); + } else { + r = wxRegion(*extra); + } + any = true; + } + if (!any) { + if (info.clipped) + d->DestroyClippingRegion(); + info.clipped = false; + } else { + d->DestroyClippingRegion(); + if (!r.IsOk() || r.IsEmpty()) { + d->SetClippingRegion(wxRect(-32000, -32000, 1, 1)); + } else if (RegionType(r) == SIMPLEREGION) { + d->SetClippingRegion(r.GetBox()); + } else { + wxRegion dev = r; + dev.Offset(d->LogicalToDeviceX(0), d->LogicalToDeviceY(0)); + d->SetDeviceClippingRegion(dev); + } + info.clipped = true; + } + info.owner = this; + if (!extra) + clipDirty = false; + else + clipDirty = true; +} + +DCState* DCFromHandle(HDC h) { + if (!h) + return nullptr; + GdiLock lock; + auto* s = reinterpret_cast(h); + return States().count(s) ? s : nullptr; +} + +wxDC& MeasureDC() { + static wxMemoryDC* dc = [] { + auto* d = new wxMemoryDC; + static wxBitmap bmp(1, 1, 24); + d->SelectObject(bmp); + return d; + }(); + return *dc; +} + +void SyncBitmap(GdiObjectImpl* bmp) { + if (!bmp || !bmp->selectedIn) + return; + DeselectBitmap(bmp->selectedIn); +} + +const wxImage* DCPixels(DCState* s) { + if (!s || s->kind != DCKind::Memory) + return nullptr; + if (!s->pixels) { + DeselectBitmap(s); + wxBitmap& bmp = CurrentBitmap(s); + s->pixels.reset(new wxImage(bmp.ConvertToImage())); + } + return s->pixels.get(); +} + +double DCBitmapScale(DCState* s) { + if (!s) + return 1.0; + if (s->kind == DCKind::Memory) { + double scale = CurrentBitmap(s).GetScaleFactor(); + return scale > 0 ? scale : 1.0; + } + if (s->dc) + return s->dc->GetContentScaleFactor(); + return s->scale; +} + +void FillDeviceRectColor(wxDC* dc, const wxRect& r, const wxColour& c) { + if (r.width <= 0 || r.height <= 0) + return; + SetNoPen(dc); + SetSolidBrush(dc, c); + dc->DrawRectangle(r); +} + +void FillDeviceRect(DCState* s, wxDC* dc, const wxRect& r, HBRUSH brush) { + if (r.width <= 0 || r.height <= 0) + return; + if (s && s->a.bkMode == OPAQUE && BrushIsHatched(brush)) + FillDeviceRectColor(dc, r, ToWxColour(s->a.bkColor)); + wxBrush b = DeviceBrush(brush); + if (!b.IsOk() || b.GetStyle() == wxBRUSHSTYLE_TRANSPARENT) + return; + SetNoPen(dc); + if (dc->GetBrush() != b) + dc->SetBrush(b); + dc->DrawRectangle(r); +} + +void PurgeTemporaryDCs() { + std::vector doomed; + { + GdiLock lock; + for (auto& kv : TempDCs()) { + kv.second->m_hDC = nullptr; + kv.second->m_hAttribDC = nullptr; + doomed.push_back(kv.second); + } + TempDCs().clear(); + doomed.insert(doomed.end(), DetachedTempDCs().begin(), DetachedTempDCs().end()); + DetachedTempDCs().clear(); + for (DCState* s : States()) + if (s->fromGetDC && s->kind == DCKind::Window && s->target != WinTarget::None) + ReleaseTarget(s); + } + for (CDC* d : doomed) + delete d; +} + +CDC* WrapDC(wxDC* dc, wxWindow* window) { + GdiLock lock; + DCState* s = NewState(DCKind::Borrowed); + s->dc = dc; + s->window = window; + s->scale = dc ? dc->GetContentScaleFactor() : 1.0; + if (window && dc && wxDynamicCast(dc, wxPaintDC) && !Sessions().count(window)) { + PaintSession ps; + ps.dc = dc; + Sessions().emplace(window, std::move(ps)); + s->sessionOwner = true; + HookDestroy(window); + } else if (window) { + HookDestroy(window); + } + auto* cdc = new CDC; + cdc->m_hDC = ToHdc(s); + cdc->m_hAttribDC = ToHdc(s); + s->owner = cdc; + return cdc; +} + +void UnwrapDC(CDC* cdc) { + if (!cdc) + return; + { + GdiLock lock; + FreeState(DCFromHandle(cdc->m_hDC)); + cdc->m_hDC = nullptr; + cdc->m_hAttribDC = nullptr; + } + delete cdc; +} + +void PaintClientDCOverlay(wxWindow* w, wxDC& dc) { + GdiLock lock; + auto s = Sessions().find(w); + if (s != Sessions().end() && s->second.own) + EndSession(w); + auto it = Overlays().find(w); + if (it == Overlays().end() || !it->second.bitmap.IsOk()) + return; + ReleaseOverlayDC(it->second); + ForgetDC(&dc); + dc.DestroyClippingRegion(); + dc.DrawBitmap(it->second.bitmap, 0, 0, true); +} + +bool HasClientDCOverlay(wxWindow* w) { + GdiLock lock; + return Overlays().count(w) != 0; +} + +void ClearClientDCOverlay(wxWindow* w, const wxRect* rect) { + GdiLock lock; + auto it = Overlays().find(w); + if (it == Overlays().end()) + return; + Overlay& ov = it->second; + ReleaseOverlayDC(ov); + if (!rect) { + Overlays().erase(it); + return; + } + double scale = ov.bitmap.GetScaleFactor(); + wxRect pr(static_cast(std::floor(rect->x * scale)), static_cast(std::floor(rect->y * scale)), + static_cast(std::ceil(rect->width * scale)), static_cast(std::ceil(rect->height * scale))); + pr.Intersect(wxRect(0, 0, ov.bitmap.GetWidth(), ov.bitmap.GetHeight())); + if (pr.IsEmpty()) + return; + wxImage img = ov.bitmap.ConvertToImage(); + if (!img.HasAlpha()) + img.InitAlpha(); + unsigned char* alpha = img.GetAlpha(); + unsigned char* data = img.GetData(); + for (int y = pr.y; y < pr.GetBottom() + 1; ++y) + for (int x = pr.x; x < pr.GetRight() + 1; ++x) { + size_t i = static_cast(y) * img.GetWidth() + x; + alpha[i] = 0; + data[i * 3] = data[i * 3 + 1] = data[i * 3 + 2] = 0; + } + ov.bitmap = wxBitmap(img, 32, scale); +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CDC + +CDC::CDC() : m_hDC(nullptr), m_hAttribDC(nullptr), m_bPrinting(FALSE) {} + +CDC::~CDC() { + if (m_hDC) + ::DeleteDC(Detach()); +} + +CDC* CDC::FromHandle(HDC hDC) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + if (!s) + return nullptr; + if (s->owner) + return s->owner; + auto it = TempDCs().find(hDC); + if (it != TempDCs().end()) + return it->second; + auto* cdc = new CDC; + cdc->m_hDC = hDC; + cdc->m_hAttribDC = hDC; + TempDCs()[hDC] = cdc; + return cdc; +} + +void CDC::DeleteTempMap() { PurgeTemporaryDCs(); } + +BOOL CDC::Attach(HDC hDC) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + if (!s) + return FALSE; + if (m_hDC && m_hDC != hDC) + ::DeleteDC(Detach()); + auto it = TempDCs().find(hDC); + if (it != TempDCs().end()) { + it->second->m_hDC = nullptr; + it->second->m_hAttribDC = nullptr; + DetachedTempDCs().push_back(it->second); + TempDCs().erase(it); + } + s->owner = this; + m_hDC = hDC; + m_hAttribDC = hDC; + return TRUE; +} + +HDC CDC::Detach() { + if (AfxIsNullThis(this)) + return nullptr; + GdiLock lock; + HDC h = m_hDC; + if (DCState* s = DCFromHandle(h)) + if (s->owner == this) + s->owner = nullptr; + m_hDC = nullptr; + m_hAttribDC = nullptr; + return h; +} + +BOOL CDC::CreateCompatibleDC(CDC* pDC) { return Attach(::CreateCompatibleDC(pDC ? pDC->m_hDC : nullptr)); } + +BOOL CDC::DeleteDC() { + if (AfxIsNullThis(this) || !m_hDC) + return FALSE; + return ::DeleteDC(Detach()); +} + +CWnd* CDC::GetWindow() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s && s->window ? CWnd::FromHandle(ToHwnd(s->window)) : nullptr; +} + +wxDC* CDC::GetWx() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return nullptr; + wxDC* d = s->Target(true); + if (!d) + return nullptr; + s->ApplyPen(d); + s->ApplyBrush(d, true); + s->ApplyFont(d); + s->Finish(); + return d; +} + +int CDC::SaveDC() { return ::SaveDC(m_hDC); } + +BOOL CDC::RestoreDC(int nSavedDC) { return ::RestoreDC(m_hDC, nSavedDC); } + +CGdiObject* CDC::SelectStockObject(int nIndex) { + return CGdiObject::FromHandle(::SelectObject(m_hDC, ::GetStockObject(nIndex))); +} + +CPen* CDC::SelectObject(CPen* pPen) { + return static_cast(CGdiObject::FromHandle(::SelectObject(m_hDC, pPen ? pPen->m_hObject : nullptr))); +} + +CBrush* CDC::SelectObject(CBrush* pBrush) { + return static_cast(CGdiObject::FromHandle(::SelectObject(m_hDC, pBrush ? pBrush->m_hObject : nullptr))); +} + +CFont* CDC::SelectObject(CFont* pFont) { + return static_cast(CGdiObject::FromHandle(::SelectObject(m_hDC, pFont ? pFont->m_hObject : nullptr))); +} + +CBitmap* CDC::SelectObject(CBitmap* pBitmap) { + return static_cast( + CGdiObject::FromHandle(::SelectObject(m_hDC, pBitmap ? pBitmap->m_hObject : nullptr))); +} + +int CDC::SelectObject(CRgn* pRgn) { return ::SelectClipRgn(m_hDC, pRgn ? pRgn->m_hObject : nullptr); } + +CGdiObject* CDC::SelectObject(CGdiObject* pObject) { + if (!pObject) + return nullptr; + GdiLock lock; + GdiObjectImpl* impl = GdiImpl(pObject->m_hObject); + if (impl && impl->kind == GdiKind::Region) { + ::SelectClipRgn(m_hDC, pObject->m_hObject); + return nullptr; + } + return CGdiObject::FromHandle(::SelectObject(m_hDC, pObject->m_hObject)); +} + +HGDIOBJ CDC::SelectObject(HGDIOBJ hObject) { return ::SelectObject(m_hDC, hObject); } + +CPalette* CDC::SelectPalette(CPalette* pPalette, BOOL) { + return static_cast( + CGdiObject::FromHandle(::SelectObject(m_hDC, pPalette ? pPalette->m_hObject : nullptr))); +} + +CPen* CDC::GetCurrentPen() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? static_cast(CGdiObject::FromHandle(s->a.pen)) : nullptr; +} + +CBrush* CDC::GetCurrentBrush() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? static_cast(CGdiObject::FromHandle(s->a.brush)) : nullptr; +} + +CFont* CDC::GetCurrentFont() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? static_cast(CGdiObject::FromHandle(s->a.font)) : nullptr; +} + +CBitmap* CDC::GetCurrentBitmap() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? static_cast(CGdiObject::FromHandle(s->a.bitmap)) : nullptr; +} + +int CDC::GetDeviceCaps(int nIndex) const { return ::GetDeviceCaps(m_hDC, nIndex); } + +COLORREF CDC::GetBkColor() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.bkColor : CLR_INVALID; +} + +COLORREF CDC::SetBkColor(COLORREF crColor) { return ::SetBkColor(m_hDC, crColor); } + +int CDC::GetBkMode() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.bkMode : 0; +} + +int CDC::SetBkMode(int nBkMode) { return ::SetBkMode(m_hDC, nBkMode); } + +COLORREF CDC::GetTextColor() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.textColor : CLR_INVALID; +} + +COLORREF CDC::SetTextColor(COLORREF crColor) { return ::SetTextColor(m_hDC, crColor); } + +int CDC::GetROP2() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.rop2 : 0; +} + +int CDC::SetROP2(int nDrawMode) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || nDrawMode < R2_BLACK || nDrawMode > R2_WHITE) + return 0; + int old = s->a.rop2; + s->a.rop2 = nDrawMode; + return old; +} + +int CDC::SetStretchBltMode(int nStretchMode) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return 0; + int old = s->a.stretchMode; + s->a.stretchMode = nStretchMode; + return old; +} + +int CDC::GetStretchBltMode() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.stretchMode : 0; +} + +UINT CDC::SetTextAlign(UINT nFlags) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return static_cast(-1); + UINT old = s->a.textAlign; + s->a.textAlign = nFlags; + return old; +} + +UINT CDC::GetTextAlign() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.textAlign : 0; +} + +int CDC::SetMapMode(int nMapMode) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || nMapMode < MM_TEXT || nMapMode > MM_ANISOTROPIC) + return 0; + int old = s->a.mapMode; + int dpi = s->Dpi(); + auto fixed = [&](int units) { + s->a.winExt = SIZE{units, units}; + s->a.vpExt = SIZE{dpi, -dpi}; + }; + switch (nMapMode) { + case MM_TEXT: + s->a.winExt = SIZE{1, 1}; + s->a.vpExt = SIZE{1, 1}; + break; + case MM_LOMETRIC: + fixed(254); + break; + case MM_HIMETRIC: + fixed(2540); + break; + case MM_LOENGLISH: + fixed(100); + break; + case MM_HIENGLISH: + fixed(1000); + break; + case MM_TWIPS: + fixed(1440); + break; + default: + break; + } + s->a.mapMode = nMapMode; + return old; +} + +int CDC::GetMapMode() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? s->a.mapMode : 0; +} + +CPoint CDC::SetViewportOrg(int x, int y) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return CPoint(); + CPoint old(s->a.vpOrg); + s->a.vpOrg = POINT{x, y}; + return old; +} + +CPoint CDC::GetViewportOrg() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? CPoint(s->a.vpOrg) : CPoint(); +} + +CPoint CDC::OffsetViewportOrg(int nWidth, int nHeight) { + CPoint old = GetViewportOrg(); + SetViewportOrg(old.x + nWidth, old.y + nHeight); + return old; +} + +namespace { + +void AdjustIsotropic(DCState* s) { + if (s->a.mapMode != MM_ISOTROPIC || !s->a.winExt.cx || !s->a.winExt.cy) + return; + double sx = static_cast(s->a.vpExt.cx) / s->a.winExt.cx; + double sy = static_cast(s->a.vpExt.cy) / s->a.winExt.cy; + double m = std::min(std::fabs(sx), std::fabs(sy)); + if (m <= 0) + return; + s->a.vpExt.cx = static_cast(std::lround(s->a.winExt.cx * std::copysign(m, sx))); + s->a.vpExt.cy = static_cast(std::lround(s->a.winExt.cy * std::copysign(m, sy))); +} + +} // namespace + +CSize CDC::SetViewportExt(int cx, int cy) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return CSize(); + CSize old(s->a.vpExt); + if ((s->a.mapMode == MM_ISOTROPIC || s->a.mapMode == MM_ANISOTROPIC) && cx && cy) { + s->a.vpExt = SIZE{cx, cy}; + AdjustIsotropic(s); + } + return old; +} + +CSize CDC::GetViewportExt() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? CSize(s->a.vpExt) : CSize(); +} + +CPoint CDC::SetWindowOrg(int x, int y) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return CPoint(); + CPoint old(s->a.winOrg); + s->a.winOrg = POINT{x, y}; + return old; +} + +CPoint CDC::GetWindowOrg() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? CPoint(s->a.winOrg) : CPoint(); +} + +CPoint CDC::OffsetWindowOrg(int nWidth, int nHeight) { + CPoint old = GetWindowOrg(); + SetWindowOrg(old.x + nWidth, old.y + nHeight); + return old; +} + +CSize CDC::SetWindowExt(int cx, int cy) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return CSize(); + CSize old(s->a.winExt); + if ((s->a.mapMode == MM_ISOTROPIC || s->a.mapMode == MM_ANISOTROPIC) && cx && cy) { + s->a.winExt = SIZE{cx, cy}; + AdjustIsotropic(s); + } + return old; +} + +CSize CDC::GetWindowExt() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? CSize(s->a.winExt) : CSize(1, 1); +} + +void CDC::DPtoLP(LPPOINT lpPoints, int nCount) const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpPoints) + return; + for (int i = 0; i < nCount; ++i) { + double x = lpPoints[i].x, y = lpPoints[i].y; + s->ToLogical(x, y); + lpPoints[i].x = static_cast(std::lround(x)); + lpPoints[i].y = static_cast(std::lround(y)); + } +} + +void CDC::DPtoLP(LPRECT lpRect) const { DPtoLP(reinterpret_cast(lpRect), 2); } + +void CDC::DPtoLP(LPSIZE lpSize) const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpSize) + return; + double sx, sy; + s->Scales(sx, sy); + lpSize->cx = static_cast(std::lround(lpSize->cx / std::fabs(sx))); + lpSize->cy = static_cast(std::lround(lpSize->cy / std::fabs(sy))); +} + +void CDC::LPtoDP(LPPOINT lpPoints, int nCount) const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpPoints) + return; + for (int i = 0; i < nCount; ++i) { + wxPoint p = s->ToDevice(lpPoints[i].x, lpPoints[i].y); + lpPoints[i].x = p.x; + lpPoints[i].y = p.y; + } +} + +void CDC::LPtoDP(LPRECT lpRect) const { LPtoDP(reinterpret_cast(lpRect), 2); } + +void CDC::LPtoDP(LPSIZE lpSize) const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpSize) + return; + double sx, sy; + s->Scales(sx, sy); + lpSize->cx = static_cast(std::lround(lpSize->cx * std::fabs(sx))); + lpSize->cy = static_cast(std::lround(lpSize->cy * std::fabs(sy))); +} + +int CDC::GetClipBox(LPRECT lpRect) const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpRect) + return ERROR; + wxRect box; + int type = SIMPLEREGION; + if (s->a.hasClip) { + type = RegionType(s->a.clip); + box = s->a.clip.IsOk() ? s->a.clip.GetBox() : wxRect(); + } else if (s->kind == DCKind::Window && s->window) { + box = wxRect(wxPoint(0, 0), s->window->GetClientSize()); + } else if (s->kind == DCKind::Memory) { + wxBitmap& bmp = CurrentBitmap(s); + box = wxRect(0, 0, static_cast(std::lround(bmp.GetLogicalWidth())), + static_cast(std::lround(bmp.GetLogicalHeight()))); + } else if (s->dc) { + box = wxRect(wxPoint(0, 0), s->dc->GetSize()); + } else if (s->window) { + box = wxRect(wxPoint(0, 0), s->window->GetClientSize()); + } + double x0 = box.x, y0 = box.y, x1 = box.x + box.width, y1 = box.y + box.height; + s->ToLogical(x0, y0); + s->ToLogical(x1, y1); + lpRect->left = static_cast(std::lround(std::min(x0, x1))); + lpRect->top = static_cast(std::lround(std::min(y0, y1))); + lpRect->right = static_cast(std::lround(std::max(x0, x1))); + lpRect->bottom = static_cast(std::lround(std::max(y0, y1))); + return type; +} + +int CDC::SelectClipRgn(CRgn* pRgn) { return ::SelectClipRgn(m_hDC, pRgn ? pRgn->m_hObject : nullptr); } + +int CDC::IntersectClipRect(int x1, int y1, int x2, int y2) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return ERROR; + wxRect r = s->DeviceRect(x1, y1, x2, y2); + if (s->a.hasClip) { + if (s->a.clip.IsOk() && !s->a.clip.IsEmpty() && r.width > 0 && r.height > 0) + s->a.clip.Intersect(r); + else + s->a.clip = wxRegion(); + } else { + s->a.clip = r.width > 0 && r.height > 0 ? wxRegion(r) : wxRegion(); + s->a.hasClip = true; + } + s->clipDirty = true; + return RegionType(s->a.clip); +} + +int CDC::IntersectClipRect(LPCRECT lpRect) { + return lpRect ? IntersectClipRect(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom) : ERROR; +} + +CPoint CDC::GetCurrentPosition() const { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + return s ? CPoint(s->a.pos) : CPoint(); +} + +CPoint CDC::MoveTo(int x, int y) { + POINT old{0, 0}; + ::MoveToEx(m_hDC, x, y, &old); + return CPoint(old); +} + +BOOL CDC::LineTo(int x, int y) { return ::LineTo(m_hDC, x, y); } + +namespace { + +BOOL ArcLike(HDC hdc, int kind, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect r = s->DeviceRect(x1, y1, x2, y2); + std::vector pts = ArcPoints(r, s->ToDevice(x3, y3), s->ToDevice(x4, y4), x3 == x4 && y3 == y4); + if (pts.size() < 2) + return TRUE; + if (kind == 0) { + DrawPolyline(s, d, pts); + return TRUE; + } + if (kind == 1) + pts.insert(pts.begin(), wxPoint(r.x + (r.width - 1) / 2, r.y + (r.height - 1) / 2)); + DrawShape(s, d, true, [&] { d->DrawPolygon(static_cast(pts.size()), pts.data()); }); + return TRUE; +} + +} // namespace + +BOOL CDC::Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { + return ArcLike(m_hDC, 0, x1, y1, x2, y2, x3, y3, x4, y4); +} + +BOOL CDC::Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd) { + return Arc(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); +} + +BOOL CDC::Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { + return ArcLike(m_hDC, 1, x1, y1, x2, y2, x3, y3, x4, y4); +} + +BOOL CDC::Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd) { + return Pie(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); +} + +BOOL CDC::Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { + return ArcLike(m_hDC, 2, x1, y1, x2, y2, x3, y3, x4, y4); +} + +BOOL CDC::Polyline(const POINT* lpPoints, int nCount) { return ::Polyline(m_hDC, lpPoints, nCount); } + +BOOL CDC::PolyBezier(const POINT* lpPoints, int nCount) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpPoints || nCount < 4 || (nCount - 1) % 3) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + std::vector pts; + double x0 = lpPoints[0].x, y0 = lpPoints[0].y; + pts.push_back(s->ToDevice(x0, y0)); + for (int i = 1; i + 2 < nCount; i += 3) { + const POINT &c1 = lpPoints[i], &c2 = lpPoints[i + 1], &e = lpPoints[i + 2]; + for (int k = 1; k <= 24; ++k) { + double t = k / 24.0, u = 1 - t; + double x = u * u * u * x0 + 3 * u * u * t * c1.x + 3 * u * t * t * c2.x + t * t * t * e.x; + double y = u * u * u * y0 + 3 * u * u * t * c1.y + 3 * u * t * t * c2.y + t * t * t * e.y; + pts.push_back(s->ToDevice(x, y)); + } + x0 = e.x; + y0 = e.y; + } + DrawPolyline(s, ds.dc(), pts); + return TRUE; +} + +BOOL CDC::PolylineTo(const POINT* lpPoints, int nCount) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpPoints || nCount < 1) + return FALSE; + std::vector all; + all.push_back(s->a.pos); + all.insert(all.end(), lpPoints, lpPoints + nCount); + BOOL r = ::Polyline(m_hDC, all.data(), static_cast(all.size())); + s->a.pos = lpPoints[nCount - 1]; + return r; +} + +void CDC::FillRect(LPCRECT lpRect, CBrush* pBrush) { ::FillRect(m_hDC, lpRect, pBrush ? pBrush->m_hObject : nullptr); } + +void CDC::FrameRect(LPCRECT lpRect, CBrush* pBrush) { + ::FrameRect(m_hDC, lpRect, pBrush ? pBrush->m_hObject : nullptr); +} + +void CDC::InvertRect(LPCRECT lpRect) { + if (lpRect) + PatBlt(lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, DSTINVERT); +} + +BOOL CDC::DrawIcon(int x, int y, HICON hIcon) { return ::DrawIcon(m_hDC, x, y, hIcon); } + +BOOL CDC::DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags) { return ::DrawEdge(m_hDC, lpRect, nEdge, nFlags); } + +BOOL CDC::DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpRect) + return FALSE; + RECT r = *lpRect; + if (nType == DFC_BUTTON && (nState & 0xFF) == DFCS_BUTTONRADIO) { + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect dr = s->DeviceRect(r.left, r.top, r.right, r.bottom); + int size = std::min(dr.width, dr.height); + wxRect box(dr.x, dr.y + (dr.height - size) / 2, size, size); + d->SetPen(wxPen(ToWxColour(SysColor(COLOR_BTNSHADOW)))); + d->SetBrush(wxBrush(ToWxColour(SysColor((nState & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW)))); + d->DrawEllipse(box.x, box.y, box.width - 1, box.height - 1); + if (nState & DFCS_CHECKED) { + int inner = std::max(2, size / 3); + d->SetPen(*wxTRANSPARENT_PEN); + d->SetBrush(wxBrush(ToWxColour(SysColor(COLOR_WINDOWTEXT)))); + d->DrawEllipse(box.x + (size - inner) / 2, box.y + (size - inner) / 2, inner, inner); + } + return TRUE; + } + if (nType == DFC_BUTTON && (nState & 0xFF) == DFCS_BUTTONCHECK) { + ::DrawEdge(m_hDC, &r, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + HBRUSH bg = GetSysColorBrush((nState & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW); + ::FillRect(m_hDC, &r, bg); + if (nState & DFCS_CHECKED) { + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect dr = s->DeviceRect(r.left, r.top, r.right, r.bottom); + d->SetPen(wxPen(ToWxColour(SysColor(COLOR_WINDOWTEXT)), std::max(1, dr.width / 6))); + wxPoint pts[3] = {wxPoint(dr.x + dr.width / 5, dr.y + dr.height / 2), + wxPoint(dr.x + dr.width * 2 / 5, dr.y + dr.height * 3 / 4), + wxPoint(dr.x + dr.width * 4 / 5, dr.y + dr.height / 4)}; + d->DrawLines(3, pts); + } + return TRUE; + } + ::FillRect(m_hDC, &r, GetSysColorBrush(COLOR_BTNFACE)); + UINT edge = (nState & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED; + if (nState & DFCS_FLAT) + edge = (nState & DFCS_PUSHED) ? BDR_SUNKENOUTER : BDR_RAISEDINNER; + return ::DrawEdge(m_hDC, &r, edge, BF_RECT); +} + +void CDC::DrawFocusRect(LPCRECT lpRect) { ::DrawFocusRect(m_hDC, lpRect); } + +BOOL CDC::Ellipse(int x1, int y1, int x2, int y2) { return ::Ellipse(m_hDC, x1, y1, x2, y2); } + +BOOL CDC::Polygon(const POINT* lpPoints, int nCount) { return ::Polygon(m_hDC, lpPoints, nCount); } + +BOOL CDC::PolyPolygon(const POINT* lpPoints, const INT* lpPolyCounts, int nCount) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s || !lpPoints || !lpPolyCounts || nCount <= 0) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + int total = 0; + std::vector counts; + for (int i = 0; i < nCount; ++i) { + counts.push_back(lpPolyCounts[i]); + total += lpPolyCounts[i]; + } + std::vector pts = DevicePoints(s, lpPoints, total); + wxDC* d = ds.dc(); + wxPolygonFillMode mode = s->a.polyFillMode == WINDING ? wxWINDING_RULE : wxODDEVEN_RULE; + DrawShape(s, d, true, [&] { d->DrawPolyPolygon(nCount, counts.data(), pts.data(), 0, 0, mode); }); + return TRUE; +} + +BOOL CDC::Rectangle(int x1, int y1, int x2, int y2) { return ::Rectangle(m_hDC, x1, y1, x2, y2); } + +BOOL CDC::RoundRect(int x1, int y1, int x2, int y2, int x3, int y3) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect r = s->DeviceRect(x1, y1, x2, y2); + if (r.width <= 1 || r.height <= 1) + return TRUE; + double radius = (s->DeviceWidth(std::abs(x3)) + s->DeviceHeight(std::abs(y3))) / 4.0; + radius = std::min(radius, std::min(r.width, r.height) / 2.0); + bool pen = HasPen(s); + int w = r.width - (pen ? 0 : 1), h = r.height - (pen ? 0 : 1); + DrawShape(s, d, true, [&] { d->DrawRoundedRectangle(r.x, r.y, w, h, radius); }); + return TRUE; +} + +BOOL CDC::RoundRect(LPCRECT lpRect, POINT point) { + return RoundRect(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y); +} + +void CDC::FillSolidRect(LPCRECT lpRect, COLORREF clr) { + if (!lpRect) + return; + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + if (!s) + return; + s->a.bkColor = clr; + DrawScope ds(s); + if (!ds) + return; + FillDeviceRectColor(ds.dc(), s->DeviceRect(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom), + ToWxColour(clr)); +} + +void CDC::FillSolidRect(int x, int y, int cx, int cy, COLORREF clr) { + RECT r{x, y, x + cx, y + cy}; + FillSolidRect(&r, clr); +} + +void CDC::Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight) { + Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, clrTopLeft, + clrBottomRight); +} + +void CDC::Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight) { + FillSolidRect(x, y, cx - 1, 1, clrTopLeft); + FillSolidRect(x, y, 1, cy - 1, clrTopLeft); + FillSolidRect(x + cx, y, -1, cy, clrBottomRight); + FillSolidRect(x, y + cy, cx, -1, clrBottomRight); +} + +BOOL CDC::FillRgn(CRgn* pRgn, CBrush* pBrush) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + GdiObjectImpl* rgn = pRgn ? GdiImpl(pRgn->m_hObject, GdiKind::Region) : nullptr; + if (!s || !rgn || !pBrush) + return FALSE; + DrawScope ds(s); + if (ds) + FillRegionRects(s, ds.dc(), rgn->region, pBrush->m_hObject); + return TRUE; +} + +BOOL CDC::FrameRgn(CRgn* pRgn, CBrush* pBrush, int nWidth, int nHeight) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + GdiObjectImpl* rgn = pRgn ? GdiImpl(pRgn->m_hObject, GdiKind::Region) : nullptr; + if (!s || !rgn || !pBrush || !rgn->region.IsOk() || rgn->region.IsEmpty()) + return FALSE; + wxRegion inner = rgn->region; + const int offs[4][2] = {{nWidth, 0}, {-nWidth, 0}, {0, nHeight}, {0, -nHeight}}; + for (const auto& o : offs) { + wxRegion moved = rgn->region; + moved.Offset(o[0], o[1]); + inner.Intersect(moved); + } + wxRegion frame = rgn->region; + if (inner.IsOk() && !inner.IsEmpty()) + frame.Subtract(inner); + DrawScope ds(s); + if (ds) + FillRegionRects(s, ds.dc(), frame, pBrush->m_hObject); + return TRUE; +} + +BOOL CDC::PaintRgn(CRgn* pRgn) { + GdiLock lock; + DCState* s = DCFromHandle(m_hDC); + GdiObjectImpl* rgn = pRgn ? GdiImpl(pRgn->m_hObject, GdiKind::Region) : nullptr; + if (!s || !rgn) + return FALSE; + DrawScope ds(s); + if (ds) + FillRegionRects(s, ds.dc(), rgn->region, s->a.brush); + return TRUE; +} + +// --------------------------------------------------------------------------------------------- +// Window DCs + +CPaintDC::CPaintDC(CWnd* pWnd) : m_hWnd(pWnd ? pWnd->m_hWnd : nullptr) { + memset(&m_ps, 0, sizeof m_ps); + Attach(::BeginPaint(m_hWnd, &m_ps)); +} + +CPaintDC::~CPaintDC() { + if (m_hDC) + ::EndPaint(m_hWnd, &m_ps); + Detach(); +} + +CClientDC::CClientDC(CWnd* pWnd) : m_hWnd(pWnd ? pWnd->m_hWnd : nullptr) { Attach(::GetDC(m_hWnd)); } + +CClientDC::~CClientDC() { + HDC h = Detach(); + if (h) + ::ReleaseDC(m_hWnd, h); +} + +CWindowDC::CWindowDC(CWnd* pWnd) : m_hWnd(pWnd ? pWnd->m_hWnd : nullptr) { Attach(::GetWindowDC(m_hWnd)); } + +CWindowDC::~CWindowDC() { + HDC h = Detach(); + if (h) + ::ReleaseDC(m_hWnd, h); +} + +CDC* CWnd::GetDC() { return CDC::FromHandle(::GetDC(m_hWnd)); } + +CDC* CWnd::GetWindowDC() { return CDC::FromHandle(::GetWindowDC(m_hWnd)); } + +int CWnd::ReleaseDC(CDC* pDC) { return pDC ? ::ReleaseDC(m_hWnd, pDC->m_hDC) : 0; } + +CDC* CWnd::BeginPaint(LPPAINTSTRUCT lpPaint) { return CDC::FromHandle(::BeginPaint(m_hWnd, lpPaint)); } + +void CWnd::EndPaint(LPPAINTSTRUCT lpPaint) { ::EndPaint(m_hWnd, lpPaint); } + +HDC GetDC(HWND hWnd) { + GdiLock lock; + DCState* s = NewWindowState(ToWx(hWnd), false); + s->fromGetDC = true; + return ToHdc(s); +} + +HDC GetWindowDC(HWND hWnd) { + GdiLock lock; + DCState* s = NewWindowState(ToWx(hWnd), true); + s->fromGetDC = true; + return ToHdc(s); +} + +int ReleaseDC(HWND, HDC hDC) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + if (!s) + return 0; + FreeState(s); + return 1; +} + +HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint) { + GdiLock lock; + wxWindow* w = ToWx(hWnd); + if (!w) + return nullptr; + DCState* s = NewWindowState(w, false); + s->paintDC = true; + if (lpPaint) { + memset(lpPaint, 0, sizeof *lpPaint); + lpPaint->hdc = ToHdc(s); + wxRect box; + if (Sessions().count(w) || NativePainting(w)) + box = w->GetUpdateRegion().GetBox(); + if (box.IsEmpty()) + box = wxRect(wxPoint(0, 0), w->GetClientSize()); + lpPaint->rcPaint.left = box.x; + lpPaint->rcPaint.top = box.y; + lpPaint->rcPaint.right = box.x + box.width; + lpPaint->rcPaint.bottom = box.y + box.height; + } + return ToHdc(s); +} + +BOOL EndPaint(HWND, const PAINTSTRUCT* lpPaint) { + if (!lpPaint) + return FALSE; + GdiLock lock; + FreeState(DCFromHandle(lpPaint->hdc)); + return TRUE; +} + +// --------------------------------------------------------------------------------------------- +// Win32 DC functions + +HDC CreateCompatibleDC(HDC hdc) { + GdiLock lock; + return ToHdc(NewMemoryState(DCFromHandle(hdc))); +} + +BOOL DeleteDC(HDC hdc) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return FALSE; + FreeState(s); + return TRUE; +} + +HGDIOBJ SelectObject(HDC hdc, HGDIOBJ h) { + GdiLock lock; + return SelectImpl(DCFromHandle(hdc), h); +} + +int SelectClipRgn(HDC hdc, HRGN hrgn) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return ERROR; + GdiObjectImpl* rgn = GdiImpl(hrgn, GdiKind::Region); + return SelectClipImpl(s, rgn ? &rgn->region : nullptr); +} + +COLORREF SetTextColor(HDC hdc, COLORREF color) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return CLR_INVALID; + COLORREF old = s->a.textColor; + s->a.textColor = color; + return old; +} + +COLORREF SetBkColor(HDC hdc, COLORREF color) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return CLR_INVALID; + COLORREF old = s->a.bkColor; + s->a.bkColor = color; + return old; +} + +int SetBkMode(HDC hdc, int mode) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || (mode != TRANSPARENT && mode != OPAQUE)) + return 0; + int old = s->a.bkMode; + s->a.bkMode = mode; + return old; +} + +int GetDeviceCaps(HDC hdc, int index) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + int dpi = s ? s->Dpi() : 96; + bool printing = s && s->owner && s->owner->m_bPrinting && s->dc; + wxSize res; + switch (index) { + case HORZSIZE: + case VERTSIZE: + case HORZRES: + case VERTRES: + case 110: + case 111: + case 117: + case 118: + res = printing ? s->dc->GetSize() : wxGetDisplaySize(); + break; + default: + break; + } + switch (index) { + case 2: + return printing ? 2 : 1; + case HORZSIZE: + return static_cast(std::lround(res.x * 25.4 / dpi)); + case VERTSIZE: + return static_cast(std::lround(res.y * 25.4 / dpi)); + case HORZRES: + case 118: + return res.x; + case VERTRES: + case 117: + return res.y; + case BITSPIXEL: + return 32; + case PLANES: + return 1; + case NUMCOLORS: + return -1; + case 28: + case 30: + case 32: + case 34: + return 0xFF; + case 36: + return 1; + case RASTERCAPS: + return 0x2A89; + case 40: + case 42: + return 36; + case 44: + return 51; + case LOGPIXELSX: + case LOGPIXELSY: + return dpi; + case 108: + return 24; + case 110: + return printing ? res.x : 0; + case 111: + return printing ? res.y : 0; + case 116: + return 60; + default: + return 0; + } +} + +BOOL MoveToEx(HDC hdc, int x, int y, LPPOINT lppt) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return FALSE; + if (lppt) + *lppt = s->a.pos; + s->a.pos = POINT{x, y}; + return TRUE; +} + +BOOL LineTo(HDC hdc, int x, int y) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return FALSE; + if (HasPen(s)) { + DrawScope ds(s); + if (ds) + DrawSegment(s, ds.dc(), s->ToDevice(s->a.pos.x, s->a.pos.y), s->ToDevice(x, y)); + } + s->a.pos = POINT{x, y}; + return TRUE; +} + +BOOL Rectangle(HDC hdc, int left, int top, int right, int bottom) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect r = s->DeviceRect(left, top, right, bottom); + if (!HasPen(s)) { + FillDeviceRect(s, d, wxRect(r.x, r.y, r.width - 1, r.height - 1), s->a.brush); + return TRUE; + } + if (r.width <= 0 || r.height <= 0) + return TRUE; + int pw = DevicePenWidth(s); + if (PenStyle(s->a.pen) == PS_INSIDEFRAME && pw > 1) + r.Deflate(pw / 2); + if (r.width <= 0 || r.height <= 0) + return TRUE; + DrawShape(s, d, true, [&] { d->DrawRectangle(r); }); + return TRUE; +} + +BOOL Ellipse(HDC hdc, int left, int top, int right, int bottom) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect r = s->DeviceRect(left, top, right, bottom); + if (r.width <= 1 || r.height <= 1) + return TRUE; + int pw = HasPen(s) ? DevicePenWidth(s) : 0; + if (pw > 1 && PenStyle(s->a.pen) == PS_INSIDEFRAME) + r.Deflate(pw / 2); + DrawShape(s, d, true, [&] { d->DrawEllipse(r.x, r.y, r.width - 1, r.height - 1); }); + return TRUE; +} + +BOOL Polygon(HDC hdc, const POINT* apt, int cpt) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || !apt || cpt < 2) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + std::vector pts = DevicePoints(s, apt, cpt); + wxPolygonFillMode mode = s->a.polyFillMode == WINDING ? wxWINDING_RULE : wxODDEVEN_RULE; + DrawShape(s, d, true, [&] { d->DrawPolygon(static_cast(pts.size()), pts.data(), 0, 0, mode); }); + return TRUE; +} + +BOOL Polyline(HDC hdc, const POINT* apt, int cpt) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || !apt || cpt < 2) + return FALSE; + DrawScope ds(s); + if (ds) + DrawPolyline(s, ds.dc(), DevicePoints(s, apt, cpt)); + return TRUE; +} + +int FillRect(HDC hDC, const RECT* lprc, HBRUSH hbr) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + if (!s || !lprc) + return 0; + DrawScope ds(s); + if (ds) + FillDeviceRect(s, ds.dc(), s->DeviceRect(lprc->left, lprc->top, lprc->right, lprc->bottom), hbr); + return 1; +} + +int FrameRect(HDC hDC, const RECT* lprc, HBRUSH hbr) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + if (!s || !lprc) + return 0; + DrawScope ds(s); + if (!ds) + return 1; + wxDC* d = ds.dc(); + wxRect r = s->DeviceRect(lprc->left, lprc->top, lprc->right, lprc->bottom); + if (r.width <= 0 || r.height <= 0) + return 1; + int tx = std::max(1, s->DeviceWidth(1)), ty = std::max(1, s->DeviceHeight(1)); + FillDeviceRect(s, d, wxRect(r.x, r.y, r.width, ty), hbr); + FillDeviceRect(s, d, wxRect(r.x, r.y + r.height - ty, r.width, ty), hbr); + FillDeviceRect(s, d, wxRect(r.x, r.y + ty, tx, r.height - 2 * ty), hbr); + FillDeviceRect(s, d, wxRect(r.x + r.width - tx, r.y + ty, tx, r.height - 2 * ty), hbr); + return 1; +} + +BOOL DrawEdge(HDC hdc, LPRECT qrc, UINT edge, UINT grfFlags) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || !qrc) + return FALSE; + UINT sides = grfFlags & BF_RECT; + UINT outer = edge & (BDR_RAISEDOUTER | BDR_SUNKENOUTER); + UINT inner = edge & (BDR_RAISEDINNER | BDR_SUNKENINNER); + bool soft = (grfFlags & BF_SOFT) != 0; + auto colors = [&](UINT bdr, COLORREF& lt, COLORREF& rb) { + if (grfFlags & BF_MONO) { + lt = rb = SysColor(COLOR_WINDOWFRAME); + } else if (grfFlags & BF_FLAT) { + lt = rb = SysColor((bdr & (BDR_RAISEDOUTER | BDR_SUNKENOUTER)) ? COLOR_BTNSHADOW : COLOR_BTNFACE); + } else if (bdr & BDR_RAISEDOUTER) { + lt = SysColor(soft ? COLOR_3DHILIGHT : COLOR_3DLIGHT); + rb = SysColor(COLOR_3DDKSHADOW); + } else if (bdr & BDR_SUNKENOUTER) { + lt = SysColor(soft ? COLOR_3DDKSHADOW : COLOR_3DSHADOW); + rb = SysColor(COLOR_3DHILIGHT); + } else if (bdr & BDR_RAISEDINNER) { + lt = SysColor(soft ? COLOR_3DLIGHT : COLOR_3DHILIGHT); + rb = SysColor(COLOR_3DSHADOW); + } else { + lt = SysColor(soft ? COLOR_3DSHADOW : COLOR_3DDKSHADOW); + rb = SysColor(COLOR_3DLIGHT); + } + }; + wxRect r = s->DeviceRect(qrc->left, qrc->top, qrc->right, qrc->bottom); + { + DrawScope ds(s); + if (ds) { + wxDC* d = ds.dc(); + wxRect cur = r; + for (UINT bdr : {outer, inner}) { + if (!bdr) + continue; + COLORREF lt, rb; + colors(bdr, lt, rb); + EdgeRect(d, cur, sides, lt, rb); + cur = ShrinkEdges(cur, sides); + } + if (grfFlags & BF_MIDDLE) + FillDeviceRectColor(d, cur, + ToWxColour(SysColor((grfFlags & BF_MONO) ? COLOR_WINDOW : COLOR_BTNFACE))); + } + } + if (grfFlags & BF_ADJUST) { + int n = (outer ? 1 : 0) + (inner ? 1 : 0); + int lx = s->LogicalWidth(n), ly = s->LogicalHeight(n); + if (sides & BF_LEFT) + qrc->left += lx; + if (sides & BF_TOP) + qrc->top += ly; + if (sides & BF_RIGHT) + qrc->right -= lx; + if (sides & BF_BOTTOM) + qrc->bottom -= ly; + } + return TRUE; +} + +BOOL DrawFocusRect(HDC hDC, const RECT* lprc) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + if (!s || !lprc) + return FALSE; + DrawScope ds(s); + if (!ds) + return TRUE; + wxDC* d = ds.dc(); + wxRect r = s->DeviceRect(lprc->left, lprc->top, lprc->right, lprc->bottom); + if (r.width <= 0 || r.height <= 0) + return TRUE; + if (s->SupportsLogicalOps(d)) { + d->SetLogicalFunction(wxINVERT); + static const wxDash dots[] = {1, 1}; + wxPen p(*wxBLACK, 1, wxPENSTYLE_USER_DASH); + p.SetDashes(2, dots); + d->SetPen(p); + d->SetBrush(*wxTRANSPARENT_BRUSH); + d->DrawRectangle(r); + d->SetLogicalFunction(wxCOPY); + return TRUE; + } + wxColour c(96, 96, 96); + SetNoPen(d); + SetSolidBrush(d, c); + for (int x = r.x; x < r.GetRight() + 1; x += 2) { + d->DrawRectangle(x, r.y, 1, 1); + d->DrawRectangle(x, r.GetBottom(), 1, 1); + } + for (int y = r.y; y < r.GetBottom() + 1; y += 2) { + d->DrawRectangle(r.x, y, 1, 1); + d->DrawRectangle(r.GetRight(), y, 1, 1); + } + return TRUE; +} + +int SaveDC(HDC hdc) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s) + return 0; + s->saved.push_back(s->a); + AddRefs(s->a); + return static_cast(s->saved.size()); +} + +BOOL RestoreDC(HDC hdc, int nSavedDC) { + GdiLock lock; + DCState* s = DCFromHandle(hdc); + if (!s || s->saved.empty()) + return FALSE; + int depth = static_cast(s->saved.size()); + int index = nSavedDC < 0 ? depth + nSavedDC : nSavedDC - 1; + if (index < 0 || index >= depth) + return FALSE; + DCAttrs target = s->saved[static_cast(index)]; + RestoreAttrs(s, target); + for (int i = depth - 1; i >= index; --i) { + ReleaseRefs(s->saved[static_cast(i)]); + s->saved.pop_back(); + } + return TRUE; +} + +BOOL DrawIcon(HDC hDC, int X, int Y, HICON hIcon) { + GdiLock lock; + DCState* s = DCFromHandle(hDC); + wxIcon* icon = IconFromHandle(hIcon); + if (!s || !icon || !icon->IsOk()) + return FALSE; + DrawScope ds(s); + if (ds) + ds.dc()->DrawIcon(*icon, s->ToDevice(X, Y)); + return TRUE; +} diff --git a/port/mfcwx/src/gdi_internal.h b/port/mfcwx/src/gdi_internal.h new file mode 100644 index 000000000..1e9e50441 --- /dev/null +++ b/port/mfcwx/src/gdi_internal.h @@ -0,0 +1,219 @@ +#pragma once + +// Shared implementation details of the GDI emulation (gdi*.cpp). + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +#include +#include +#include +#include + +namespace mfcwx { + +std::recursive_mutex& GdiMutex(); + +class GdiLock { +public: + GdiLock() { GdiMutex().lock(); } + ~GdiLock() { GdiMutex().unlock(); } + GdiLock(const GdiLock&) = delete; + GdiLock& operator=(const GdiLock&) = delete; +}; + +enum class GdiKind { Pen, Brush, Font, Bitmap, Region, Palette }; + +struct DCState; + +struct GdiObjectImpl { + explicit GdiObjectImpl(GdiKind k) : kind(k) {} + GdiKind kind; + int refs = 1; + bool stock = false; + bool deleted = false; + CGdiObject* permanent = nullptr; + + LOGPEN logPen{}; + DWORD penStyle = 0; + std::vector dashes; + + LOGBRUSH logBrush{}; + int sysColor = -1; + wxBrush brush; + + LOGFONT logFont{}; + bool fontPending = false; + wxFont font; + double emPx = 0; + double scaledFor = 1.0; + wxFont scaledFont; + + wxBitmap bitmap; + int bitsPixel = 32; + SIZE dimension{0, 0}; + DCState* selectedIn = nullptr; + + wxRegion region; +}; + +// Handles (gdi.cpp) +GdiObjectImpl* GdiImpl(HGDIOBJ h); +GdiObjectImpl* GdiImpl(HGDIOBJ h, GdiKind kind); +HGDIOBJ RegisterGdiObject(GdiObjectImpl* impl); +void GdiAddRef(HGDIOBJ h); +void GdiRelease(HGDIOBJ h); +// (HBRUSH)(COLOR_xxx + 1) values accepted by FillRect and window classes; -1 otherwise. +int SysColorBrushIndex(HGDIOBJ h); +HGDIOBJ DefaultBitmapHandle(); +bool IsStockFont(HFONT h); + +wxPen DevicePen(HPEN h, double widthScale); +wxBrush DeviceBrush(HBRUSH h); +wxFont DeviceFont(HFONT h, double scale); +double FontEmPixels(HFONT h); +bool BrushIsHatched(HBRUSH h); +COLORREF BrushColor(HBRUSH h); +bool PenIsNull(HPEN h); +int PenStyle(HPEN h); +int PenWidth(HPEN h); +COLORREF PenColor(HPEN h); + +wxFont MakeFont(const LOGFONT& lf, double* emPx); +double PixelsToPoints(double px); +wxBitmap NewBitmap(int width, int height, double scale, const wxColour& fill); +HBITMAP NewBitmapHandle(const wxBitmap& bmp, int bitsPixel); + +// DCs (gdi_dc.cpp) +enum class DCKind { Info, Borrowed, Window, Memory }; +enum class WinTarget { None, Paint, Client, OverlayPending, Overlay }; + +struct DCAttrs { + HPEN pen = nullptr; + HBRUSH brush = nullptr; + HFONT font = nullptr; + HBITMAP bitmap = nullptr; + HPALETTE palette = nullptr; + COLORREF textColor = 0; + COLORREF bkColor = 0xFFFFFF; + int bkMode = OPAQUE; + int rop2 = R2_COPYPEN; + int stretchMode = BLACKONWHITE; + int polyFillMode = ALTERNATE; + UINT textAlign = 0; + int mapMode = MM_TEXT; + POINT winOrg{0, 0}; + POINT vpOrg{0, 0}; + SIZE winExt{1, 1}; + SIZE vpExt{1, 1}; + POINT pos{0, 0}; + bool hasClip = false; + wxRegion clip; +}; + +struct DCState { + DCKind kind = DCKind::Info; + DCAttrs a; + std::vector saved; + wxDC* dc = nullptr; + std::unique_ptr owned; + wxWindow* window = nullptr; + CDC* owner = nullptr; + WinTarget target = WinTarget::None; + bool fromGetDC = false; + bool paintDC = false; + bool sessionOwner = false; + bool wholeWindow = false; + bool clipDirty = true; + bool bitmapOut = false; + double scale = 1.0; + wxBitmap defaultBitmap; + std::unique_ptr pixels; + + wxDC* Target(bool drawing); + wxDC* Measure(); + void Finish(); + + void Scales(double& sx, double& sy) const; + wxPoint ToDevice(double x, double y) const; + void ToLogical(double& x, double& y) const; + wxRect DeviceRect(int l, int t, int r, int b) const; + int LogicalWidth(int deviceCx) const; + int LogicalHeight(int deviceCy) const; + int DeviceWidth(int logicalCx) const; + int DeviceHeight(int logicalCy) const; + int Dpi() const; + + void ApplyPen(wxDC* d); + void ApplyBrush(wxDC* d, bool fill); + void ApplyFont(wxDC* d); + void ApplyClip(wxDC* d, const wxRect* extra = nullptr); + bool SupportsLogicalOps(wxDC* d) const; + GdiObjectImpl* SelectedBitmap() const; +}; + +DCState* DCFromHandle(HDC h); +inline HDC ToHdc(DCState* s) { return reinterpret_cast(s); } +wxDC& MeasureDC(); +void SyncBitmap(GdiObjectImpl* bmp); +// Pixels of the bitmap selected into a memory DC (physical resolution); null for other DCs. +const wxImage* DCPixels(DCState* s); +// Scale factor of the bitmap a memory DC draws into (the DC's content scale otherwise). +double DCBitmapScale(DCState* s); + +class DrawScope { +public: + explicit DrawScope(DCState* s) : m_s(s), m_dc(s ? s->Target(true) : nullptr) {} + ~DrawScope() { + if (m_dc) + m_s->Finish(); + } + DrawScope(const DrawScope&) = delete; + DrawScope& operator=(const DrawScope&) = delete; + wxDC* dc() const { return m_dc; } + explicit operator bool() const { return m_dc != nullptr; } + +private: + DCState* m_s; + wxDC* m_dc; +}; + +// Fills a device rectangle with a brush, honouring hatch backgrounds and R2 modes. +void FillDeviceRect(DCState* s, wxDC* dc, const wxRect& r, HBRUSH brush); +void FillDeviceRectColor(wxDC* dc, const wxRect& r, const wxColour& c); + +// Text (gdi_text.cpp) +struct DeviceMetrics { + int height = 0; + int ascent = 0; + int descent = 0; + int internalLeading = 0; + int externalLeading = 0; + int aveWidth = 0; + int maxWidth = 0; +}; +DeviceMetrics GetDeviceMetrics(DCState* s, wxDC* dc); +int DeviceTextWidth(wxDC* dc, const wxString& text); + +// Bits (gdi_bits.cpp) +bool BlitImpl(DCState* dst, int x, int y, int w, int h, DCState* src, int xs, int ys, int ws, int hs, DWORD rop); +bool DrawImageImpl(DCState* dst, int x, int y, int w, int h, const wxImage& img, int xs, int ys, int ws, int hs, + DWORD rop); +bool DibToImage(const BITMAPINFO* bmi, const void* bits, UINT usage, wxImage& out, int startScan = 0, + int lines = -1); +bool DdbBitsToImage(int width, int height, int bpp, int stride, const void* bits, wxImage& out); +bool ImageToDdbBits(const wxImage& img, int bpp, std::vector& out, int& stride); +// Applies a raster operation to a device rectangle of a memory DC in software. +bool SoftwareRop(DCState* dst, const wxRect& r, const wxImage* src, DWORD rop, COLORREF pattern); + +} // namespace mfcwx diff --git a/port/mfcwx/src/gdi_text.cpp b/port/mfcwx/src/gdi_text.cpp new file mode 100644 index 000000000..2a0818207 --- /dev/null +++ b/port/mfcwx/src/gdi_text.cpp @@ -0,0 +1,701 @@ +#include "gdi_internal.h" + +#ifdef __WXOSX__ +#include +#endif + +#include +#include +#include + +namespace mfcwx { + +namespace { + +struct Run { + wxString text; + int x; + size_t start; +}; + +struct Line { + wxString text; + int mnemonic = -1; +}; + +wxString StripLineBreaks(const wxString& s) { + wxString out; + out.reserve(s.length()); + for (wxUniChar c : s) + if (c != '\r' && c != '\n') + out += c; + return out; +} + +wxString ProcessPrefix(const wxString& s, int& mnemonic) { + wxString out; + out.reserve(s.length()); + mnemonic = -1; + for (size_t i = 0; i < s.length(); ++i) { + wxUniChar c = s[i]; + if (c == '&') { + if (i + 1 < s.length() && s[i + 1] == '&') { + out += '&'; + ++i; + } else if (i + 1 < s.length()) { + if (mnemonic < 0) + mnemonic = static_cast(out.length()); + } + continue; + } + out += c; + } + return out; +} + +std::vector LayoutRuns(wxDC* dc, const wxString& line, int tabWidth, int* width) { + std::vector runs; + int x = 0; + size_t start = 0; + for (size_t i = 0; i <= line.length(); ++i) { + if (i < line.length() && line[i] != '\t') + continue; + wxString seg = line.Mid(start, i - start); + if (!seg.empty()) { + runs.push_back(Run{seg, x, start}); + x += DeviceTextWidth(dc, seg); + } + if (i < line.length()) { + if (tabWidth > 0) + x = (x / tabWidth + 1) * tabWidth; + else + x += DeviceTextWidth(dc, " "); + } + start = i + 1; + } + if (width) + *width = x; + return runs; +} + +int LineWidth(wxDC* dc, const wxString& line, int tabWidth) { + if (line.Find('\t') == wxNOT_FOUND) + return DeviceTextWidth(dc, line); + int w = 0; + LayoutRuns(dc, line, tabWidth, &w); + return w; +} + +std::vector> WrapParagraph(wxDC* dc, const wxString& p, int maxWidth, int tabWidth) { + std::vector> ranges; + size_t len = p.length(), i = 0; + if (len == 0) { + ranges.emplace_back(0, 0); + return ranges; + } + while (i < len) { + size_t lineStart = i, end = i, j = i; + while (j < len) { + size_t k = j; + while (k < len && p[k] == ' ') + ++k; + while (k < len && p[k] != ' ') + ++k; + int w = LineWidth(dc, p.Mid(lineStart, k - lineStart), tabWidth); + if (w > maxWidth && end > lineStart) + break; + end = k; + j = k; + if (w > maxWidth) + break; + } + if (end == lineStart) + end = std::min(len, lineStart + 1); + ranges.emplace_back(lineStart, end); + i = end; + while (i < len && p[i] == ' ') + ++i; + } + return ranges; +} + +wxString Ellipsize(wxDC* dc, const wxString& line, int maxWidth, UINT fmt) { + const wxString dots = "..."; + if (fmt & DT_PATH_ELLIPSIS) { + int sep = std::max(line.Find('\\', true), line.Find('/', true)); + if (sep > 0) { + wxString head = line.Left(static_cast(sep)), tail = line.Mid(static_cast(sep)); + if (DeviceTextWidth(dc, dots + tail) <= maxWidth) { + size_t lo = 0, hi = head.length(); + while (lo < hi) { + size_t mid = (lo + hi + 1) / 2; + if (DeviceTextWidth(dc, head.Left(mid) + dots + tail) <= maxWidth) + lo = mid; + else + hi = mid - 1; + } + return head.Left(lo) + dots + tail; + } + } + } + size_t lo = 0, hi = line.length(); + while (lo < hi) { + size_t mid = (lo + hi + 1) / 2; + if (DeviceTextWidth(dc, line.Left(mid) + dots) <= maxWidth) + lo = mid; + else + hi = mid - 1; + } + return line.Left(lo) + dots; +} + +void DrawRuns(wxDC* d, const std::vector& runs, int x, int y) { + for (const Run& r : runs) + d->DrawText(r.text, x + r.x, y); +} + +void FillTextBackground(DCState* s, wxDC* d, const wxRect& r) { + if (s->a.bkMode == OPAQUE && r.width > 0 && r.height > 0) { + FillDeviceRectColor(d, r, ToWxColour(s->a.bkColor)); + s->ApplyFont(d); + } +} + +int AlignLeft(UINT align, int refX, int width) { + if ((align & TA_CENTER) == TA_CENTER) + return refX - width / 2; + if (align & TA_RIGHT) + return refX - width; + return refX; +} + +int AlignTop(UINT align, int refY, const DeviceMetrics& m) { + if ((align & TA_BASELINE) == TA_BASELINE) + return refY - m.ascent; + if (align & TA_BOTTOM) + return refY - m.height; + return refY; +} + +void UpdateCurrentPosition(DCState* s, int deviceWidth) { + UINT align = s->a.textAlign; + if (!(align & TA_UPDATECP) || (align & TA_CENTER) == TA_CENTER) + return; + double sx, sy; + s->Scales(sx, sy); + int lw = s->LogicalWidth(deviceWidth); + int dir = sx < 0 ? -1 : 1; + s->a.pos.x += (align & TA_RIGHT) ? -dir * lw : dir * lw; +} + +int Escapement(DCState* s) { + GdiObjectImpl* f = GdiImpl(s->a.font, GdiKind::Font); + if (!f) + return 0; + LONG e = f->logFont.lfEscapement; + return e > -3600 && e < 3600 ? static_cast(e) : 0; +} + +BOOL TextOutImpl(DCState* s, int x, int y, const char* str, int n) { + if (!s || !str) + return FALSE; + if (n < 0) + n = static_cast(strlen(str)); + wxString text = StripLineBreaks(ToWx(str, n)); + DrawScope ds(s); + wxDC* d = ds ? ds.dc() : s->Measure(); + s->ApplyFont(d); + int width = DeviceTextWidth(d, text); + DeviceMetrics m = GetDeviceMetrics(s, d); + POINT ref = (s->a.textAlign & TA_UPDATECP) ? s->a.pos : POINT{x, y}; + wxPoint dp = s->ToDevice(ref.x, ref.y); + int left = AlignLeft(s->a.textAlign, dp.x, width); + int top = AlignTop(s->a.textAlign, dp.y, m); + if (ds) { + int esc = Escapement(s); + if (esc) { + d->DrawRotatedText(text, dp.x, dp.y, esc / 10.0); + } else { + FillTextBackground(s, d, wxRect(left, top, width, m.height)); + d->DrawText(text, left, top); + } + } + UpdateCurrentPosition(s, width); + return TRUE; +} + +int NextTabStop(int x, int origin, int nTabPositions, const int* stops, int defaultTab) { + int rel = x - origin; + if (nTabPositions <= 0 || !stops) { + int t = std::max(1, defaultTab); + return origin + (rel / t + 1) * t; + } + if (nTabPositions == 1) { + int t = std::max(1, std::abs(stops[0])); + return origin + (rel / t + 1) * t; + } + for (int i = 0; i < nTabPositions; ++i) + if (std::abs(stops[i]) > rel) + return origin + std::abs(stops[i]); + return x; +} + +CSize TabbedImpl(DCState* s, int x, int y, const char* str, int n, int nTabPositions, const int* stops, + int nTabOrigin, bool draw) { + if (!s || !str) + return CSize(); + if (n < 0) + n = static_cast(strlen(str)); + wxString text = StripLineBreaks(ToWx(str, n)); + DrawScope scope(draw ? s : nullptr); + wxDC* d = scope ? scope.dc() : s->Measure(); + s->ApplyFont(d); + DeviceMetrics m = GetDeviceMetrics(s, d); + int defaultTab = s->LogicalWidth(8 * m.aveWidth); + POINT ref = (s->a.textAlign & TA_UPDATECP) ? s->a.pos : POINT{x, y}; + int lx = ref.x; + size_t start = 0; + for (size_t i = 0; i <= text.length(); ++i) { + if (i < text.length() && text[i] != '\t') + continue; + wxString seg = text.Mid(start, i - start); + int w = DeviceTextWidth(d, seg); + if (scope && !seg.empty()) { + wxPoint p = s->ToDevice(lx, ref.y); + int top = AlignTop(s->a.textAlign, p.y, m); + FillTextBackground(s, d, wxRect(p.x, top, w, m.height)); + d->DrawText(seg, p.x, top); + } + lx += s->LogicalWidth(w); + if (i < text.length()) + lx = NextTabStop(lx, nTabOrigin, nTabPositions, stops, defaultTab); + start = i + 1; + } + return CSize(lx - ref.x, s->LogicalHeight(m.height)); +} + +int DrawTextImpl(DCState* s, const char* str, int n, LPRECT rc, UINT fmt) { + if (!s || !rc || !str) + return 0; + if (n < 0) + n = static_cast(strlen(str)); + int tabChars = 8; + if (fmt & DT_TABSTOP) { + tabChars = static_cast((fmt >> 8) & 0xFF); + if (!tabChars) + tabChars = 8; + fmt &= ~0xFF00u; + } + bool calc = (fmt & DT_CALCRECT) != 0; + bool single = (fmt & DT_SINGLELINE) != 0; + DrawScope scope(calc ? nullptr : s); + wxDC* d = scope ? scope.dc() : s->Measure(); + s->ApplyFont(d); + DeviceMetrics m = GetDeviceMetrics(s, d); + int lineH = m.height + ((fmt & DT_EXTERNALLEADING) ? m.externalLeading : 0); + int tabW = (fmt & DT_EXPANDTABS) ? tabChars * m.aveWidth : 0; + wxRect R = s->DeviceRect(rc->left, rc->top, rc->right, rc->bottom); + + wxString text = ToWx(str, n); + std::vector paragraphs; + if (single) { + paragraphs.push_back(StripLineBreaks(text)); + } else { + wxString cur; + for (size_t i = 0; i < text.length(); ++i) { + wxUniChar c = text[i]; + if (c == '\r' || c == '\n') { + paragraphs.push_back(cur); + cur.clear(); + if (c == '\r' && i + 1 < text.length() && text[i + 1] == '\n') + ++i; + continue; + } + cur += c; + } + paragraphs.push_back(cur); + } + + std::vector lines; + for (const wxString& para : paragraphs) { + int mnemonic = -1; + wxString p = (fmt & DT_NOPREFIX) ? para : ProcessPrefix(para, mnemonic); + if ((fmt & DT_WORDBREAK) && !single) { + for (const auto& range : WrapParagraph(d, p, R.width, tabW)) { + Line l; + l.text = p.Mid(range.first, range.second - range.first); + if (mnemonic >= static_cast(range.first) && mnemonic < static_cast(range.second)) + l.mnemonic = mnemonic - static_cast(range.first); + lines.push_back(l); + } + } else { + Line l; + l.text = p; + l.mnemonic = mnemonic; + lines.push_back(l); + } + } + + std::vector widths; + int maxW = 0; + for (const Line& l : lines) { + widths.push_back(LineWidth(d, l.text, tabW)); + maxW = std::max(maxW, widths.back()); + } + int total = lineH * static_cast(lines.size()); + double sx, sy; + s->Scales(sx, sy); + if (calc) { + rc->right = rc->left + (sx < 0 ? -1 : 1) * s->LogicalWidth(maxW); + rc->bottom = rc->top + (sy < 0 ? -1 : 1) * s->LogicalHeight(total); + return s->LogicalHeight(total); + } + + int y0 = R.y; + if (single && (fmt & DT_VCENTER)) + y0 = R.y + (R.height - lineH) / 2; + else if (single && (fmt & DT_BOTTOM)) + y0 = R.y + R.height - lineH; + + if (fmt & (DT_END_ELLIPSIS | DT_PATH_ELLIPSIS | DT_WORD_ELLIPSIS)) { + for (size_t i = 0; i < lines.size(); ++i) { + if (widths[i] > R.width) { + lines[i].text = Ellipsize(d, lines[i].text, R.width, fmt); + lines[i].mnemonic = -1; + widths[i] = LineWidth(d, lines[i].text, tabW); + } + } + } + + if (scope) { + bool clip = false; + std::vector xs; + for (size_t i = 0; i < lines.size(); ++i) { + int x = R.x; + if (fmt & DT_CENTER) + x = R.x + (R.width - widths[i]) / 2; + else if (fmt & DT_RIGHT) + x = R.x + R.width - widths[i]; + xs.push_back(x); + int y = y0 + lineH * static_cast(i); + if (x < R.x || x + widths[i] > R.x + R.width || y < R.y || y + lineH > R.y + R.height) + clip = true; + } + if (fmt & DT_NOCLIP) + clip = false; + if (clip) + s->ApplyClip(d, &R); + for (size_t i = 0; i < lines.size(); ++i) { + int y = y0 + lineH * static_cast(i); + FillTextBackground(s, d, wxRect(xs[i], y, widths[i], lineH)); + int w = 0; + std::vector runs = LayoutRuns(d, lines[i].text, tabW, &w); + DrawRuns(d, runs, xs[i], y); + int mn = lines[i].mnemonic; + if (mn >= 0 && mn < static_cast(lines[i].text.length())) { + for (const Run& r : runs) { + if (static_cast(mn) < r.start || static_cast(mn) >= r.start + r.text.length()) + continue; + size_t col = static_cast(mn) - r.start; + int ux = xs[i] + r.x + DeviceTextWidth(d, r.text.Left(col)); + int uw = DeviceTextWidth(d, r.text.Mid(col, 1)); + FillDeviceRectColor(d, wxRect(ux, y + m.ascent + 1, uw, 1), ToWxColour(s->a.textColor)); + s->ApplyFont(d); + } + } + } + if (clip) + s->ApplyClip(d); + } + if (single && (fmt & (DT_VCENTER | DT_BOTTOM))) + return s->LogicalHeight(y0 - R.y + total); + return s->LogicalHeight(total); +} + +DCState* LockedState(HDC h) { return DCFromHandle(h); } + +} // namespace + +DeviceMetrics GetDeviceMetrics(DCState* s, wxDC* dc) { + DeviceMetrics m; + wxFontMetrics fm = dc->GetFontMetrics(); + m.externalLeading = std::max(0, fm.externalLeading); + m.descent = fm.descent; + m.height = fm.height - m.externalLeading; + m.ascent = m.height - m.descent; +#ifdef __WXOSX__ + // Core Graphics puts the baseline at ceil(top + ascent); wx's integer metrics round differently. + if (CTFontRef ct = dc->GetFont().OSXGetCTFont()) { + m.ascent = static_cast(std::ceil(CTFontGetAscent(ct) - 1e-3)); + m.descent = static_cast(std::ceil(CTFontGetDescent(ct) - 1e-3)); + m.externalLeading = static_cast(std::lround(CTFontGetLeading(ct))); + m.height = m.ascent + m.descent; + } +#endif + double sx, sy; + s->Scales(sx, sy); + double em = FontEmPixels(s->a.font) * (IsStockFont(s->a.font) ? 1.0 : std::fabs(sy)); + m.internalLeading = std::max(0, m.height - static_cast(std::lround(em))); + m.aveWidth = fm.averageWidth > 0 ? fm.averageWidth : DeviceTextWidth(dc, "x"); + if (dc->GetFont().IsFixedWidth()) + m.maxWidth = m.aveWidth; + else + m.maxWidth = std::max(DeviceTextWidth(dc, "W"), DeviceTextWidth(dc, "M")); + return m; +} + +int DeviceTextWidth(wxDC* dc, const wxString& text) { + if (text.empty()) + return 0; + wxCoord w = 0, h = 0; + dc->GetTextExtent(text, &w, &h); + return w; +} + +} // namespace mfcwx + +using namespace mfcwx; + +BOOL CDC::TextOut(int x, int y, const char* lpszString, int nCount) { return ::TextOut(m_hDC, x, y, lpszString, nCount); } + +BOOL CDC::TextOut(int x, int y, const CString& str) { + return ::TextOut(m_hDC, x, y, str.GetString(), str.GetLength()); +} + +BOOL CDC::ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, const char* lpszString, UINT nCount, + LPINT lpDxWidths) { + GdiLock lock; + DCState* s = LockedState(m_hDC); + if (!s) + return FALSE; + const char* str = lpszString ? lpszString : ""; + int n = lpszString ? static_cast(nCount) : 0; + DrawScope ds(s); + wxDC* d = ds ? ds.dc() : s->Measure(); + s->ApplyFont(d); + wxRect R; + if (lpRect) + R = s->DeviceRect(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + if (ds && lpRect && (nOptions & ETO_OPAQUE)) { + FillDeviceRectColor(d, R, ToWxColour(s->a.bkColor)); + s->ApplyFont(d); + } + wxString text = StripLineBreaks(ToWx(str, n)); + DeviceMetrics m = GetDeviceMetrics(s, d); + std::vector offsets; + int width = 0; + if (lpDxWidths && !text.empty()) { + int acc = 0; + for (size_t i = 0; i < text.length() && i < static_cast(n); ++i) { + offsets.push_back(s->DeviceWidth(acc)); + acc += lpDxWidths[i]; + } + width = s->DeviceWidth(acc); + } else { + width = DeviceTextWidth(d, text); + } + POINT ref = (s->a.textAlign & TA_UPDATECP) ? s->a.pos : POINT{x, y}; + wxPoint dp = s->ToDevice(ref.x, ref.y); + int left = AlignLeft(s->a.textAlign, dp.x, width); + int top = AlignTop(s->a.textAlign, dp.y, m); + if (ds) { + bool clip = lpRect && (nOptions & ETO_CLIPPED); + if (clip) + s->ApplyClip(d, &R); + if (!(lpRect && (nOptions & ETO_OPAQUE))) + FillTextBackground(s, d, wxRect(left, top, width, m.height)); + if (!offsets.empty()) { + for (size_t i = 0; i < offsets.size(); ++i) + d->DrawText(text.Mid(i, 1), left + offsets[i], top); + } else { + d->DrawText(text, left, top); + } + if (clip) + s->ApplyClip(d); + } + UpdateCurrentPosition(s, width); + return TRUE; +} + +BOOL CDC::ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, const CString& str, LPINT lpDxWidths) { + return ExtTextOut(x, y, nOptions, lpRect, str.GetString(), static_cast(str.GetLength()), lpDxWidths); +} + +CSize CDC::TabbedTextOut(int x, int y, const char* lpszString, int nCount, int nTabPositions, + LPINT lpnTabStopPositions, int nTabOrigin) { + GdiLock lock; + DCState* s = LockedState(m_hDC); + CSize size = TabbedImpl(s, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin, true); + if (s && (s->a.textAlign & TA_UPDATECP)) + s->a.pos.x += size.cx; + return size; +} + +int CDC::DrawText(const char* lpszString, int nCount, LPRECT lpRect, UINT nFormat) { + return ::DrawText(m_hDC, lpszString, nCount, lpRect, nFormat); +} + +int CDC::DrawText(const CString& str, LPRECT lpRect, UINT nFormat) { + return ::DrawText(m_hDC, str.GetString(), str.GetLength(), lpRect, nFormat); +} + +CSize CDC::GetTextExtent(const char* lpszString, int nCount) const { + SIZE sz{0, 0}; + ::GetTextExtentPoint32(m_hDC, lpszString, nCount, &sz); + return CSize(sz); +} + +CSize CDC::GetTextExtent(const CString& str) const { return GetTextExtent(str.GetString(), str.GetLength()); } + +CSize CDC::GetTabbedTextExtent(const char* lpszString, int nCount, int nTabPositions, LPINT lpnTabStopPositions) const { + GdiLock lock; + return TabbedImpl(LockedState(m_hDC), 0, 0, lpszString, nCount, nTabPositions, lpnTabStopPositions, 0, false); +} + +BOOL CDC::GetTextExtentExPoint(const char* lpszString, int nCount, int nMaxExtent, LPINT lpnFit, LPINT alpDx, + LPSIZE lpSize) const { + GdiLock lock; + DCState* s = LockedState(m_hDC); + if (!s || !lpszString) + return FALSE; + if (nCount < 0) + nCount = static_cast(strlen(lpszString)); + wxDC* d = s->Measure(); + wxString text = ToWx(lpszString, nCount); + wxArrayInt widths; + if (!text.empty()) + d->GetPartialTextExtents(text, widths); + int fit = 0; + for (size_t i = 0; i < widths.size(); ++i) { + int lw = s->LogicalWidth(widths[i]); + if (lw <= nMaxExtent || !lpnFit) + fit = static_cast(i) + 1; + if (alpDx && (static_cast(i) < fit || !lpnFit)) + alpDx[i] = lw; + } + if (lpnFit) + *lpnFit = fit; + if (lpSize) { + DeviceMetrics m = GetDeviceMetrics(s, d); + lpSize->cx = widths.empty() ? 0 : s->LogicalWidth(widths.back()); + lpSize->cy = s->LogicalHeight(m.height); + } + return TRUE; +} + +BOOL CDC::GetTextMetrics(LPTEXTMETRIC lpMetrics) const { return ::GetTextMetrics(m_hDC, lpMetrics); } + +int CDC::GetTextFace(int nCount, char* lpszFacename) const { + GdiLock lock; + DCState* s = LockedState(m_hDC); + if (!s) + return 0; + LOGFONT lf; + memset(&lf, 0, sizeof lf); + ::GetObject(s->a.font, sizeof lf, &lf); + int len = static_cast(strnlen(lf.lfFaceName, LF_FACESIZE)); + if (!lpszFacename) + return len + 1; + if (nCount <= 0) + return 0; + int n = std::min(len, nCount - 1); + memcpy(lpszFacename, lf.lfFaceName, static_cast(n)); + lpszFacename[n] = 0; + return n; +} + +int CDC::GetTextFace(CString& rString) const { + char buf[LF_FACESIZE + 1]; + int n = GetTextFace(sizeof buf, buf); + rString = buf; + return n; +} + +BOOL CDC::GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const { + GdiLock lock; + DCState* s = LockedState(m_hDC); + if (!s || !lpBuffer || nLastChar < nFirstChar) + return FALSE; + wxDC* d = s->Measure(); + for (UINT c = nFirstChar; c <= nLastChar; ++c) { + char ch = static_cast(c & 0xFF); + lpBuffer[c - nFirstChar] = s->LogicalWidth(DeviceTextWidth(d, ToWx(&ch, 1))); + } + return TRUE; +} + +BOOL TextOut(HDC hdc, int x, int y, const char* lpString, int c) { + GdiLock lock; + return TextOutImpl(LockedState(hdc), x, y, lpString, c); +} + +BOOL TextOutA(HDC hdc, int x, int y, const char* lpString, int c) { return TextOut(hdc, x, y, lpString, c); } + +int DrawText(HDC hdc, const char* lpchText, int cchText, LPRECT lprc, UINT format) { + GdiLock lock; + return DrawTextImpl(LockedState(hdc), lpchText, cchText, lprc, format); +} + +int DrawTextA(HDC hdc, const char* lpchText, int cchText, LPRECT lprc, UINT format) { + return DrawText(hdc, lpchText, cchText, lprc, format); +} + +BOOL GetTextExtentPoint32(HDC hdc, const char* lpString, int c, LPSIZE psizl) { + GdiLock lock; + DCState* s = LockedState(hdc); + if (!s || !psizl) + return FALSE; + if (!lpString) + c = 0; + if (c < 0) + c = static_cast(strlen(lpString)); + wxDC* d = s->Measure(); + DeviceMetrics m = GetDeviceMetrics(s, d); + psizl->cx = c ? s->LogicalWidth(DeviceTextWidth(d, StripLineBreaks(ToWx(lpString, c)))) : 0; + psizl->cy = s->LogicalHeight(m.height); + return TRUE; +} + +BOOL GetTextExtentPoint32A(HDC hdc, const char* lpString, int c, LPSIZE psizl) { + return GetTextExtentPoint32(hdc, lpString, c, psizl); +} + +BOOL GetTextMetrics(HDC hdc, LPTEXTMETRIC lptm) { + GdiLock lock; + DCState* s = LockedState(hdc); + if (!s || !lptm) + return FALSE; + wxDC* d = s->Measure(); + DeviceMetrics m = GetDeviceMetrics(s, d); + LOGFONT lf; + memset(&lf, 0, sizeof lf); + ::GetObject(s->a.font, sizeof lf, &lf); + memset(lptm, 0, sizeof *lptm); + lptm->tmHeight = s->LogicalHeight(m.height); + lptm->tmAscent = s->LogicalHeight(m.ascent); + lptm->tmDescent = lptm->tmHeight - lptm->tmAscent; + lptm->tmInternalLeading = s->LogicalHeight(m.internalLeading); + lptm->tmExternalLeading = s->LogicalHeight(m.externalLeading); + lptm->tmAveCharWidth = s->LogicalWidth(m.aveWidth); + lptm->tmMaxCharWidth = s->LogicalWidth(m.maxWidth); + lptm->tmWeight = lf.lfWeight ? lf.lfWeight : FW_NORMAL; + lptm->tmOverhang = 0; + lptm->tmDigitizedAspectX = 96; + lptm->tmDigitizedAspectY = 96; + lptm->tmFirstChar = 0x20; + lptm->tmLastChar = 0xFF; + lptm->tmDefaultChar = 0x1F; + lptm->tmBreakChar = 0x20; + lptm->tmItalic = lf.lfItalic ? 1 : 0; + lptm->tmUnderlined = lf.lfUnderline ? 1 : 0; + lptm->tmStruckOut = lf.lfStrikeOut ? 1 : 0; + bool fixed = d->GetFont().IsFixedWidth(); + BYTE family = static_cast(lf.lfPitchAndFamily & 0xF0); + if (!family) + family = static_cast(fixed ? FF_MODERN : FF_SWISS); + lptm->tmPitchAndFamily = static_cast(family | (fixed ? 0 : 0x01) | 0x02 | 0x04); + lptm->tmCharSet = lf.lfCharSet; + return TRUE; +} + +BOOL GetTextMetricsA(HDC hdc, LPTEXTMETRIC lptm) { return GetTextMetrics(hdc, lptm); } diff --git a/port/mfcwx/src/gl.cpp b/port/mfcwx/src/gl.cpp new file mode 100644 index 000000000..b3830ee93 --- /dev/null +++ b/port/mfcwx/src/gl.cpp @@ -0,0 +1,199 @@ +#include "windows_impl.h" + +#ifdef __APPLE__ +#include +#else +#include +#endif +#include + +#include +#include + +namespace mfcwx { + +namespace { + +// A GL canvas covering the client area of a window that asked for an OpenGL pixel format. Paint, +// mouse and keyboard input are forwarded to the window, which renders through the WGL calls. +class GLSurface : public wxGLCanvas { +public: + GLSurface(wxWindow* owner, const int* attribs) + : wxGLCanvas(owner, wxID_ANY, attribs, wxPoint(0, 0), owner->GetClientSize(), wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS), + m_owner(owner) { + Bind(wxEVT_PAINT, [this](wxPaintEvent&) { + wxPaintDC dc(this); + if (IsManagedWindow(m_owner)) + DispatchMessageTo(ToHwnd(m_owner), WM_PAINT, 0, 0); + }); + Bind(wxEVT_ERASE_BACKGROUND, [](wxEraseEvent&) {}); + owner->Bind(wxEVT_SIZE, [this](wxSizeEvent& e) { + SetSize(m_owner->GetClientSize()); + e.Skip(); + }); + auto forwardMouse = [this](wxMouseEvent& e, UINT msg) { + if (IsManagedWindow(m_owner)) + DispatchMessageTo(ToHwnd(m_owner), msg, MouseFlags(e), MAKELPARAM(e.GetX(), e.GetY())); + e.Skip(); + }; + Bind(wxEVT_LEFT_DOWN, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_LBUTTONDOWN); }); + Bind(wxEVT_LEFT_UP, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_LBUTTONUP); }); + Bind(wxEVT_LEFT_DCLICK, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_LBUTTONDBLCLK); }); + Bind(wxEVT_RIGHT_DOWN, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_RBUTTONDOWN); }); + Bind(wxEVT_RIGHT_UP, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_RBUTTONUP); }); + Bind(wxEVT_MIDDLE_DOWN, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_MBUTTONDOWN); }); + Bind(wxEVT_MIDDLE_UP, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_MBUTTONUP); }); + Bind(wxEVT_MOTION, [forwardMouse](wxMouseEvent& e) { forwardMouse(e, WM_MOUSEMOVE); }); + Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent& e) { + int delta = e.GetWheelRotation() * WHEEL_DELTA / std::max(1, e.GetWheelDelta()); + wxPoint screen = ClientToScreen(e.GetPosition()); + if (IsManagedWindow(m_owner)) + DispatchMessageTo(ToHwnd(m_owner), WM_MOUSEWHEEL, + MAKEWPARAM(MouseFlags(e), static_cast(static_cast(delta))), + MAKELPARAM(screen.x, screen.y)); + }); + auto forwardKey = [this](wxKeyEvent& e, UINT msg) { + UINT vk = VirtualKeyFromWx(e.GetKeyCode()); + if (vk && IsManagedWindow(m_owner)) + DispatchMessageTo(ToHwnd(m_owner), msg, vk, KeyLParam(e, msg == WM_KEYUP)); + e.Skip(); + }; + Bind(wxEVT_KEY_DOWN, [forwardKey](wxKeyEvent& e) { forwardKey(e, WM_KEYDOWN); }); + Bind(wxEVT_KEY_UP, [forwardKey](wxKeyEvent& e) { forwardKey(e, WM_KEYUP); }); + } + +private: + wxWindow* m_owner; +}; + +struct GLContextHandle { + wxGLContext* context = nullptr; + GLSurface* surface = nullptr; +}; + +std::map& Surfaces() { + static std::map s; + return s; +} + +HGLRC g_current = nullptr; +HDC g_currentDC = nullptr; + +wxWindow* WindowOfDC(HDC hdc) { + CDC* dc = hdc ? CDC::FromHandle(hdc) : nullptr; + CWnd* wnd = dc ? dc->GetWindow() : nullptr; + return wnd && wnd->m_hWnd ? wnd->GetWx() : nullptr; +} + +GLSurface* SurfaceFor(HDC hdc) { + wxWindow* w = WindowOfDC(hdc); + if (!w) + return nullptr; + auto it = Surfaces().find(w); + return it == Surfaces().end() ? nullptr : it->second; +} + +} // namespace + +} // namespace mfcwx + +using namespace mfcwx; + +int ChoosePixelFormat(HDC, const PIXELFORMATDESCRIPTOR*) { return 1; } + +BOOL SetPixelFormat(HDC hdc, int, const PIXELFORMATDESCRIPTOR* ppfd) { + return OnMain([&]() -> BOOL { + wxWindow* w = WindowOfDC(hdc); + if (!w) + return FALSE; + if (Surfaces().count(w)) + return TRUE; + int depth = ppfd && ppfd->cDepthBits ? ppfd->cDepthBits : 24; + std::vector attribs = {WX_GL_RGBA, WX_GL_DEPTH_SIZE, depth}; + if (!ppfd || (ppfd->dwFlags & PFD_DOUBLEBUFFER)) + attribs.push_back(WX_GL_DOUBLEBUFFER); + attribs.push_back(0); + auto* surface = new GLSurface(w, attribs.data()); + Surfaces()[w] = surface; + w->Bind(wxEVT_DESTROY, [w](wxWindowDestroyEvent& e) { + if (e.GetWindow() == w) + Surfaces().erase(w); + e.Skip(); + }); + return TRUE; + }); +} + +int GetPixelFormat(HDC hdc) { return SurfaceFor(hdc) ? 1 : 0; } + +int DescribePixelFormat(HDC, int, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) { + if (ppfd && nBytes >= sizeof(PIXELFORMATDESCRIPTOR)) { + memset(ppfd, 0, sizeof *ppfd); + ppfd->nSize = sizeof *ppfd; + ppfd->nVersion = 1; + ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + ppfd->iPixelType = PFD_TYPE_RGBA; + ppfd->cColorBits = 32; + ppfd->cRedBits = ppfd->cGreenBits = ppfd->cBlueBits = ppfd->cAlphaBits = 8; + ppfd->cDepthBits = 24; + ppfd->iLayerType = PFD_MAIN_PLANE; + } + return 1; +} + +BOOL SwapBuffers(HDC hdc) { + return OnMain([&]() -> BOOL { + GLSurface* s = SurfaceFor(hdc); + if (!s && g_current) + s = reinterpret_cast(g_current)->surface; + return s ? s->SwapBuffers() : FALSE; + }); +} + +HGLRC wglCreateContext(HDC hdc) { + return OnMain([&]() -> HGLRC { + GLSurface* s = SurfaceFor(hdc); + if (!s) + return nullptr; + auto* h = new GLContextHandle; + h->surface = s; + h->context = new wxGLContext(s); + return reinterpret_cast(h); + }); +} + +BOOL wglDeleteContext(HGLRC hglrc) { + if (!hglrc) + return FALSE; + OnMain([&] { + auto* h = reinterpret_cast(hglrc); + if (g_current == hglrc) { + g_current = nullptr; + g_currentDC = nullptr; + } + delete h->context; + delete h; + }); + return TRUE; +} + +BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc) { + return OnMain([&]() -> BOOL { + g_current = hglrc; + g_currentDC = hdc; + if (!hglrc) + return TRUE; + auto* h = reinterpret_cast(hglrc); + GLSurface* s = SurfaceFor(hdc); + if (!s) + s = h->surface; + if (!s || !s->IsShownOnScreen()) + return TRUE; + return s->SetCurrent(*h->context) ? TRUE : FALSE; + }); +} + +HGLRC wglGetCurrentContext() { return g_current; } +HDC wglGetCurrentDC() { return g_currentDC; } + +void* wglGetProcAddress(const char* name) { return dlsym(RTLD_DEFAULT, name); } diff --git a/port/mfcwx/src/globalmem.h b/port/mfcwx/src/globalmem.h new file mode 100644 index 000000000..dd9a521f2 --- /dev/null +++ b/port/mfcwx/src/globalmem.h @@ -0,0 +1,40 @@ +#pragma once + +// HGLOBAL/HLOCAL layout: the handle is the data pointer (GlobalLock(h) == h, so GMEM_FIXED +// callers may use the handle directly), preceded by a GlobalHeader. + +#include "mfcwx/win32.h" + +#include + +namespace mfcwx { + +struct GlobalHeader { + unsigned magic; + unsigned flags; + size_t size; + long lockCount; + size_t reserved; +}; + +static_assert(sizeof(GlobalHeader) % 16 == 0, "data must stay 16-byte aligned"); + +constexpr unsigned kGlobalMagic = 0x474C4D58u; + +inline GlobalHeader* GlobalHeaderOf(HGLOBAL h) { + if (!h) + return nullptr; + auto* header = reinterpret_cast(static_cast(h) - sizeof(GlobalHeader)); + return header->magic == kGlobalMagic ? header : nullptr; +} + +// Allocates an HGLOBAL holding a copy of data (size bytes; data may be null for zeroed memory). +HGLOBAL GlobalFromData(const void* data, size_t size, UINT flags = GMEM_MOVEABLE); +bool GlobalIsValid(HGLOBAL h); +inline void* GlobalData(HGLOBAL h) { return GlobalHeaderOf(h) ? h : nullptr; } +inline size_t GlobalDataSize(HGLOBAL h) { + GlobalHeader* header = GlobalHeaderOf(h); + return header ? header->size : 0; +} + +} // namespace mfcwx diff --git a/port/mfcwx/src/help.cpp b/port/mfcwx/src/help.cpp new file mode 100644 index 000000000..37971f678 --- /dev/null +++ b/port/mfcwx/src/help.cpp @@ -0,0 +1,681 @@ +#include "windows_impl.h" + +#include "htmlhelp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace mfcwx { + +namespace { + +const char kIndexFileName[] = "CrypTool.helpindex"; +const char kDataFileScheme[] = "cryptool-data:"; + +struct HelpIndex { + wxString dir; + wxString baseUrl; + wxString title; + wxString defaultTopic; + wxString contentsFile; + wxString indexFile; + std::map contexts; + std::multimap alinks; + std::multimap keywords; + std::map titles; + std::map pages; +}; + +wxString HelpRoot() { return wxFileName::DirName(wxString::FromUTF8(GetDataDirectory())).GetPath(); } + +wxString HelpDirectory() { + return HelpRoot() + wxFILE_SEP_PATH + (strcmp(GetResourceLanguage(), "de") == 0 ? "hlp_de" : "hlp_en"); +} + +wxString FileUrl(const wxString& path) { return wxFileSystem::FileNameToURL(wxFileName(path)); } + +// Help pages are served through a "cthelp:" protocol so they can be adjusted before wxHTML parses them. +const char kHelpProtocol[] = "cthelp"; + +wxString HelpUrl(const wxString& path) { return kHelpProtocol + FileUrl(path).Mid(4); } + +wxString PathFromHelpUrl(const wxString& url) { + return wxFileSystem::URLToFileName("file" + url.BeforeFirst('#').Mid(strlen(kHelpProtocol))).GetFullPath(); +} + +std::unique_ptr ReadIndex(const wxString& dir) { + std::ifstream in(std::string(wxFileName(dir, kIndexFileName).GetFullPath().utf8_str()), std::ios::binary); + std::string line; + if (!in || !std::getline(in, line) || line.compare(0, 18, "CrypToolHelpIndex\t") != 0) + return nullptr; + std::unique_ptr index(new HelpIndex); + index->dir = dir; + index->baseUrl = HelpUrl(dir + wxFILE_SEP_PATH); + if (!index->baseUrl.EndsWith("/")) + index->baseUrl += "/"; + while (std::getline(in, line)) { + if (!line.empty() && line.back() == '\r') + line.pop_back(); + wxArrayString f = wxSplit(wxString::FromUTF8(line.c_str()), '\t', 0); + if (f.size() < 2) + continue; + const wxString& kind = f[0]; + if (kind == "title") + index->title = f[1]; + else if (kind == "default") + index->defaultTopic = f[1]; + else if (kind == "contents") + index->contentsFile = f[1]; + else if (kind == "index") + index->indexFile = f[1]; + else if (f.size() < 3) + continue; + else if (kind == "context") + index->contexts[static_cast(wxAtol(f[1]))] = f[2]; + else if (kind == "alink") + index->alinks.emplace(f[1].Lower(), f[2]); + else if (kind == "keyword") + index->keywords.emplace(f[1].Lower(), f[2]); + else if (kind == "topic") { + index->titles[f[1]] = f[2]; + index->pages[f[1].Lower()] = f[1]; + } + } + return index; +} + +const HelpIndex* CurrentIndex() { + static std::map> cache; + wxString dir = HelpDirectory(); + auto it = cache.find(dir); + if (it == cache.end() || !it->second) + it = cache.emplace(dir, ReadIndex(dir)).first; + if (!it->second) { + cache.erase(it); + wxLogDebug("mfcwx: no help index in %s", dir); + return nullptr; + } + return it->second.get(); +} + +// Topic and image references in the help are not reliably cased. +wxString ResolveCaseInsensitive(const wxString& path) { + if (wxFileExists(path)) + return path; + wxString root = HelpRoot(); + if (!path.StartsWith(root + wxFILE_SEP_PATH)) + return wxString(); + wxString resolved = root; + wxStringTokenizer parts(path.Mid(root.length() + 1), wxFILE_SEP_PATH, wxTOKEN_STRTOK); + while (parts.HasMoreTokens()) { + wxString part = parts.GetNextToken(); + wxString exact = resolved + wxFILE_SEP_PATH + part; + if (wxFileName::Exists(exact)) { + resolved = exact; + continue; + } + wxDir dir(resolved); + wxString name, match; + for (bool more = dir.IsOpened() && dir.GetFirst(&name); more; more = dir.GetNext(&name)) + if (name.CmpNoCase(part) == 0) { + match = name; + break; + } + if (match.empty()) + return wxString(); + resolved += wxFILE_SEP_PATH + match; + } + return wxFileExists(resolved) ? resolved : wxString(); +} + +wxString BrowserUrl(const wxString& url) { + if (!url.StartsWith(wxString(kHelpProtocol) + ":")) + return url; + wxString anchor = url.AfterFirst('#'); + wxString path = ResolveCaseInsensitive(PathFromHelpUrl(url)); + return FileUrl(path.empty() ? PathFromHelpUrl(url) : path) + (anchor.empty() ? wxString() : "#" + anchor); +} + +// Pages without a charset are Windows-1252; script-only file links (helper.js parser()) become plain links. +std::string PreparePage(const std::string& page) { + static const std::string open = "onclick=\"parser('"; + static const std::string close = "')\""; + std::string lower(page); + std::transform(lower.begin(), lower.end(), lower.begin(), + [](unsigned char c) { return static_cast(tolower(c)); }); + std::string out; + if (lower.find("charset") == std::string::npos) + out = "\n"; + size_t pos = 0; + for (size_t hit; (hit = lower.find(open, pos)) != std::string::npos;) { + size_t start = hit + open.size(); + size_t end = page.find(close, start); + if (end == std::string::npos) + break; + bool web = lower.compare(start, 5, "http:") == 0 || lower.compare(start, 6, "https:") == 0; + out += page.substr(pos, hit - pos) + "href=\"" + (web ? "" : kDataFileScheme) + + page.substr(start, end - start) + "\""; + pos = end + close.size(); + } + return out + page.substr(pos); +} + +class HelpFSHandler : public wxFileSystemHandler { +public: + bool CanOpen(const wxString& location) override { return GetProtocol(location) == kHelpProtocol; } + + wxFSFile* OpenFile(wxFileSystem&, const wxString& location) override { + wxString path = ResolveCaseInsensitive(PathFromHelpUrl(location)); + if (path.empty()) + return nullptr; + std::unique_ptr stream(new wxFFileInputStream(path)); + if (!stream->IsOk()) + return nullptr; + wxString lower = path.Lower(); + if (lower.EndsWith(".html") || lower.EndsWith(".htm")) { + std::string page(static_cast(stream->GetLength()), '\0'); + stream->Read(&page[0], page.size()); + page = PreparePage(page.substr(0, stream->LastRead())); + wxMemoryOutputStream copy; + copy.Write(page.data(), page.size()); + stream.reset(new wxMemoryInputStream(copy)); + } + return new wxFSFile(stream.release(), location.BeforeFirst('#'), GetMimeTypeFromExt(path), + GetAnchor(location), wxDateTime(wxFileModificationTime(path))); + } +}; + +wxString UiString(UINT id, const char* fallback) { + std::string s; + return LoadResourceString(id, s) && !s.empty() ? ToWx(s.c_str()) : wxString(fallback); +} + +void OpenDataFile(wxWindow* parent, const wxString& relative) { + wxString rel = relative; + rel.Replace("\\", "/"); + wxString path = ResolveCaseInsensitive(HelpRoot() + wxFILE_SEP_PATH + rel); + if (path.empty() || !wxLaunchDefaultApplication(path)) { + wxString text = wxString::Format("%s\n%s", UiString(AFX_IDP_FAILED_TO_LAUNCH_HELP, "Failed to launch help."), + HelpRoot() + wxFILE_SEP_PATH + rel); + ShowMessageBox(parent, FromWx(text).c_str(), nullptr, MB_OK | MB_ICONEXCLAMATION); + } +} + +bool IsExternalUrl(const wxString& href) { + wxString scheme = href.BeforeFirst(':'); + if (scheme.length() < 2 || scheme.length() == href.length()) + return false; + for (wxUniChar c : scheme) + if (!wxIsalnum(c) && c != '+' && c != '-' && c != '.') + return false; + return scheme.CmpNoCase("file") != 0; +} + +int OpenInBrowserId() { + static const int id = wxWindow::NewControlId(); + return id; +} + +template +class HelpWindowShell : public Base { +public: + explicit HelpWindowShell(wxHtmlHelpData* data) : Base(data) { + this->Bind(wxEVT_HTML_LINK_CLICKED, &HelpWindowShell::OnLink, this); + this->Bind(wxEVT_TOOL, &HelpWindowShell::OnOpenInBrowser, this, OpenInBrowserId()); + } + + void AddToolbarButtons(wxToolBar* toolBar, int) override { + toolBar->AddSeparator(); + toolBar->AddTool(OpenInBrowserId(), _("Open in browser"), wxArtProvider::GetBitmap(wxART_HELP_PAGE, wxART_TOOLBAR), + _("Open this page in the web browser")); + } + +private: + void OnLink(wxHtmlLinkEvent& event) { + const wxMouseEvent* mouse = event.GetLinkInfo().GetEvent(); + wxString href = event.GetLinkInfo().GetHref(); + if (mouse && !mouse->LeftUp()) { + event.Skip(); + } else if (href.StartsWith(kDataFileScheme)) { + OpenDataFile(this, href.Mid(strlen(kDataFileScheme))); + } else if (IsExternalUrl(href)) { + wxLaunchDefaultBrowser(href); + } else { + event.Skip(); + } + } + + void OnOpenInBrowser(wxCommandEvent&) { + wxHtmlWindow* html = this->GetHelpWindow() ? this->GetHelpWindow()->GetHtmlWindow() : nullptr; + if (!html || html->GetOpenedPage().empty()) + return; + wxString url = html->GetOpenedPage(); + if (!html->GetOpenedAnchor().empty()) + url += "#" + html->GetOpenedAnchor(); + wxLaunchDefaultBrowser(BrowserUrl(url)); + } +}; + +using HelpFrame = HelpWindowShell; +using HelpDialog = HelpWindowShell; + +wxSize DefaultHelpSize(wxWindow* w) { return w->FromDIP(wxSize(1000, 720)); } + +class HelpController : public wxHtmlHelpController { +public: + explicit HelpController(const HelpIndex& index) : wxHtmlHelpController(wxHF_DEFAULT_STYLE) { + wxString title = index.title; + title.Replace("%", "%%"); + SetTitleFormat(title.empty() ? wxString("%s") : title + " - %s"); + wxFileSystem fs; + std::unique_ptr book(fs.OpenFile(FileUrl(wxFileName(index.dir, kIndexFileName).GetFullPath()))); + m_loaded = book && GetHelpData()->AddBookParam(*book, wxFONTENCODING_SYSTEM, index.title, index.contentsFile, + index.indexFile, index.defaultTopic, index.baseUrl); + } + + bool IsLoaded() const { return m_loaded; } + wxHtmlHelpFrame* Frame() const { return m_helpFrame; } + +protected: + wxHtmlHelpFrame* CreateHelpFrame(wxHtmlHelpData* data) override { + HelpFrame* frame = new HelpFrame(data); + frame->SetController(this); + frame->SetTitleFormat(m_titleFormat); +#if wxUSE_CONFIG + frame->Create(m_parentWindow, wxID_ANY, wxEmptyString, m_FrameStyle, m_Config, m_ConfigRoot); + bool configured = m_Config != nullptr; +#else + frame->Create(m_parentWindow, wxID_ANY, wxEmptyString, m_FrameStyle); + bool configured = false; +#endif + frame->SetShouldPreventAppExit(m_shouldPreventAppExit); + if (!configured) { + frame->SetSize(DefaultHelpSize(frame)); + frame->Centre(); + } + m_helpFrame = frame; + return frame; + } + +private: + bool m_loaded = false; +}; + +enum class Pane { Page, Contents, Index }; + +struct HelpRequest { + wxString topic; + Pane pane = Pane::Page; +}; + +struct HelpState { + HelpController* controller = nullptr; + wxString controllerDir; + std::vector> controllers; + HelpDialog* modalHelp = nullptr; + HelpRequest pending; + bool pendingScheduled = false; +}; + +// Never destroyed: the controllers must not outlive the wx windows they point to at exit. +HelpState& State() { + static HelpState* state = new HelpState; + return *state; +} + +HelpController* ControllerFor(const HelpIndex& index) { + HelpState& st = State(); + if (st.controller && st.controllerDir == index.dir) + return st.controller; + if (st.controller) + st.controller->Quit(); + static bool registered = false; + if (!registered) { + registered = true; + wxFileSystem::AddHandler(new HelpFSHandler); + } + std::unique_ptr c(new HelpController(index)); + if (!c->IsLoaded()) + return nullptr; + st.controller = c.get(); + st.controllerDir = index.dir; + st.controllers.push_back(std::move(c)); + return st.controller; +} + +wxDialog* ActiveModalDialog() { + wxDialog* found = nullptr; + for (wxWindow* w : wxTopLevelWindows) { + wxDialog* d = wxDynamicCast(w, wxDialog); + if (d && d->IsModal() && d->IsShown()) + found = d; + } + return found; +} + +HWND PseudoHelpWindow() { + static char tag; + return reinterpret_cast(&tag); +} + +HWND HelpWindowHandle() { + HelpState& st = State(); + if (st.modalHelp) + return ToHwnd(st.modalHelp); + if (st.controller && st.controller->Frame()) + return ToHwnd(st.controller->Frame()); + return PseudoHelpWindow(); +} + +void Present(wxHtmlHelpWindow* window, const HelpRequest& request) { + if (request.pane == Pane::Contents) + window->DisplayContents(); + else if (request.pane == Pane::Index) + window->DisplayIndex(); + if (!request.topic.empty()) + window->Display(request.topic); +} + +void RunModalHelp(wxDialog* parent, HelpController* controller, const wxString& title, const HelpRequest& request) { + HelpState& st = State(); + HelpDialog dlg(controller->GetHelpData()); + dlg.Create(parent, wxID_ANY, wxEmptyString, wxHF_DEFAULT_STYLE); + if (!title.empty()) + dlg.SetTitle(title); + dlg.SetSize(DefaultHelpSize(&dlg)); + dlg.CentreOnParent(); + Present(dlg.GetHelpWindow(), request); + st.modalHelp = &dlg; + dlg.ShowModal(); + st.modalHelp = nullptr; +} + +void Display(const HelpRequest& request) { + HelpState& st = State(); + const HelpIndex* index = CurrentIndex(); + HelpController* controller = index ? ControllerFor(*index) : nullptr; + if (!controller) + return; + if (st.modalHelp) { + Present(st.modalHelp->GetHelpWindow(), request); + st.modalHelp->Raise(); + } else if (wxDialog* modal = ActiveModalDialog()) { + RunModalHelp(modal, controller, index->title, request); + } else { + if (request.pane == Pane::Contents) + controller->DisplayContents(); + else if (request.pane == Pane::Index) + controller->DisplayIndex(); + if (!request.topic.empty()) + controller->Display(request.topic); + if (wxHtmlHelpFrame* frame = controller->Frame()) { + frame->Show(); + frame->Raise(); + } + } +} + +void ShowPending() { + HelpState& st = State(); + if (!st.pendingScheduled) + return; + st.pendingScheduled = false; + Display(st.pending); +} + +// Frames get no input while a modal dialog runs (macOS, GTK), so the help is then shown modally, deferred. +HWND Show(const HelpIndex& index, const HelpRequest& request) { + if (!ControllerFor(index)) + return nullptr; + HelpState& st = State(); + if (!st.modalHelp && !ActiveModalDialog()) { + Display(request); + } else { + st.pending = request; + if (!st.pendingScheduled) { + st.pendingScheduled = true; + wxTheApp->CallAfter(&ShowPending); + } + } + return HelpWindowHandle(); +} + +// "file.chm::/topic.html>window" or "topic.html#anchor" to a topic file relative to the help directory. +wxString TopicFromReference(const wxString& reference) { + wxString topic = reference; + int sep = topic.Find("::"); + if (sep != wxNOT_FOUND) + topic = topic.Mid(sep + 2); + topic = topic.BeforeFirst('>'); + topic.Replace("\\", "/"); + while (topic.StartsWith("/")) + topic.Remove(0, 1); + return topic; +} + +// A topic as the help data expects it: relative to the help directory, in the file's case. +wxString TopicPath(const HelpIndex& index, const wxString& topic) { + wxString file = topic.BeforeFirst('#'); + wxString anchor = topic.AfterFirst('#'); + auto page = index.pages.find(file.Lower()); + if (page != index.pages.end()) { + file = page->second; + } else { + wxString path = ResolveCaseInsensitive(index.dir + wxFILE_SEP_PATH + file); + if (file.empty() || path.empty()) + return wxString(); + file = path.Mid(index.dir.length() + 1); + file.Replace("\\", "/"); + } + return file + (anchor.empty() ? wxString() : "#" + anchor); +} + +HWND ShowTopic(const HelpIndex& index, const wxString& topic, Pane pane = Pane::Page) { + if (IsExternalUrl(topic) && !topic.Lower().StartsWith("mk:") && !topic.Lower().StartsWith("ms-its:")) { + wxLaunchDefaultBrowser(topic); + return PseudoHelpWindow(); + } + HelpRequest request; + request.topic = TopicPath(index, topic); + request.pane = pane; + if (request.topic.empty() && pane == Pane::Page) + return nullptr; + return Show(index, request); +} + +wxWindow* DialogParent(HWND caller) { + HelpState& st = State(); + if (st.modalHelp) + return st.modalHelp; + if (wxDialog* modal = ActiveModalDialog()) + return modal; + if (st.controller && st.controller->Frame() && st.controller->Frame()->IsShown()) + return st.controller->Frame(); + return caller ? ToWx(caller) : MainWxWindow(); +} + +HWND LinkLookup(HWND caller, const HelpIndex& index, const HH_AKLINK* link, bool alink) { + if (!link || !link->pszKeywords) + return nullptr; + const std::multimap& table = alink ? index.alinks : index.keywords; + std::vector pages; + wxStringTokenizer keywords(ToWx(link->pszKeywords), ";", wxTOKEN_STRTOK); + while (keywords.HasMoreTokens()) { + wxString keyword = keywords.GetNextToken().Trim().Trim(false).Lower(); + auto range = table.equal_range(keyword); + for (auto it = range.first; it != range.second; ++it) + if (std::find(pages.begin(), pages.end(), it->second) == pages.end()) + pages.push_back(it->second); + } + if (pages.empty()) { + if (link->pszUrl && *link->pszUrl) + return ShowTopic(index, TopicFromReference(ToWx(link->pszUrl))); + if (link->fIndexOnFail) + return ShowTopic(index, wxString(), Pane::Index); + if (link->pszMsgText && *link->pszMsgText) { + ShowMessageBox(DialogParent(caller), link->pszMsgText, link->pszMsgTitle, MB_OK | MB_ICONINFORMATION); + return HelpWindowHandle(); + } + return nullptr; + } + wxString page = pages.front(); + if (pages.size() > 1) { + wxArrayString choices; + for (const wxString& p : pages) { + auto t = index.titles.find(p); + choices.Add(t != index.titles.end() && !t->second.empty() ? t->second : p); + } + wxSingleChoiceDialog dlg(DialogParent(caller), _("Click a topic, then click Display."), _("Topics Found"), + choices); + if (dlg.ShowModal() != wxID_OK) + return HelpWindowHandle(); + page = pages[static_cast(dlg.GetSelection())]; + } + return ShowTopic(index, page); +} + +void CloseAll() { + HelpState& st = State(); + st.pendingScheduled = false; + if (st.modalHelp) + st.modalHelp->EndModal(wxID_CANCEL); + if (st.controller) + st.controller->Quit(); +} + +HWND HtmlHelpOnMain(HWND caller, const char* pszFile, UINT uCommand, DWORD_PTR dwData) { + switch (uCommand) { + case HH_INITIALIZE: + if (dwData) + *reinterpret_cast(dwData) = 1; + return PseudoHelpWindow(); + case HH_UNINITIALIZE: + case HH_CLOSE_ALL: + CloseAll(); + return PseudoHelpWindow(); + case HH_SET_WIN_TYPE: + case HH_SYNC: + return PseudoHelpWindow(); + case HH_GET_WIN_TYPE: + if (dwData) + *reinterpret_cast(dwData) = nullptr; + return nullptr; + case HH_GET_WIN_HANDLE: { + HWND h = HelpWindowHandle(); + return h == PseudoHelpWindow() ? nullptr : h; + } + default: + break; + } + + const HelpIndex* index = CurrentIndex(); + if (!index) + return nullptr; + switch (uCommand) { + case HH_DISPLAY_TOPIC: { + wxString topic; + if (dwData) + topic = TopicFromReference(ToWx(reinterpret_cast(dwData))); + else if (pszFile && strstr(pszFile, "::")) + topic = TopicFromReference(ToWx(pszFile)); + return ShowTopic(*index, topic.empty() ? index->defaultTopic : topic); + } + case HH_DISPLAY_TOC: + case HH_DISPLAY_SEARCH: + return ShowTopic(*index, wxString(), Pane::Contents); + case HH_DISPLAY_INDEX: + return ShowTopic(*index, wxString(), Pane::Index); + case HH_HELP_CONTEXT: { + auto it = index->contexts.find(static_cast(dwData)); + return it == index->contexts.end() ? nullptr : ShowTopic(*index, it->second); + } + case HH_ALINK_LOOKUP: + case HH_KEYWORD_LOOKUP: + return LinkLookup(caller, *index, reinterpret_cast(dwData), uCommand == HH_ALINK_LOOKUP); + default: + return nullptr; + } +} + +} // namespace + +} // namespace mfcwx + +using namespace mfcwx; + +HWND HtmlHelp(HWND hwndCaller, const char* pszFile, UINT uCommand, DWORD_PTR dwData) { + return OnMain([&]() -> HWND { return HtmlHelpOnMain(hwndCaller, pszFile, uCommand, dwData); }); +} + +HWND HtmlHelpA(HWND hwndCaller, const char* pszFile, UINT uCommand, DWORD_PTR dwData) { + return HtmlHelp(hwndCaller, pszFile, uCommand, dwData); +} + +int GetMenuStringW(HMENU hMenu, UINT uIDItem, LPWSTR lpString, int cchMax, UINT flags) { + int length = ::GetMenuString(hMenu, uIDItem, nullptr, 0, flags); + if (!lpString || cchMax <= 0) + return length; + std::vector ansi(static_cast(length) + 1); + ::GetMenuString(hMenu, uIDItem, ansi.data(), length + 1, flags); + int n = std::min(length, cchMax - 1); + for (int i = 0; i < n; ++i) + lpString[i] = AnsiToUnicode(static_cast(ansi[static_cast(i)])); + lpString[n] = 0; + return n; +} + +void CWinApp::WinHelp(DWORD_PTR dwData, UINT nCmd) { + m_bHelpMode = FALSE; + WinHelpInternal(dwData, nCmd); +} + +void CWinApp::WinHelpInternal(DWORD_PTR dwData, UINT nCmd) { + m_bHelpMode = FALSE; + switch (nCmd) { + case HELP_CONTEXT: + case HELP_CONTEXTPOPUP: + HtmlHelp(dwData, HH_HELP_CONTEXT); + break; + case HELP_CONTENTS: + HtmlHelp(0, HH_DISPLAY_TOC); + break; + case HELP_KEY: + case HELP_PARTIALKEY: { + HH_AKLINK link = {}; + link.cbStruct = sizeof link; + link.pszKeywords = reinterpret_cast(dwData); + link.fIndexOnFail = TRUE; + HtmlHelp(reinterpret_cast(&link), HH_KEYWORD_LOOKUP); + break; + } + case HELP_QUIT: + HtmlHelp(0, HH_CLOSE_ALL); + break; + default: + HtmlHelp(0, HH_DISPLAY_TOPIC); + break; + } +} + +void CWinApp::HtmlHelp(DWORD_PTR dwData, UINT nCmd) { + m_bHelpMode = FALSE; + CWnd* main = AfxGetMainWnd(); + if (!::HtmlHelp(main ? main->m_hWnd : nullptr, m_pszHelpFilePath, nCmd, dwData)) + AfxMessageBox(FromWx(UiString(AFX_IDP_FAILED_TO_LAUNCH_HELP, "Failed to launch help.")).c_str(), + MB_OK | MB_ICONINFORMATION); +} diff --git a/port/mfcwx/src/internal.h b/port/mfcwx/src/internal.h new file mode 100644 index 000000000..f71b29000 --- /dev/null +++ b/port/mfcwx/src/internal.h @@ -0,0 +1,232 @@ +#pragma once + +// Internal contracts shared by the mfcwx implementation files. Not visible to application code. + +#include "bridge.h" +#include "mfcwx/rcdata.h" + +#include +#include + +#include +#include +#include +#include +#include + +namespace mfcwx { + +// --------------------------------------------------------------------------------------------- +// Resources (resources.cpp) + +// Registers the generated resource module of the application (g_rcModule_). +void RegisterResourceModule(const rc::Module* module); +// Selects the UI language ("de", "en", ...); also sets the ANSI code page. +void SetResourceLanguage(const char* code); +const char* GetResourceLanguage(); +std::vector AvailableResourceLanguages(); + +// A resource reference as passed to Win32 APIs: MAKEINTRESOURCE(id) or a name. +struct ResRef { + int id = 0; + std::string name; + static ResRef From(const char* lpszName); + static ResRef FromId(UINT id) { ResRef r; r.id = static_cast(id); return r; } + bool Matches(int otherId, const char* otherName) const; +}; + +const rc::Dialog* FindDialog(const ResRef& ref); +const rc::Menu* FindMenu(const ResRef& ref); +const rc::AccelTable* FindAccelTable(const ResRef& ref); +const rc::Toolbar* FindToolbar(const ResRef& ref); +// Path of a file resource (BITMAP, ICON, CURSOR, GIF, ...) on disk, empty if unknown. +std::string FindFileResource(const char* type, const ResRef& ref); +std::vector FindDlgInit(int dialogId); +// Returns the resource string in the ANSI code page. +bool LoadResourceString(UINT id, std::string& out); +const rc::VersionInfo* GetVersionInfo(); +// Directory holding the application's data files (res/, help, pse, examples, ...). +std::string GetDataDirectory(); +void SetDataDirectory(const std::string& dir); +void SetDefaultDataDirectory(const std::string& dir); + +wxBitmap LoadBitmapResource(const ResRef& ref); +wxIcon LoadIconResource(const ResRef& ref); +wxCursor LoadCursorResource(const ResRef& ref); +// Converts an .rc menu text ("&File\tCtrl+O") to wx syntax ("&File\tCtrl+O" with wx accelerator names). +wxString MenuTextToWx(const char* utf8Text); + +// --------------------------------------------------------------------------------------------- +// Windows (wnd.cpp) + +// Win32 control ids map to wx ids with an offset so they never collide with wx's stock ids. +constexpr int kIdOffset = 20000; +// wx ids must stay below 0x7fff: small Windows ids are offset, larger ones get compact ids above wxID_HIGHEST. +int ToWxId(int winId); +int FromWxId(int wxId); +bool IsCommandWxId(int wxId); + +enum class ControlKind { + Generic, // custom-drawn wxWindow (CWnd::Create, owner-drawn controls, views) + Static, + StaticBitmap, + StaticFrame, // SS_*RECT / SS_*FRAME / SS_ETCHED* + GroupBox, + PushButton, + CheckBox, + RadioButton, + OwnerDrawButton, + Edit, + RichEdit, + ComboBox, // editable (CBS_DROPDOWN / CBS_SIMPLE) + ComboList, // CBS_DROPDOWNLIST + ListBox, + ScrollBar, + Progress, + Slider, + Spin, + ListView, + TreeView, + Tab, + Scintilla, + Dialog, + Frame, + MDIChild, + ToolBar, + StatusBar, + GLCanvas, +}; + +struct WindowState { + wxWindow* window = nullptr; + CWnd* permanent = nullptr; // attached CWnd (subclassed), may be null + ControlKind kind = ControlKind::Generic; + int winId = 0; // Win32 control id + DWORD style = 0; // Win32 style bits + DWORD exStyle = 0; + LONG_PTR userData = 0; // GWL_USERDATA + std::map> timers; + std::map timerProcs; + HFONT font = nullptr; + bool redraw = true; + bool destroying = false; + bool destroyNotified = false; + bool hooked = false; + bool dropBound = false; + bool settingText = false; // suppresses change notifications for programmatic updates + int defaultButtonId = 0; // dialogs: DM_SETDEFID + int checkState = 0; // BM_SETCHECK state of buttons + void* image = nullptr; // STM_SETIMAGE / STM_SETICON handle + wxString text; // caption of custom-drawn windows + wxSize baseUnits; // dialogs: dialog base units of the dialog font + std::function customPaint; + std::vector> itemData; // unused by most kinds + CWnd* buddy = nullptr; // spin buttons + HWND owner = nullptr; + void* extra = nullptr; // kind-specific data owned by the control implementation + std::function deleteExtra; + ~WindowState() { + if (deleteExtra) + deleteExtra(); + } +}; + +WindowState* GetState(wxWindow* window); // null if the window is not managed +WindowState& EnsureState(wxWindow* window); +inline wxWindow* ToWx(HWND hWnd) { return reinterpret_cast(hWnd); } +inline HWND ToHwnd(wxWindow* w) { return reinterpret_cast(w); } + +// Binds the event bridge to a window created by mfcwx (idempotent). +void HookWindow(wxWindow* window, ControlKind kind, int winId, DWORD style, DWORD exStyle); + +// Message dispatch. All functions must be called on the main thread except SendMessageAnyThread. +LRESULT DispatchMessageTo(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT DefaultWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +bool IsMainThread(); +// Runs fn on the main thread and waits for it (Windows SendMessage semantics across threads). +void RunOnMainThread(const std::function& fn); +void PostToMainThread(std::function fn); + +// Converts a window rectangle in dialog units to pixels for the given dialog window. +wxRect DialogUnitsToPixels(wxWindow* dialog, int x, int y, int cx, int cy); + +// Creates the wx controls of a dialog template inside parent; returns false on failure. +bool CreateDialogControls(wxWindow* parent, const rc::Dialog& tmpl); +// Creates a single control from a template entry (also used by CWnd::Create for standard classes). +wxWindow* CreateControl(wxWindow* parent, const char* cls, const char* text, int winId, const wxRect& rect, + DWORD style, DWORD exStyle); + +// Current message being processed (for CWnd::Default / GetCurrentMessage). +struct CurrentMessage { + MSG msg; + wxEvent* event; // originating wx event, null for synthetic messages + bool defaultCalled; // CWnd::Default() requested the toolkit's default processing +}; +CurrentMessage* GetCurrentMessageSlot(); + +// --------------------------------------------------------------------------------------------- +// GDI (gdi.cpp, gdi_dc.cpp, gdi_text.cpp, gdi_bits.cpp) + +struct GdiObjectImpl; +// HGDIOBJ values point to refcounted GdiObjectImpl objects (stock objects are never freed); +// (HBRUSH)(COLOR_xxx + 1) values are accepted wherever Win32 accepts them. HDC values point to +// a DCState; CDC::m_hDC holds it. +wxPen PenFromHandle(HPEN h); +wxBrush BrushFromHandle(HBRUSH h); +wxFont FontFromHandle(HFONT h); +// The bitmap is deselected from a memory DC first so its pixels are current; null if invalid. +wxBitmap* BitmapFromHandle(HBITMAP h); +HFONT DefaultGuiFont(); +wxColour ToWxColour(COLORREF c); +COLORREF FromWxColour(const wxColour& c); +COLORREF SysColor(int index); +// A new HBITMAP owning a copy of bmp, as if created by CreateBitmap (freed by DeleteObject). +HBITMAP CreateBitmapHandle(const wxBitmap& bmp); +// A shared, never deleted HFONT describing font (for WM_GETFONT of controls using wx fonts). +HFONT FontHandleFor(const wxFont& font); +// HICON values are wxIcon* owned by the icon loader. +inline wxIcon* IconFromHandle(HICON h) { return reinterpret_cast(h); } + +// Wraps a wx DC that is owned elsewhere (e.g. a wxPaintDC in an event handler) as CDC. +// Wrapping a wxPaintDC registers it as the window's paint DC until UnwrapDC: CPaintDC, CClientDC +// and GetDC created for that window meanwhile draw through it instead of creating another +// wxPaintDC (nested native paint contexts must be destroyed in LIFO order on macOS). +CDC* WrapDC(wxDC* dc, wxWindow* window); +void UnwrapDC(CDC* cdc); +// Deletes the temporary CGdiObject/CDC wrappers made by FromHandle and releases the native DCs of +// GetDC handles that were not released; call on idle. +void PurgeTemporaryGdiWrappers(); + +// Drawing through CClientDC/GetDC outside a paint event is not visible on macOS (and Wayland), so +// it goes to a per-window transparent overlay bitmap and the window is refreshed. The paint bridge +// must call PaintClientDCOverlay(window, dc) at the end of every paint event (after WM_PAINT, with +// the event's paint DC); it also ends DCs obtained during that paint. ClearClientDCOverlay drops +// the overlay (or clears rect, in client coordinates) and is called on Invalidate/InvalidateRect +// and size changes. +void PaintClientDCOverlay(wxWindow* window, wxDC& dc); +bool HasClientDCOverlay(wxWindow* window); +void ClearClientDCOverlay(wxWindow* window, const wxRect* rect = nullptr); + +// --------------------------------------------------------------------------------------------- +// Menus (menu.cpp) + +// HMENU values are CMenu-independent menu handles (MenuHandle*). +struct MenuHandle; +wxMenuBar* BuildMenuBar(const rc::Menu& menu); +wxMenu* BuildPopupMenu(const rc::Menu& menu, int index); +HMENU HandleFromWxMenu(wxMenu* menu); +HMENU HandleFromWxMenuBar(wxMenuBar* bar); +wxMenu* WxMenuFromHandle(HMENU h); +wxMenuBar* WxMenuBarFromHandle(HMENU h); + +// --------------------------------------------------------------------------------------------- +// Application (app.cpp) + +CWinApp*& AppInstance(); +wxWindow* MainWxWindow(); +// Shows a message box; nType is the MB_* combination. Returns IDOK, IDCANCEL, ... +int ShowMessageBox(wxWindow* parent, const char* text, const char* caption, UINT nType); + +void StartSnapshotTimerFromEnvironment(); + +} // namespace mfcwx diff --git a/port/mfcwx/src/kernel.cpp b/port/mfcwx/src/kernel.cpp new file mode 100644 index 000000000..8ffda7c08 --- /dev/null +++ b/port/mfcwx/src/kernel.cpp @@ -0,0 +1,1131 @@ +#include "afx.h" +#include "runtime.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#endif + +namespace mfcwx { +namespace { + +enum class Kind { Thread, Event, Mutex, Semaphore, Process, ProcessThread, File }; + +struct Object { + explicit Object(Kind k) : kind(k) {} + virtual ~Object() = default; + Kind kind; + int refs = 1; + int handles = 1; + int waiters = 0; + std::string name; +}; + +struct ThreadObj : Object { + ThreadObj() : Object(Kind::Thread) {} + std::function body; + DWORD id = 0; + DWORD exitCode = STILL_ACTIVE; + bool started = false; + bool finished = false; + bool zombie = false; + int suspendCount = 0; + int priority = THREAD_PRIORITY_NORMAL; + size_t stackSize = 0; +}; + +struct EventObj : Object { + EventObj(bool m, bool s) : Object(Kind::Event), manual(m), signaled(s) {} + bool manual; + bool signaled; + unsigned pulseGen = 0; +}; + +struct MutexObj : Object { + MutexObj() : Object(Kind::Mutex) {} + DWORD owner = 0; + int count = 0; +}; + +struct SemaphoreObj : Object { + SemaphoreObj(LONG c, LONG m) : Object(Kind::Semaphore), count(c), max(m) {} + LONG count; + LONG max; +}; + +struct ProcessObj : Object { + ProcessObj() : Object(Kind::Process) {} + pid_t pid = 0; + DWORD exitCode = STILL_ACTIVE; + bool exited = false; +}; + +void Release(Object* o); + +struct ProcessThreadObj : Object { + explicit ProcessThreadObj(ProcessObj* p) : Object(Kind::ProcessThread), process(p) {} + ~ProcessThreadObj() override { Release(process); } + ProcessObj* process; +}; + +struct FileObj : Object { + FileObj(int f, std::string p, bool o) : Object(Kind::File), fd(f), path(std::move(p)), owns(o) {} + ~FileObj() override { + if (owns && fd >= 0) + close(fd); + } + int fd; + std::string path; + bool owns; +}; + +// Kernel state lives for the whole process; detached threads may still use it during exit. +std::mutex& Lock() { + static std::mutex* m = new std::mutex; + return *m; +} +std::condition_variable& Cv() { + static std::condition_variable* cv = new std::condition_variable; + return *cv; +} +std::unordered_set& Objects() { + static auto* s = new std::unordered_set; + return *s; +} +std::map& Names() { + static auto* m = new std::map; + return *m; +} +std::deque& Graveyard() { + static auto* d = new std::deque; + return *d; +} + +constexpr size_t kGraveyardSize = 256; +constexpr size_t kMinStackSize = 16 * 1024 * 1024; +const HANDLE kCurrentThread = reinterpret_cast(static_cast(-2)); +const HANDLE kCurrentProcess = reinterpret_cast(static_cast(-1)); + +thread_local DWORD t_lastError = 0; +thread_local DWORD t_threadId = 0; +thread_local ThreadObj* t_self = nullptr; +std::atomic g_nextThreadId{0x104}; + +DWORD NewThreadId() { return g_nextThreadId.fetch_add(4); } + +Object* LookupLocked(HANDLE h) { + if (!h || h == kCurrentThread || h == kCurrentProcess) + return nullptr; + auto* o = static_cast(h); + return Objects().count(o) ? o : nullptr; +} + +template +T* LookupLocked(HANDLE h, Kind kind) { + Object* o = LookupLocked(h); + return o && o->kind == kind ? static_cast(o) : nullptr; +} + +void Register(Object* o) { + std::lock_guard lk(Lock()); + Objects().insert(o); +} + +void Release(Object* o) { + if (!o) + return; + std::vector doomed; + { + std::lock_guard lk(Lock()); + if (--o->refs > 0) + return; + if (o->kind == Kind::Thread) { + // Freed thread objects stay addressable for a while so that waiting on a stale + // thread handle (MFC auto-delete pattern) still reports a finished thread. + auto* t = static_cast(o); + t->zombie = true; + Graveyard().push_back(t); + while (Graveyard().size() > kGraveyardSize) { + ThreadObj* old = Graveyard().front(); + Graveyard().pop_front(); + Objects().erase(old); + doomed.push_back(old); + } + } else { + Objects().erase(o); + if (!o->name.empty()) { + auto it = Names().find(o->name); + if (it != Names().end() && it->second == o) + Names().erase(it); + } + doomed.push_back(o); + } + } + for (Object* d : doomed) + delete d; +} + +bool IsReady(Object* o, DWORD self, unsigned startGen) { + switch (o->kind) { + case Kind::Thread: + return static_cast(o)->finished; + case Kind::Event: { + auto* e = static_cast(o); + return e->signaled || (e->manual && e->pulseGen != startGen); + } + case Kind::Mutex: { + auto* m = static_cast(o); + return m->owner == 0 || m->owner == self; + } + case Kind::Semaphore: + return static_cast(o)->count > 0; + case Kind::Process: + return static_cast(o)->exited; + case Kind::ProcessThread: + return static_cast(o)->process->exited; + case Kind::File: + return true; + } + return false; +} + +void AcquireLocked(Object* o, DWORD self) { + switch (o->kind) { + case Kind::Event: { + auto* e = static_cast(o); + if (!e->manual) + e->signaled = false; + break; + } + case Kind::Mutex: { + auto* m = static_cast(o); + m->owner = self; + ++m->count; + break; + } + case Kind::Semaphore: + --static_cast(o)->count; + break; + default: + break; + } +} + +void CheckSuspendLocked(std::unique_lock& lk) { + ThreadObj* self = t_self; + if (!self) + return; + while (self->suspendCount > 0) + Cv().wait(lk); +} + +void CheckSuspend() { + if (!t_self) + return; + std::unique_lock lk(Lock()); + CheckSuspendLocked(lk); +} + +void* ThreadMain(void* arg) { + auto* t = static_cast(arg); + t_self = t; + t_threadId = t->id; + DWORD code = 0; + try { + code = t->body(); + } catch (ThreadExit& e) { + code = e.code; + } catch (CException* e) { + char msg[512] = ""; + e->GetErrorMessage(msg, sizeof msg); + fprintf(stderr, "mfcwx: uncaught MFC exception in thread %u: %s\n", static_cast(t->id), msg); + e->Delete(); + code = static_cast(-1); + } + t->body = nullptr; + { + std::lock_guard lk(Lock()); + t->exitCode = code; + t->finished = true; + } + Cv().notify_all(); + t_self = nullptr; + Release(t); + return nullptr; +} + +bool Launch(ThreadObj* t) { + pthread_attr_t attr; + pthread_attr_init(&attr); + size_t stack = std::max(t->stackSize, kMinStackSize); + long page = sysconf(_SC_PAGESIZE); + if (page > 0) + stack = (stack + static_cast(page) - 1) / static_cast(page) * static_cast(page); + pthread_attr_setstacksize(&attr, stack); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_t thread; + int rc = pthread_create(&thread, &attr, ThreadMain, t); + pthread_attr_destroy(&attr); + return rc == 0; +} + +void FailLaunch(ThreadObj* t) { + { + std::lock_guard lk(Lock()); + t->body = nullptr; + t->exitCode = static_cast(-1); + t->finished = true; + } + Cv().notify_all(); + Release(t); +} + +template +HANDLE CreateNamed(LPCSTR name, Kind kind, Make make) { + std::string key = name ? name : ""; + if (!key.empty()) { + std::lock_guard lk(Lock()); + auto it = Names().find(key); + if (it != Names().end()) { + if (it->second->kind != kind) { + t_lastError = ERROR_INVALID_HANDLE; + return nullptr; + } + ++it->second->handles; + ++it->second->refs; + t_lastError = ERROR_ALREADY_EXISTS; + return it->second; + } + } + T* o = make(); + o->name = key; + { + std::lock_guard lk(Lock()); + Objects().insert(o); + if (!key.empty()) + Names()[key] = o; + } + t_lastError = 0; + return o; +} + +DWORD WaitImpl(DWORD count, const HANDLE* handles, bool waitAll, DWORD ms) { + if (count == 0 || count > 64 || !handles) { + t_lastError = 87; + return WAIT_FAILED; + } + DWORD self = GetCurrentThreadId(); + std::vector objs(count); + std::vector gens(count, 0); + std::unique_lock lk(Lock()); + CheckSuspendLocked(lk); + for (DWORD i = 0; i < count; ++i) { + Object* o = LookupLocked(handles[i]); + if (!o) { + for (DWORD j = 0; j < i; ++j) + --objs[j]->waiters; + lk.unlock(); + for (DWORD j = 0; j < i; ++j) + Release(objs[j]); + t_lastError = ERROR_INVALID_HANDLE; + return WAIT_FAILED; + } + ++o->refs; + ++o->waiters; + objs[i] = o; + if (o->kind == Kind::Event) + gens[i] = static_cast(o)->pulseGen; + } + auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms == INFINITE ? 0 : ms); + DWORD result = WAIT_TIMEOUT; + for (bool timedOut = false;;) { + if (waitAll) { + bool all = true; + for (DWORD i = 0; i < count && all; ++i) + all = IsReady(objs[i], self, gens[i]); + if (all) { + for (DWORD i = 0; i < count; ++i) + AcquireLocked(objs[i], self); + result = WAIT_OBJECT_0; + break; + } + } else { + bool done = false; + for (DWORD i = 0; i < count; ++i) + if (IsReady(objs[i], self, gens[i])) { + AcquireLocked(objs[i], self); + result = WAIT_OBJECT_0 + i; + done = true; + break; + } + if (done) + break; + } + if (ms == 0 || timedOut) + break; + if (ms == INFINITE) + Cv().wait(lk); + else if (Cv().wait_until(lk, deadline) == std::cv_status::timeout) + timedOut = true; + } + for (Object* o : objs) + --o->waiters; + lk.unlock(); + Cv().notify_all(); + for (Object* o : objs) + Release(o); + return result; +} + +std::vector SplitCommandLine(const char* cmd) { + std::vector args; + if (!cmd) + return args; + const char* p = cmd; + while (*p == ' ' || *p == '\t') + ++p; + if (!*p) + return args; + std::string prog; + if (*p == '"') { + ++p; + while (*p && *p != '"') + prog += *p++; + if (*p == '"') + ++p; + } else { + while (*p && *p != ' ' && *p != '\t') + prog += *p++; + } + args.push_back(prog); + for (;;) { + while (*p == ' ' || *p == '\t') + ++p; + if (!*p) + break; + std::string arg; + bool quoted = false; + while (*p && (quoted || (*p != ' ' && *p != '\t'))) { + if (*p == '\\') { + size_t n = 0; + while (*p == '\\') { + ++n; + ++p; + } + if (*p == '"') { + arg.append(n / 2, '\\'); + if (n % 2) { + arg += '"'; + ++p; + } + } else { + arg.append(n, '\\'); + } + } else if (*p == '"') { + if (quoted && p[1] == '"') { + arg += '"'; + p += 2; + } else { + quoted = !quoted; + ++p; + } + } else { + arg += *p++; + } + } + args.push_back(arg); + } + return args; +} + +bool IsExecutableFile(const std::string& path) { + struct stat st; + return !path.empty() && stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode) && access(path.c_str(), X_OK) == 0; +} + +bool EndsWithExe(const std::string& s) { return s.size() > 4 && strcasecmp(s.c_str() + s.size() - 4, ".exe") == 0; } + +std::string ResolveProgram(const std::string& appName) { + std::vector candidates{appName}; + if (EndsWithExe(appName)) + candidates.push_back(appName.substr(0, appName.size() - 4)); + for (const std::string& name : candidates) { + if (name.find('\\') != std::string::npos || name.find('/') != std::string::npos) { + std::string native = FsPath(name.c_str()); + if (IsExecutableFile(native)) + return native; + continue; + } + std::string native = NativePath(name.c_str()); + std::vector dirs; + std::string exe = ExecutablePath(); + size_t slash = exe.rfind('/'); + if (slash != std::string::npos) + dirs.push_back(exe.substr(0, slash)); + const char* path = getenv("PATH"); + std::string all = path ? path : "/usr/local/bin:/usr/bin:/bin"; + size_t start = 0; + for (;;) { + size_t colon = all.find(':', start); + std::string dir = all.substr(start, colon == std::string::npos ? std::string::npos : colon - start); + dirs.push_back(dir.empty() ? "." : dir); + if (colon == std::string::npos) + break; + start = colon + 1; + } + dirs.push_back("."); + for (const std::string& dir : dirs) { + std::string full = dir + "/" + native; + if (IsExecutableFile(full)) + return full; + } + } + return std::string(); +} + +std::string ConvertArgument(const std::string& arg) { + bool drive = arg.size() >= 3 && arg[1] == ':' && (arg[2] == '\\' || arg[2] == '/') && isalpha(static_cast(arg[0])); + if (arg.find('\\') != std::string::npos || drive) + return NativePath(arg.c_str()); + return AnsiToUtf8(arg.c_str()); +} + +void ClearCloexec(int fd) { + int flags = fcntl(fd, F_GETFD); + if (flags >= 0) + fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC); +} + +} // namespace + +HANDLE StartThread(std::function body, DWORD flags, size_t stackSize, DWORD* threadId) { + auto* t = new ThreadObj; + t->body = std::move(body); + t->id = NewThreadId(); + t->stackSize = stackSize; + if (threadId) + *threadId = t->id; + if (flags & CREATE_SUSPENDED) { + t->suspendCount = 1; + Register(t); + return t; + } + t->started = true; + t->refs = 2; + Register(t); + if (!Launch(t)) { + FailLaunch(t); + CloseHandle(t); + t_lastError = ERROR_NOT_ENOUGH_MEMORY; + return nullptr; + } + return t; +} + +bool IsProcessMainThread() { +#if defined(__APPLE__) + return pthread_main_np() != 0; +#elif defined(__linux__) + return static_cast(syscall(SYS_gettid)) == getpid(); +#else + static const pthread_t mainThread = pthread_self(); + return pthread_equal(mainThread, pthread_self()) != 0; +#endif +} + +HANDLE HandleFromFd(int fd, const std::string& nativePath, bool owns) { + if (fd < 0) + return INVALID_HANDLE_VALUE; + auto* f = new FileObj(fd, nativePath, owns); + Register(f); + return f; +} + +int FdFromHandle(HANDLE h) { + std::lock_guard lk(Lock()); + auto* f = LookupLocked(h, Kind::File); + return f ? f->fd : -1; +} + +} // namespace mfcwx + +using namespace mfcwx; + +DWORD GetLastError(void) { return t_lastError; } + +void SetLastError(DWORD err) { t_lastError = err; } + +DWORD GetCurrentThreadId(void) { + if (!t_threadId) + t_threadId = NewThreadId(); + return t_threadId; +} + +DWORD GetCurrentProcessId(void) { return static_cast(getpid()); } + +HANDLE GetCurrentProcess(void) { return kCurrentProcess; } + +HANDLE GetCurrentThread(void) { return kCurrentThread; } + +void Sleep(DWORD ms) { + CheckSuspend(); + if (ms == 0) { + sched_yield(); + } else if (ms == INFINITE) { + for (;;) + pause(); + } else { + struct timespec ts; + ts.tv_sec = ms / 1000; + ts.tv_nsec = static_cast(ms % 1000) * 1000000L; + while (nanosleep(&ts, &ts) != 0 && errno == EINTR) { + } + } + CheckSuspend(); +} + +DWORD WaitForSingleObject(HANDLE h, DWORD ms) { return WaitImpl(1, &h, false, ms); } + +DWORD WaitForMultipleObjects(DWORD count, const HANDLE* handles, BOOL waitAll, DWORD ms) { + return WaitImpl(count, handles, waitAll != FALSE, ms); +} + +BOOL CloseHandle(HANDLE h) { + if (h == kCurrentThread || h == kCurrentProcess) + return TRUE; + Object* o; + { + std::lock_guard lk(Lock()); + o = LookupLocked(h); + if (!o || o->handles <= 0) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (--o->handles == 0 && !o->name.empty()) { + auto it = Names().find(o->name); + if (it != Names().end() && it->second == o) + Names().erase(it); + o->name.clear(); + } + } + Release(o); + return TRUE; +} + +BOOL GetExitCodeThread(HANDLE thread, LPDWORD code) { + std::lock_guard lk(Lock()); + if (thread == kCurrentThread) { + if (code) + *code = STILL_ACTIVE; + return TRUE; + } + if (auto* t = LookupLocked(thread, Kind::Thread)) { + if (code) + *code = t->finished ? t->exitCode : STILL_ACTIVE; + return TRUE; + } + if (auto* pt = LookupLocked(thread, Kind::ProcessThread)) { + if (code) + *code = pt->process->exited ? pt->process->exitCode : STILL_ACTIVE; + return TRUE; + } + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; +} + +BOOL GetExitCodeProcess(HANDLE process, LPDWORD code) { + std::lock_guard lk(Lock()); + if (process == kCurrentProcess) { + if (code) + *code = STILL_ACTIVE; + return TRUE; + } + auto* p = LookupLocked(process, Kind::Process); + if (!p) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (code) + *code = p->exited ? p->exitCode : STILL_ACTIVE; + return TRUE; +} + +BOOL TerminateThread(HANDLE thread, DWORD code) { + // Only a thread that has not started yet can be stopped safely. + { + std::lock_guard lk(Lock()); + auto* t = LookupLocked(thread, Kind::Thread); + if (!t) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (t->started || t->finished) { + t_lastError = 50; + return FALSE; + } + t->started = true; + t->finished = true; + t->exitCode = code; + t->body = nullptr; + } + Cv().notify_all(); + return TRUE; +} + +BOOL TerminateProcess(HANDLE process, UINT code) { + if (process == kCurrentProcess) + _exit(static_cast(code)); + pid_t pid; + { + std::lock_guard lk(Lock()); + auto* p = LookupLocked(process, Kind::Process); + if (!p) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (p->exited) + return TRUE; + pid = p->pid; + } + if (kill(pid, SIGKILL) != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + return TRUE; +} + +HANDLE CreateThread(LPSECURITY_ATTRIBUTES, SIZE_T stack, LPTHREAD_START_ROUTINE fn, LPVOID param, DWORD flags, + LPDWORD threadId) { + if (!fn) { + t_lastError = 87; + return nullptr; + } + DWORD id = 0; + HANDLE h = StartThread([fn, param]() { return fn(param); }, flags, stack, &id); + if (threadId) + *threadId = id; + return h; +} + +DWORD ResumeThread(HANDLE thread) { + ThreadObj* launch = nullptr; + DWORD previous; + { + std::lock_guard lk(Lock()); + auto* t = LookupLocked(thread, Kind::Thread); + if (!t || t->zombie) { + t_lastError = ERROR_INVALID_HANDLE; + return static_cast(-1); + } + previous = static_cast(t->suspendCount); + if (t->suspendCount > 0) + --t->suspendCount; + if (t->suspendCount == 0 && !t->started) { + t->started = true; + ++t->refs; + launch = t; + } + } + Cv().notify_all(); + if (launch && !Launch(launch)) + FailLaunch(launch); + return previous; +} + +DWORD SuspendThread(HANDLE thread) { + // Suspension is cooperative: a running thread stops at its next Sleep or wait. + std::unique_lock lk(Lock()); + ThreadObj* t = thread == kCurrentThread ? t_self : LookupLocked(thread, Kind::Thread); + if (!t || t->zombie || t->finished) { + t_lastError = ERROR_INVALID_HANDLE; + return static_cast(-1); + } + DWORD previous = static_cast(t->suspendCount++); + if (t == t_self) + CheckSuspendLocked(lk); + return previous; +} + +void ExitThread(DWORD code) { + if (t_self) + throw ThreadExit{code, true}; + pthread_exit(nullptr); +} + +BOOL SetThreadPriority(HANDLE thread, int priority) { + std::lock_guard lk(Lock()); + ThreadObj* t = thread == kCurrentThread ? t_self : LookupLocked(thread, Kind::Thread); + if (t) + t->priority = priority; + else if (thread != kCurrentThread) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + return TRUE; +} + +int GetThreadPriority(HANDLE thread) { + std::lock_guard lk(Lock()); + ThreadObj* t = thread == kCurrentThread ? t_self : LookupLocked(thread, Kind::Thread); + return t ? t->priority : THREAD_PRIORITY_NORMAL; +} + +BOOL SetPriorityClass(HANDLE, DWORD) { return TRUE; } + +HANDLE CreateEventA(LPSECURITY_ATTRIBUTES, BOOL manualReset, BOOL initialState, LPCSTR name) { + return CreateNamed(name, Kind::Event, + [&]() { return new EventObj(manualReset != FALSE, initialState != FALSE); }); +} + +BOOL SetEvent(HANDLE h) { + { + std::lock_guard lk(Lock()); + auto* e = LookupLocked(h, Kind::Event); + if (!e) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + e->signaled = true; + } + Cv().notify_all(); + return TRUE; +} + +BOOL ResetEvent(HANDLE h) { + std::lock_guard lk(Lock()); + auto* e = LookupLocked(h, Kind::Event); + if (!e) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + e->signaled = false; + return TRUE; +} + +BOOL PulseEvent(HANDLE h) { + { + std::lock_guard lk(Lock()); + auto* e = LookupLocked(h, Kind::Event); + if (!e) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (e->manual) { + ++e->pulseGen; + e->signaled = false; + } else if (e->waiters > 0) { + e->signaled = true; + } + } + Cv().notify_all(); + return TRUE; +} + +HANDLE CreateMutexA(LPSECURITY_ATTRIBUTES, BOOL initialOwner, LPCSTR name) { + DWORD self = GetCurrentThreadId(); + return CreateNamed(name, Kind::Mutex, [&]() { + auto* m = new MutexObj; + if (initialOwner) { + m->owner = self; + m->count = 1; + } + return m; + }); +} + +BOOL ReleaseMutex(HANDLE h) { + DWORD self = GetCurrentThreadId(); + { + std::lock_guard lk(Lock()); + auto* m = LookupLocked(h, Kind::Mutex); + if (!m) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (m->owner != self || m->count <= 0) { + t_lastError = 288; + return FALSE; + } + if (--m->count == 0) + m->owner = 0; + } + Cv().notify_all(); + return TRUE; +} + +HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES, LONG initial, LONG max, LPCSTR name) { + if (max <= 0 || initial < 0 || initial > max) { + t_lastError = 87; + return nullptr; + } + return CreateNamed(name, Kind::Semaphore, [&]() { return new SemaphoreObj(initial, max); }); +} + +BOOL ReleaseSemaphore(HANDLE h, LONG count, LPLONG previous) { + { + std::lock_guard lk(Lock()); + auto* s = LookupLocked(h, Kind::Semaphore); + if (!s) { + t_lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (count <= 0 || count > s->max - s->count) { + t_lastError = 298; + return FALSE; + } + if (previous) + *previous = s->count; + s->count += count; + } + Cv().notify_all(); + return TRUE; +} + +static std::recursive_mutex* CriticalSectionImpl(LPCRITICAL_SECTION cs) { + auto* impl = static_cast(__atomic_load_n(&cs->impl, __ATOMIC_ACQUIRE)); + if (impl) + return impl; + auto* fresh = new std::recursive_mutex; + void* expected = nullptr; + if (__atomic_compare_exchange_n(&cs->impl, &expected, static_cast(fresh), false, __ATOMIC_ACQ_REL, + __ATOMIC_ACQUIRE)) + return fresh; + delete fresh; + return static_cast(expected); +} + +void InitializeCriticalSection(LPCRITICAL_SECTION cs) { cs->impl = new std::recursive_mutex; } + +void DeleteCriticalSection(LPCRITICAL_SECTION cs) { + delete static_cast(cs->impl); + cs->impl = nullptr; +} + +void EnterCriticalSection(LPCRITICAL_SECTION cs) { CriticalSectionImpl(cs)->lock(); } + +void LeaveCriticalSection(LPCRITICAL_SECTION cs) { CriticalSectionImpl(cs)->unlock(); } + +BOOL TryEnterCriticalSection(LPCRITICAL_SECTION cs) { return CriticalSectionImpl(cs)->try_lock() ? TRUE : FALSE; } + +LONG InterlockedIncrement(LONG volatile* p) { return __atomic_add_fetch(p, 1, __ATOMIC_SEQ_CST); } + +LONG InterlockedDecrement(LONG volatile* p) { return __atomic_sub_fetch(p, 1, __ATOMIC_SEQ_CST); } + +LONG InterlockedExchange(LONG volatile* p, LONG v) { return __atomic_exchange_n(p, v, __ATOMIC_SEQ_CST); } + +LONG InterlockedExchangeAdd(LONG volatile* p, LONG v) { return __atomic_fetch_add(p, v, __ATOMIC_SEQ_CST); } + +LONG InterlockedCompareExchange(LONG volatile* p, LONG exchange, LONG comparand) { + __atomic_compare_exchange_n(p, &comparand, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return comparand; +} + +BOOL CreateProcessA(LPCSTR app, LPSTR cmdLine, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, + LPVOID env, LPCSTR curDir, LPSTARTUPINFO si, LPPROCESS_INFORMATION pi) { + std::vector args = SplitCommandLine(cmdLine); + std::string program = app && *app ? std::string(app) : (args.empty() ? std::string() : args[0]); + if (program.empty()) { + t_lastError = 87; + return FALSE; + } + if (args.empty()) + args.push_back(program); + std::string path = ResolveProgram(program); + if (path.empty()) { + t_lastError = ERROR_FILE_NOT_FOUND; + return FALSE; + } + std::vector argStore; + argStore.push_back(path); + for (size_t i = 1; i < args.size(); ++i) + argStore.push_back(ConvertArgument(args[i])); + std::vector argv; + for (std::string& a : argStore) + argv.push_back(&a[0]); + argv.push_back(nullptr); + + std::vector envStore; + std::vector envp; + if (env) { + for (const char* e = static_cast(env); *e; e += strlen(e) + 1) + envStore.push_back(AnsiToUtf8(e)); + for (std::string& e : envStore) + envp.push_back(&e[0]); + envp.push_back(nullptr); + } + std::string cwd = curDir && *curDir ? FsPath(curDir) : std::string(); + + int redirect[3] = {-1, -1, -1}; + int devNull = -1; + if (si && (si->dwFlags & STARTF_USESTDHANDLES)) { + HANDLE stdHandles[3] = {si->hStdInput, si->hStdOutput, si->hStdError}; + for (int i = 0; i < 3; ++i) + redirect[i] = stdHandles[i] ? FdFromHandle(stdHandles[i]) : -1; + if (!si->hStdInput) { + devNull = open("/dev/null", O_RDONLY | O_CLOEXEC); + redirect[0] = devNull; + } + } + + int errPipe[2]; + if (pipe(errPipe) != 0) { + SetLastErrorFromErrno(errno); + if (devNull >= 0) + close(devNull); + return FALSE; + } + fcntl(errPipe[0], F_SETFD, FD_CLOEXEC); + fcntl(errPipe[1], F_SETFD, FD_CLOEXEC); + + pid_t pid = fork(); + if (pid == 0) { + sigset_t none; + sigemptyset(&none); + pthread_sigmask(SIG_SETMASK, &none, nullptr); + signal(SIGPIPE, SIG_DFL); + for (int i = 0; i < 3; ++i) { + if (redirect[i] < 0) + continue; + if (redirect[i] == i) + ClearCloexec(i); + else + dup2(redirect[i], i); + } + int err = 0; + if (!cwd.empty() && chdir(cwd.c_str()) != 0) + err = errno; + if (!err) { + if (env) + execve(path.c_str(), argv.data(), envp.data()); + else + execv(path.c_str(), argv.data()); + err = errno; + } + ssize_t ignored = write(errPipe[1], &err, sizeof err); + (void)ignored; + _exit(127); + } + close(errPipe[1]); + if (devNull >= 0) + close(devNull); + if (pid < 0) { + int err = errno; + close(errPipe[0]); + SetLastErrorFromErrno(err); + return FALSE; + } + int childErr = 0; + ssize_t n; + while ((n = read(errPipe[0], &childErr, sizeof childErr)) < 0 && errno == EINTR) { + } + close(errPipe[0]); + if (n == static_cast(sizeof childErr)) { + int status; + while (waitpid(pid, &status, 0) < 0 && errno == EINTR) { + } + SetLastErrorFromErrno(childErr); + return FALSE; + } + + auto* proc = new ProcessObj; + proc->pid = pid; + proc->refs = 3; + auto* thread = new ProcessThreadObj(proc); + Register(proc); + Register(thread); + std::thread([proc]() { + int status = 0; + pid_t r; + while ((r = waitpid(proc->pid, &status, 0)) < 0 && errno == EINTR) { + } + DWORD code = 0; + if (r == proc->pid) { + if (WIFEXITED(status)) + code = static_cast(WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + code = static_cast(128 + WTERMSIG(status)); + } + { + std::lock_guard lk(Lock()); + proc->exitCode = code; + proc->exited = true; + } + Cv().notify_all(); + Release(proc); + }).detach(); + + if (pi) { + pi->hProcess = proc; + pi->hThread = thread; + pi->dwProcessId = static_cast(pid); + pi->dwThreadId = NewThreadId(); + } else { + CloseHandle(proc); + CloseHandle(thread); + } + t_lastError = 0; + return TRUE; +} + +UINT WinExec(LPCSTR cmdLine, UINT) { + STARTUPINFO si; + memset(&si, 0, sizeof si); + si.cb = sizeof si; + PROCESS_INFORMATION pi; + std::string cmd = cmdLine ? cmdLine : ""; + if (!CreateProcessA(nullptr, &cmd[0], nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) { + DWORD err = GetLastError(); + return err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ? err : 11; + } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 33; +} + +void ExitProcess(UINT code) { exit(static_cast(code)); } + +uintptr_t mfcwx_beginthread(void (*fn)(void*), unsigned stack, void* arg) { + if (!fn) + return static_cast(-1); + HANDLE h = StartThread([fn, arg]() -> DWORD { + fn(arg); + return 0; + }, 0, stack, nullptr); + if (!h) + return static_cast(-1); + // _beginthread handles are closed by the runtime when the thread ends. + CloseHandle(h); + return reinterpret_cast(h); +} + +uintptr_t mfcwx_beginthreadex(void*, unsigned stack, unsigned (*fn)(void*), void* arg, unsigned flags, + unsigned* threadId) { + if (!fn) + return 0; + DWORD id = 0; + HANDLE h = StartThread([fn, arg]() -> DWORD { return fn(arg); }, flags, stack, &id); + if (threadId) + *threadId = id; + return reinterpret_cast(h); +} + +void mfcwx_endthread(unsigned code) { ExitThread(code); } + +void mfcwx_sleep_ms(unsigned long ms) { Sleep(static_cast(ms)); } diff --git a/port/mfcwx/src/listctrl.cpp b/port/mfcwx/src/listctrl.cpp new file mode 100644 index 000000000..1cec63ca6 --- /dev/null +++ b/port/mfcwx/src/listctrl.cpp @@ -0,0 +1,1173 @@ +#include "controls_internal.h" + +#include "afxcmn.h" + +#include +#include +#include + +#include + +namespace mfcwx { + +namespace { + +struct ListViewExtra { + DWORD exStyle = 0; + int selectionMark = -1; + COLORREF textBkColor = CLR_DEFAULT; + CImageList* imageLists[3] = {nullptr, nullptr, nullptr}; + bool suppressActivate = false; +}; + +ListViewExtra& ListExtra(wxListCtrl* lc) { return Extra(EnsureState(lc)); } + +UINT StateImage(int index) { return static_cast(index) << 12; } + +wxWindow* ListMainWindow(wxListCtrl* lc) { +#if !defined(__WXMSW__) && !defined(__WXQT__) + for (wxWindow* c : lc->GetChildren()) + if (static_cast(c) == static_cast(lc->m_mainWin)) + return c; +#endif + return lc; +} + +wxPoint ToListPoint(wxListCtrl* lc, wxWindow* from, const wxPoint& p) { + return from == lc ? p : lc->ScreenToClient(from->ClientToScreen(p)); +} + +wxString ItemText(const char* p) { + if (!p || p == LPSTR_TEXTCALLBACK) + return wxString(); + return ToWx(p); +} + +int CopyText(const wxString& s, char* buf, int cch) { + if (!buf || cch <= 0) + return 0; + std::string a = FromWx(s); + size_t n = std::min(a.size(), static_cast(cch - 1)); + memcpy(buf, a.data(), n); + buf[n] = 0; + return static_cast(n); +} + +bool ValidItem(wxListCtrl* lc, long item) { return item >= 0 && item < lc->GetItemCount(); } + +bool ValidColumn(wxListCtrl* lc, int col) { return col >= 0 && (col == 0 || col < lc->GetColumnCount()); } + +UINT ItemState(wxListCtrl* lc, long item, UINT mask) { + long wxMask = 0; + if (mask & LVIS_SELECTED) + wxMask |= wxLIST_STATE_SELECTED; + if (mask & LVIS_FOCUSED) + wxMask |= wxLIST_STATE_FOCUSED; + long s = wxMask ? lc->GetItemState(item, wxMask) : 0; + UINT state = 0; + if (s & wxLIST_STATE_SELECTED) + state |= LVIS_SELECTED; + if (s & wxLIST_STATE_FOCUSED) + state |= LVIS_FOCUSED; + if ((mask & LVIS_STATEIMAGEMASK) && lc->HasCheckBoxes()) + state |= StateImage(lc->IsItemChecked(item) ? 2 : 1); + return state & mask; +} + +void SetItemStateOne(wxListCtrl* lc, long item, UINT state, UINT mask) { + long wxMask = 0; + long wxState = 0; + if (mask & LVIS_SELECTED) { + wxMask |= wxLIST_STATE_SELECTED; + if (state & LVIS_SELECTED) + wxState |= wxLIST_STATE_SELECTED; + } + if (mask & LVIS_FOCUSED) { + wxMask |= wxLIST_STATE_FOCUSED; + if (state & LVIS_FOCUSED) + wxState |= wxLIST_STATE_FOCUSED; + } + if (wxMask) + lc->SetItemState(item, wxState, wxMask); + if ((mask & LVIS_STATEIMAGEMASK) && lc->HasCheckBoxes()) + lc->CheckItem(item, ((state & LVIS_STATEIMAGEMASK) >> 12) == 2); +} + +bool SetItemStates(wxListCtrl* lc, long item, UINT state, UINT mask) { + if (item == -1) { + for (long i = 0; i < lc->GetItemCount(); ++i) + SetItemStateOne(lc, i, state, mask); + return true; + } + if (!ValidItem(lc, item)) + return false; + SetItemStateOne(lc, item, state, mask); + return true; +} + +wxListColumnFormat AlignFromFormat(int fmt) { + switch (fmt & LVCFMT_JUSTIFYMASK) { + case LVCFMT_RIGHT: return wxLIST_FORMAT_RIGHT; + case LVCFMT_CENTER: return wxLIST_FORMAT_CENTRE; + default: return wxLIST_FORMAT_LEFT; + } +} + +int FormatFromAlign(wxListColumnFormat align) { + switch (align) { + case wxLIST_FORMAT_RIGHT: return LVCFMT_RIGHT; + case wxLIST_FORMAT_CENTRE: return LVCFMT_CENTER; + default: return LVCFMT_LEFT; + } +} + +int RectCode(int code) { + switch (code) { + case LVIR_ICON: return wxLIST_RECT_ICON; + case LVIR_LABEL: return wxLIST_RECT_LABEL; + default: return wxLIST_RECT_BOUNDS; + } +} + +bool ItemRect(wxListCtrl* lc, long item, int subItem, int code, RECT* out) { + if (!out || !ValidItem(lc, item)) + return false; + wxRect r; + bool ok = subItem < 0 ? lc->GetItemRect(item, r, RectCode(code)) + : subItem < lc->GetColumnCount() && lc->GetSubItemRect(item, subItem, r, RectCode(code)); + if (!ok) + return false; + out->left = r.x; + out->top = r.y; + out->right = r.x + r.width; + out->bottom = r.y + r.height; + return true; +} + +struct ListHit { + long item = -1; + int subItem = -1; + UINT flags = LVHT_NOWHERE; +}; + +ListHit HitTestList(wxListCtrl* lc, const wxPoint& pt) { + ListHit hit; + long count = lc->GetItemCount(); + long first = 0; + long last = count - 1; + bool report = lc->InReportView(); + if (report) { + first = std::max(0L, lc->GetTopItem()); + last = std::min(count - 1, first + lc->GetCountPerPage() + 1); + } + for (long i = first; i <= last; ++i) { + wxRect r; + if (!lc->GetItemRect(i, r, wxLIST_RECT_BOUNDS) || !r.Contains(pt)) + continue; + hit.item = i; + hit.subItem = 0; + hit.flags = LVHT_ONITEMLABEL; + if (report) { + for (int c = 0; c < lc->GetColumnCount(); ++c) { + wxRect sr; + if (lc->GetSubItemRect(i, c, sr) && pt.x >= sr.x && pt.x < sr.x + sr.width) { + hit.subItem = c; + break; + } + } + } + wxRect icon; + if (lc->HasCheckBoxes() && hit.subItem == 0 && + pt.x < r.x + wxRendererNative::Get().GetCheckBoxSize(lc).x + 4) + hit.flags = LVHT_ONITEMSTATEICON; + else if (lc->GetItemRect(i, icon, wxLIST_RECT_ICON) && icon.width > 0 && icon.Contains(pt)) + hit.flags = LVHT_ONITEMICON; + return hit; + } + return hit; +} + +void ApplyExtendedStyle(wxListCtrl* lc, DWORD oldStyle, DWORD newStyle) { + if ((oldStyle ^ newStyle) & LVS_EX_CHECKBOXES) + lc->EnableCheckBoxes((newStyle & LVS_EX_CHECKBOXES) != 0); + if ((oldStyle ^ newStyle) & LVS_EX_GRIDLINES) { + bool on = (newStyle & LVS_EX_GRIDLINES) != 0; + lc->SetSingleStyle(wxLC_HRULES, on); + lc->SetSingleStyle(wxLC_VRULES, on); + lc->Refresh(); + } +} + +LRESULT ListNotify(wxListCtrl* lc, UINT code, long item, int subItem, UINT newState = 0, UINT oldState = 0, + UINT changed = 0, const wxPoint& pt = wxPoint(0, 0)) { + NMITEMACTIVATE nm; + memset(&nm, 0, sizeof nm); + nm.hdr.code = code; + nm.iItem = static_cast(item); + nm.iSubItem = subItem; + nm.uNewState = newState; + nm.uOldState = oldState; + nm.uChanged = changed; + nm.ptAction.x = pt.x; + nm.ptAction.y = pt.y; + if (ValidItem(lc, item)) + nm.lParam = static_cast(lc->GetItemData(item)); + return NotifyParentNM(lc, &nm.hdr); +} + +void MouseNotify(wxListCtrl* lc, wxWindow* from, UINT code, const wxMouseEvent& e) { + wxPoint pt = ToListPoint(lc, from, e.GetPosition()); + ListHit hit = HitTestList(lc, pt); + ListNotify(lc, code, hit.item, hit.item >= 0 ? hit.subItem : -1, 0, 0, 0, pt); +} + +} // namespace + +void BindListViewEvents(wxWindow* w) { + auto* lc = wxDynamicCast(w, wxListCtrl); + if (!lc) + return; + lc->Bind(wxEVT_LIST_ITEM_SELECTED, [lc](wxListEvent& e) { + if (WindowState* st = GetState(lc)) + Extra(*st).selectionMark = static_cast(e.GetIndex()); + ListNotify(lc, LVN_ITEMCHANGED, e.GetIndex(), 0, LVIS_SELECTED | LVIS_FOCUSED, 0, LVIF_STATE); + }); + lc->Bind(wxEVT_LIST_ITEM_DESELECTED, + [lc](wxListEvent& e) { ListNotify(lc, LVN_ITEMCHANGED, e.GetIndex(), 0, 0, LVIS_SELECTED, LVIF_STATE); }); + lc->Bind(wxEVT_LIST_ITEM_CHECKED, [lc](wxListEvent& e) { + ListNotify(lc, LVN_ITEMCHANGED, e.GetIndex(), 0, StateImage(2), StateImage(1), LVIF_STATE); + }); + lc->Bind(wxEVT_LIST_ITEM_UNCHECKED, [lc](wxListEvent& e) { + ListNotify(lc, LVN_ITEMCHANGED, e.GetIndex(), 0, StateImage(1), StateImage(2), LVIF_STATE); + }); + lc->Bind(wxEVT_LIST_COL_CLICK, + [lc](wxListEvent& e) { ListNotify(lc, LVN_COLUMNCLICK, -1, std::max(0, e.GetColumn())); }); + lc->Bind(wxEVT_LIST_KEY_DOWN, [lc](wxListEvent& e) { + NMLVKEYDOWN nm; + memset(&nm, 0, sizeof nm); + nm.hdr.code = LVN_KEYDOWN; + nm.wVKey = static_cast(VirtualKeyFromWx(e.GetKeyCode())); + NotifyParentNM(lc, &nm.hdr); + e.Skip(); + }); + lc->Bind(wxEVT_LIST_ITEM_ACTIVATED, [lc](wxListEvent&) { + WindowState* st = GetState(lc); + if (!st) + return; + ListViewExtra& ex = Extra(*st); + if (ex.suppressActivate) { + ex.suppressActivate = false; + return; + } + NMHDR hdr; + hdr.code = NM_RETURN; + NotifyParentNM(lc, &hdr); + }); + + wxWindow* main = ListMainWindow(lc); + main->Bind(wxEVT_LEFT_UP, [lc, main](wxMouseEvent& e) { + MouseNotify(lc, main, NM_CLICK, e); + e.Skip(); + }); + main->Bind(wxEVT_LEFT_DCLICK, [lc, main](wxMouseEvent& e) { + if (WindowState* st = GetState(lc)) { + Extra(*st).suppressActivate = true; + lc->CallAfter([lc] { + if (WindowState* s = GetState(lc)) + Extra(*s).suppressActivate = false; + }); + } + MouseNotify(lc, main, NM_DBLCLK, e); + e.Skip(); + }); + main->Bind(wxEVT_RIGHT_UP, [lc, main](wxMouseEvent& e) { + MouseNotify(lc, main, NM_RCLICK, e); + e.Skip(); + }); + if (main != lc) { + main->Bind(wxEVT_SET_FOCUS, [lc](wxFocusEvent& e) { + if (WindowState* st = GetState(lc)) + NotifyFocusChange(lc, *st, true); + e.Skip(); + }); + main->Bind(wxEVT_KILL_FOCUS, [lc](wxFocusEvent& e) { + if (WindowState* st = GetState(lc)) + NotifyFocusChange(lc, *st, false); + e.Skip(); + }); + } +} + +LRESULT ListViewProc(wxWindow* w, WindowState& st, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + handled = true; + auto* lc = wxDynamicCast(w, wxListCtrl); + if (!lc) { + handled = false; + return 0; + } + ListViewExtra& ex = Extra(st); + switch (msg) { + case LVM_GETITEMCOUNT: + return lc->GetItemCount(); + case LVM_GETTOPINDEX: + return lc->InReportView() || lc->HasFlag(wxLC_LIST) ? std::max(0L, lc->GetTopItem()) : 0; + case LVM_GETITEMTEXT: { + auto* item = reinterpret_cast(lParam); + if (!item) + return 0; + long index = static_cast(wParam); + wxString text; + if (ValidItem(lc, index) && ValidColumn(lc, item->iSubItem)) + text = lc->GetItemText(index, item->iSubItem); + return CopyText(text, item->pszText, item->cchTextMax); + } + case LVM_GETITEMRECT: { + auto* r = reinterpret_cast(lParam); + return r && ItemRect(lc, static_cast(wParam), -1, r->left, r); + } + case LVM_GETSUBITEMRECT: { + auto* r = reinterpret_cast(lParam); + if (!r) + return FALSE; + int sub = r->top; + int code = r->left; + if (sub == 0 && code == LVIR_BOUNDS) + sub = -1; + return ItemRect(lc, static_cast(wParam), sub, code, r); + } + case LVM_SUBITEMHITTEST: { + auto* info = reinterpret_cast(lParam); + if (!info) + return -1; + ListHit hit = HitTestList(lc, wxPoint(info->pt.x, info->pt.y)); + info->flags = hit.flags; + info->iItem = static_cast(hit.item); + info->iSubItem = hit.item >= 0 ? hit.subItem : -1; + return hit.item; + } + case LVM_SETEXTENDEDLISTVIEWSTYLE: { + DWORD mask = wParam ? static_cast(wParam) : 0xFFFFFFFFu; + DWORD old = ex.exStyle; + ex.exStyle = (old & ~mask) | (static_cast(lParam) & mask); + ApplyExtendedStyle(lc, old, ex.exStyle); + return static_cast(old); + } + case LVM_GETEXTENDEDLISTVIEWSTYLE: + return static_cast(ex.exStyle); + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + default: + handled = false; + return 0; + } +} + +} // namespace mfcwx + +using namespace mfcwx; + +namespace { + +wxListCtrl* ListOf(const CWnd* w) { return w->m_hWnd ? wxDynamicCast(w->GetWx(), wxListCtrl) : nullptr; } + +wxImageList* WxImageList(const CImageList* il) { + return il ? reinterpret_cast(il->m_hImageList) : nullptr; +} + +struct SortContext { + int (*compare)(LPARAM, LPARAM, LPARAM); + LPARAM data; +}; + +int wxCALLBACK SortTrampoline(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) { + auto* ctx = reinterpret_cast(sortData); + return ctx->compare(static_cast(item1), static_cast(item2), ctx->data); +} + +int AddBitmap(wxImageList* il, const wxBitmap& bmp, COLORREF crMask) { + if (!il || !bmp.IsOk()) + return -1; + int cx = 0; + int cy = 0; + il->GetSize(0, cx, cy); + if (cx <= 0 || cy <= 0) + return -1; + int first = -1; + int count = std::max(1, bmp.GetWidth() / cx); + for (int i = 0; i < count; ++i) { + wxBitmap part = bmp.GetWidth() > cx ? bmp.GetSubBitmap(wxRect(i * cx, 0, cx, std::min(cy, bmp.GetHeight()))) + : bmp; + if (part.GetWidth() != cx || part.GetHeight() != cy) + part = wxBitmap(part.ConvertToImage().Size(wxSize(cx, cy), wxPoint(0, 0))); + int index = crMask == CLR_NONE ? il->Add(part) : il->Add(part, ToWxColour(crMask)); + if (first < 0) + first = index; + } + return first; +} + +} // namespace + +// --------------------------------------------------------------------------------------------- +// CImageList + +IMPLEMENT_DYNCREATE(CImageList, CObject) + +CImageList::CImageList() : m_hImageList(nullptr) {} + +CImageList::~CImageList() { DeleteImageList(); } + +BOOL CImageList::Create(int cx, int cy, UINT nFlags, int nInitial, int) { + return OnMain([&]() -> BOOL { + DeleteImageList(); + m_hImageList = reinterpret_cast(new wxImageList(cx, cy, (nFlags & ILC_MASK) != 0, std::max(1, nInitial))); + return TRUE; + }); +} + +BOOL CImageList::Create(UINT nBitmapID, int cx, int, COLORREF crMask) { + return OnMain([&]() -> BOOL { + wxBitmap bmp = LoadBitmapResource(ResRef::FromId(nBitmapID)); + if (!bmp.IsOk() || cx <= 0) + return FALSE; + DeleteImageList(); + auto* il = new wxImageList(cx, bmp.GetHeight(), crMask != CLR_NONE, std::max(1, bmp.GetWidth() / cx)); + m_hImageList = reinterpret_cast(il); + AddBitmap(il, bmp, crMask); + return TRUE; + }); +} + +BOOL CImageList::DeleteImageList() { + if (!m_hImageList) + return FALSE; + wxImageList* il = WxImageList(this); + m_hImageList = nullptr; + OnMain([&] { delete il; }); + return TRUE; +} + +int CImageList::Add(CBitmap* pbmImage, CBitmap* pbmMask) { + return OnMain([&]() -> int { + wxBitmap* bmp = pbmImage ? BitmapFromHandle(static_cast(pbmImage->m_hObject)) : nullptr; + if (!bmp || !bmp->IsOk()) + return -1; + wxBitmap* mask = pbmMask ? BitmapFromHandle(static_cast(pbmMask->m_hObject)) : nullptr; + if (!mask || !mask->IsOk()) + return AddBitmap(WxImageList(this), *bmp, CLR_NONE); + wxImage img = bmp->ConvertToImage(); + wxImage m = mask->ConvertToImage(); + if (!img.HasAlpha()) + img.InitAlpha(); + int w = std::min(img.GetWidth(), m.GetWidth()); + int h = std::min(img.GetHeight(), m.GetHeight()); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) + if (m.GetRed(x, y) > 127) + img.SetAlpha(x, y, 0); + return AddBitmap(WxImageList(this), wxBitmap(img), CLR_NONE); + }); +} + +int CImageList::Add(CBitmap* pbmImage, COLORREF crMask) { + return OnMain([&]() -> int { + wxBitmap* bmp = pbmImage ? BitmapFromHandle(static_cast(pbmImage->m_hObject)) : nullptr; + return bmp ? AddBitmap(WxImageList(this), *bmp, crMask) : -1; + }); +} + +int CImageList::Add(HICON hIcon) { + return OnMain([&]() -> int { + auto* icon = reinterpret_cast(hIcon); + wxImageList* il = WxImageList(this); + if (!il || !icon || !icon->IsOk()) + return -1; + return il->Add(*icon); + }); +} + +int CImageList::GetImageCount() const { + return OnMain([&]() -> int { + wxImageList* il = WxImageList(this); + return il ? il->GetImageCount() : 0; + }); +} + +BOOL CImageList::Draw(CDC* pDC, int nImage, POINT pt, UINT nStyle) { + return OnMain([&]() -> BOOL { + wxImageList* il = WxImageList(this); + wxDC* dc = pDC ? pDC->GetWx() : nullptr; + if (!il || !dc || nImage < 0 || nImage >= il->GetImageCount()) + return FALSE; + int flags = (nStyle & ILD_TRANSPARENT) ? wxIMAGELIST_DRAW_TRANSPARENT : wxIMAGELIST_DRAW_NORMAL; + return il->Draw(nImage, *dc, pt.x, pt.y, flags, true); + }); +} + +// --------------------------------------------------------------------------------------------- +// CHeaderCtrl + +IMPLEMENT_DYNAMIC(CHeaderCtrl, CWnd) + +int CHeaderCtrl::GetItemCount() const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + return lc ? lc->GetColumnCount() : 0; + }); +} + +// --------------------------------------------------------------------------------------------- +// CListCtrl + +IMPLEMENT_DYNAMIC(CListCtrl, CWnd) + +BOOL CListCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { + return CWnd::Create("SysListView32", nullptr, dwStyle, rect, pParentWnd, nID); +} + +COLORREF CListCtrl::GetBkColor() const { + return OnMain([&]() -> COLORREF { + wxListCtrl* lc = ListOf(this); + return lc ? FromWxColour(lc->GetBackgroundColour()) : CLR_NONE; + }); +} + +BOOL CListCtrl::SetBkColor(COLORREF cr) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc) + return FALSE; + if (cr == CLR_NONE && lc->GetParent()) + lc->SetBackgroundColour(lc->GetParent()->GetBackgroundColour()); + else if (cr != CLR_NONE) + lc->SetBackgroundColour(ToWxColour(cr)); + lc->Refresh(); + return TRUE; + }); +} + +COLORREF CListCtrl::GetTextColor() const { + return OnMain([&]() -> COLORREF { + wxListCtrl* lc = ListOf(this); + return lc ? FromWxColour(lc->GetTextColour()) : 0; + }); +} + +BOOL CListCtrl::SetTextColor(COLORREF cr) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc) + return FALSE; + lc->SetTextColour(ToWxColour(cr)); + lc->Refresh(); + return TRUE; + }); +} + +COLORREF CListCtrl::GetTextBkColor() const { + return OnMain([&]() -> COLORREF { + wxListCtrl* lc = ListOf(this); + if (!lc) + return CLR_NONE; + COLORREF c = ListExtra(lc).textBkColor; + return c == CLR_DEFAULT ? FromWxColour(lc->GetBackgroundColour()) : c; + }); +} + +BOOL CListCtrl::SetTextBkColor(COLORREF cr) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc) + return FALSE; + ListExtra(lc).textBkColor = cr; + return TRUE; + }); +} + +CImageList* CListCtrl::GetImageList(int nImageList) const { + return OnMain([&]() -> CImageList* { + wxListCtrl* lc = ListOf(this); + if (!lc || nImageList < 0 || nImageList > 2) + return nullptr; + return ListExtra(lc).imageLists[nImageList]; + }); +} + +CImageList* CListCtrl::SetImageList(CImageList* pImageList, int nImageListType) { + return OnMain([&]() -> CImageList* { + wxListCtrl* lc = ListOf(this); + if (!lc || nImageListType < 0 || nImageListType > 2) + return nullptr; + ListViewExtra& ex = ListExtra(lc); + CImageList* old = ex.imageLists[nImageListType]; + ex.imageLists[nImageListType] = pImageList; + int which = nImageListType == LVSIL_NORMAL ? wxIMAGE_LIST_NORMAL + : nImageListType == LVSIL_SMALL ? wxIMAGE_LIST_SMALL : wxIMAGE_LIST_STATE; + lc->SetImageList(WxImageList(pImageList), which); + return old; + }); +} + +int CListCtrl::GetItemCount() const { return static_cast(::SendMessage(m_hWnd, LVM_GETITEMCOUNT, 0, 0)); } + +BOOL CListCtrl::GetItem(LVITEM* pItem) const { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !pItem || !ValidItem(lc, pItem->iItem) || !ValidColumn(lc, pItem->iSubItem)) + return FALSE; + long item = pItem->iItem; + if (pItem->mask & LVIF_TEXT) + CopyText(lc->GetItemText(item, pItem->iSubItem), pItem->pszText, pItem->cchTextMax); + if (pItem->mask & LVIF_IMAGE) { + wxListItem li; + li.SetId(item); + li.SetColumn(pItem->iSubItem); + li.SetMask(wxLIST_MASK_IMAGE); + pItem->iImage = lc->GetItem(li) ? li.GetImage() : -1; + } + if (pItem->mask & LVIF_PARAM) + pItem->lParam = static_cast(lc->GetItemData(item)); + if (pItem->mask & LVIF_STATE) + pItem->state = ItemState(lc, item, pItem->stateMask); + if (pItem->mask & LVIF_INDENT) + pItem->iIndent = 0; + return TRUE; + }); +} + +BOOL CListCtrl::SetItem(const LVITEM* pItem) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !pItem || !ValidItem(lc, pItem->iItem) || !ValidColumn(lc, pItem->iSubItem)) + return FALSE; + long item = pItem->iItem; + int col = pItem->iSubItem; + if (pItem->mask & LVIF_TEXT) + lc->SetItem(item, col, ItemText(pItem->pszText)); + if (pItem->mask & LVIF_IMAGE) + lc->SetItemColumnImage(item, col, pItem->iImage); + if (col == 0 && (pItem->mask & LVIF_PARAM)) + lc->SetItemPtrData(item, static_cast(pItem->lParam)); + if (col == 0 && (pItem->mask & LVIF_STATE)) + SetItemStateOne(lc, item, pItem->state, pItem->stateMask); + return TRUE; + }); +} + +BOOL CListCtrl::SetItem(int nItem, int nSubItem, UINT nMask, const char* lpszItem, int nImage, UINT nState, + UINT nStateMask, LPARAM lParam) { + LVITEM lvi; + memset(&lvi, 0, sizeof lvi); + lvi.mask = nMask; + lvi.iItem = nItem; + lvi.iSubItem = nSubItem; + lvi.state = nState; + lvi.stateMask = nStateMask; + lvi.pszText = const_cast(lpszItem); + lvi.iImage = nImage; + lvi.lParam = lParam; + return SetItem(&lvi); +} + +int CListCtrl::GetNextItem(int nItem, int nFlags) const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc) + return -1; + int count = lc->GetItemCount(); + UINT want = static_cast(nFlags) & (LVNI_SELECTED | LVNI_FOCUSED | LVNI_CUT | LVNI_DROPHILITED); + if (want & (LVNI_CUT | LVNI_DROPHILITED)) + return -1; + auto matches = [&](int i) { return (ItemState(lc, i, want) & want) == want; }; + if (nFlags & (LVNI_ABOVE | LVNI_TOLEFT)) { + for (int i = std::min(nItem, count) - 1; i >= 0; --i) + if (matches(i)) + return i; + return -1; + } + if (want == LVNI_SELECTED) + return static_cast(lc->GetNextItem(nItem, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)); + for (int i = nItem < 0 ? 0 : nItem + 1; i < count; ++i) + if (matches(i)) + return i; + return -1; + }); +} + +POSITION CListCtrl::GetFirstSelectedItemPosition() const { + return reinterpret_cast(static_cast(1 + GetNextItem(-1, LVNI_SELECTED))); +} + +int CListCtrl::GetNextSelectedItem(POSITION& pos) const { + int old = static_cast(reinterpret_cast(pos)) - 1; + pos = reinterpret_cast(static_cast(1 + GetNextItem(old, LVNI_SELECTED))); + return old; +} + +BOOL CListCtrl::GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const { + if (!lpRect) + return FALSE; + lpRect->left = static_cast(nCode); + return static_cast(::SendMessage(m_hWnd, LVM_GETITEMRECT, static_cast(nItem), + reinterpret_cast(lpRect))); +} + +BOOL CListCtrl::GetSubItemRect(int iItem, int iSubItem, int nArea, CRect& ref) { + RECT* r = &ref; + r->top = iSubItem; + r->left = nArea; + return static_cast(::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, static_cast(iItem), + reinterpret_cast(r))); +} + +BOOL CListCtrl::GetItemPosition(int nItem, LPPOINT lpPoint) const { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + wxPoint p; + if (!lc || !lpPoint || !ValidItem(lc, nItem) || !lc->GetItemPosition(nItem, p)) + return FALSE; + lpPoint->x = p.x; + lpPoint->y = p.y; + return TRUE; + }); +} + +int CListCtrl::GetStringWidth(const char* lpsz) const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + return lc && lpsz ? lc->GetTextExtent(ToWx(lpsz)).x : 0; + }); +} + +BOOL CListCtrl::GetColumn(int nCol, LVCOLUMN* pColumn) const { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !pColumn || nCol < 0 || nCol >= lc->GetColumnCount()) + return FALSE; + wxListItem li; + li.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_WIDTH | wxLIST_MASK_FORMAT | wxLIST_MASK_IMAGE); + if (!lc->GetColumn(nCol, li)) + return FALSE; + if (pColumn->mask & LVCF_TEXT) + CopyText(li.GetText(), pColumn->pszText, pColumn->cchTextMax); + if (pColumn->mask & LVCF_WIDTH) + pColumn->cx = li.GetWidth(); + if (pColumn->mask & LVCF_FMT) + pColumn->fmt = FormatFromAlign(li.GetAlign()); + if (pColumn->mask & LVCF_IMAGE) + pColumn->iImage = li.GetImage(); + if (pColumn->mask & LVCF_SUBITEM) + pColumn->iSubItem = nCol; + if (pColumn->mask & LVCF_ORDER) + pColumn->iOrder = nCol; + return TRUE; + }); +} + +BOOL CListCtrl::SetColumn(int nCol, const LVCOLUMN* pColumn) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !pColumn || nCol < 0 || nCol >= lc->GetColumnCount()) + return FALSE; + wxListItem li; + if (pColumn->mask & LVCF_TEXT) + li.SetText(ItemText(pColumn->pszText)); + if (pColumn->mask & LVCF_WIDTH) + li.SetWidth(pColumn->cx); + if (pColumn->mask & LVCF_FMT) + li.SetAlign(AlignFromFormat(pColumn->fmt)); + if (pColumn->mask & LVCF_IMAGE) + li.SetImage(pColumn->iImage); + return lc->SetColumn(nCol, li); + }); +} + +int CListCtrl::GetColumnWidth(int nCol) const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + return lc && nCol >= 0 && nCol < lc->GetColumnCount() ? lc->GetColumnWidth(nCol) : 0; + }); +} + +BOOL CListCtrl::SetColumnWidth(int nCol, int cx) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || nCol < 0 || nCol >= lc->GetColumnCount()) + return FALSE; + int width = cx == LVSCW_AUTOSIZE ? wxLIST_AUTOSIZE : cx == LVSCW_AUTOSIZE_USEHEADER ? wxLIST_AUTOSIZE_USEHEADER : cx; + return lc->SetColumnWidth(nCol, width); + }); +} + +BOOL CListCtrl::GetViewRect(LPRECT lpRect) const { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !lpRect) + return FALSE; + wxRect r = lc->GetViewRect(); + lpRect->left = r.x; + lpRect->top = r.y; + lpRect->right = r.x + r.width; + lpRect->bottom = r.y + r.height; + return TRUE; + }); +} + +int CListCtrl::GetTopIndex() const { return static_cast(::SendMessage(m_hWnd, LVM_GETTOPINDEX, 0, 0)); } + +int CListCtrl::GetCountPerPage() const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + return lc ? lc->GetCountPerPage() : 0; + }); +} + +BOOL CListCtrl::GetOrigin(LPPOINT lpPoint) const { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !lpPoint) + return FALSE; + lpPoint->x = 0; + lpPoint->y = 0; + return !(lc->InReportView() || lc->HasFlag(wxLC_LIST)); + }); +} + +BOOL CListCtrl::SetItemState(int nItem, LVITEM* pItem) { + if (!pItem) + return FALSE; + return SetItemState(nItem, pItem->state, pItem->stateMask); +} + +BOOL CListCtrl::SetItemState(int nItem, UINT nState, UINT nMask) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + return lc && SetItemStates(lc, nItem, nState, nMask); + }); +} + +UINT CListCtrl::GetItemState(int nItem, UINT nMask) const { + return OnMain([&]() -> UINT { + wxListCtrl* lc = ListOf(this); + return lc && ValidItem(lc, nItem) ? ItemState(lc, nItem, nMask) : 0; + }); +} + +CString CListCtrl::GetItemText(int nItem, int nSubItem) const { + return OnMain([&]() -> CString { + wxListCtrl* lc = ListOf(this); + if (!lc || !ValidItem(lc, nItem) || !ValidColumn(lc, nSubItem)) + return CString(); + return CStr(lc->GetItemText(nItem, nSubItem)); + }); +} + +int CListCtrl::GetItemText(int nItem, int nSubItem, char* lpszText, int nLen) const { + LVITEM lvi; + memset(&lvi, 0, sizeof lvi); + lvi.iSubItem = nSubItem; + lvi.cchTextMax = nLen; + lvi.pszText = lpszText; + return static_cast(::SendMessage(m_hWnd, LVM_GETITEMTEXT, static_cast(nItem), + reinterpret_cast(&lvi))); +} + +BOOL CListCtrl::SetItemText(int nItem, int nSubItem, const char* lpszText) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !ValidItem(lc, nItem) || !ValidColumn(lc, nSubItem)) + return FALSE; + return lc->SetItem(nItem, nSubItem, ItemText(lpszText)); + }); +} + +void CListCtrl::SetItemCount(int nItems) { + OnMain([&] { + wxListCtrl* lc = ListOf(this); + if (lc && lc->IsVirtual()) + lc->SetItemCount(nItems); + }); +} + +BOOL CListCtrl::SetItemData(int nItem, DWORD_PTR dwData) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + return lc && ValidItem(lc, nItem) && lc->SetItemPtrData(nItem, static_cast(dwData)); + }); +} + +DWORD_PTR CListCtrl::GetItemData(int nItem) const { + return OnMain([&]() -> DWORD_PTR { + wxListCtrl* lc = ListOf(this); + return lc && ValidItem(lc, nItem) ? static_cast(lc->GetItemData(nItem)) : 0; + }); +} + +UINT CListCtrl::GetSelectedCount() const { + return OnMain([&]() -> UINT { + wxListCtrl* lc = ListOf(this); + return lc ? static_cast(lc->GetSelectedItemCount()) : 0; + }); +} + +int CListCtrl::GetSelectionMark() const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc) + return -1; + int mark = ListExtra(lc).selectionMark; + return ValidItem(lc, mark) ? mark : -1; + }); +} + +int CListCtrl::SetSelectionMark(int iIndex) { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc) + return -1; + ListViewExtra& ex = ListExtra(lc); + int old = ex.selectionMark; + ex.selectionMark = iIndex; + return old; + }); +} + +DWORD CListCtrl::GetExtendedStyle() const { + return static_cast(::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)); +} + +DWORD CListCtrl::SetExtendedStyle(DWORD dwNewStyle) { + return static_cast(::SendMessage(m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, static_cast(dwNewStyle))); +} + +CHeaderCtrl* CListCtrl::GetHeaderCtrl() const { + return m_hWnd ? static_cast(CWnd::FromHandle(m_hWnd)) : nullptr; +} + +int CListCtrl::InsertItem(const LVITEM* pItem) { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc || !pItem || pItem->iSubItem != 0 || pItem->iItem < 0) + return -1; + long index = std::min(pItem->iItem, lc->GetItemCount()); + wxListItem li; + li.SetId(index); + li.SetText((pItem->mask & LVIF_TEXT) ? ItemText(pItem->pszText) : wxString()); + if (pItem->mask & LVIF_IMAGE) + li.SetImage(pItem->iImage); + long r = lc->InsertItem(li); + if (r < 0) + return -1; + if (pItem->mask & LVIF_PARAM) + lc->SetItemPtrData(r, static_cast(pItem->lParam)); + if (pItem->mask & LVIF_STATE) + SetItemStateOne(lc, r, pItem->state, pItem->stateMask); + return static_cast(r); + }); +} + +int CListCtrl::InsertItem(int nItem, const char* lpszItem) { + return InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0); +} + +int CListCtrl::InsertItem(int nItem, const char* lpszItem, int nImage) { + return InsertItem(LVIF_TEXT | LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0); +} + +int CListCtrl::InsertItem(UINT nMask, int nItem, const char* lpszItem, UINT nState, UINT nStateMask, int nImage, + LPARAM lParam) { + LVITEM lvi; + memset(&lvi, 0, sizeof lvi); + lvi.mask = nMask; + lvi.iItem = nItem; + lvi.state = nState; + lvi.stateMask = nStateMask; + lvi.pszText = const_cast(lpszItem); + lvi.iImage = nImage; + lvi.lParam = lParam; + return InsertItem(&lvi); +} + +BOOL CListCtrl::DeleteItem(int nItem) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !ValidItem(lc, nItem)) + return FALSE; + ListViewExtra& ex = ListExtra(lc); + if (ex.selectionMark == nItem) + ex.selectionMark = -1; + else if (ex.selectionMark > nItem) + --ex.selectionMark; + return lc->DeleteItem(nItem); + }); +} + +BOOL CListCtrl::DeleteAllItems() { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc) + return FALSE; + ListExtra(lc).selectionMark = -1; + return lc->DeleteAllItems(); + }); +} + +int CListCtrl::FindItem(LVFINDINFO* pFindInfo, int nStart) const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc || !pFindInfo) + return -1; + int count = lc->GetItemCount(); + wxString needle = (pFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL)) && pFindInfo->psz ? ToWx(pFindInfo->psz) + : wxString(); + auto matches = [&](int i) { + if (pFindInfo->flags & LVFI_PARAM) + return static_cast(lc->GetItemData(i)) == pFindInfo->lParam; + if (pFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL)) { + wxString text = lc->GetItemText(i); + if (pFindInfo->flags & LVFI_PARTIAL) + return text.Lower().StartsWith(needle.Lower()); + return text.CmpNoCase(needle) == 0; + } + return false; + }; + for (int i = nStart + 1; i < count; ++i) + if (i >= 0 && matches(i)) + return i; + if (pFindInfo->flags & LVFI_WRAP) + for (int i = 0; i <= std::min(nStart, count - 1); ++i) + if (matches(i)) + return i; + return -1; + }); +} + +int CListCtrl::HitTest(LVHITTESTINFO* pHitTestInfo) const { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc || !pHitTestInfo) + return -1; + ListHit hit = HitTestList(lc, wxPoint(pHitTestInfo->pt.x, pHitTestInfo->pt.y)); + pHitTestInfo->flags = hit.flags; + pHitTestInfo->iItem = static_cast(hit.item); + return static_cast(hit.item); + }); +} + +int CListCtrl::HitTest(CPoint pt, UINT* pFlags) const { + LVHITTESTINFO info; + memset(&info, 0, sizeof info); + info.pt = pt; + int item = HitTest(&info); + if (pFlags) + *pFlags = info.flags; + return item; +} + +int CListCtrl::SubItemHitTest(LVHITTESTINFO* pInfo) { + return static_cast(::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, reinterpret_cast(pInfo))); +} + +BOOL CListCtrl::EnsureVisible(int nItem, BOOL) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + return lc && ValidItem(lc, nItem) && lc->EnsureVisible(nItem); + }); +} + +BOOL CListCtrl::Scroll(CSize size) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + return lc && lc->ScrollList(size.cx, size.cy); + }); +} + +BOOL CListCtrl::RedrawItems(int nFirst, int nLast) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc) + return FALSE; + int count = lc->GetItemCount(); + nFirst = std::max(0, nFirst); + nLast = std::min(count - 1, nLast); + if (nFirst <= nLast) + lc->RefreshItems(nFirst, nLast); + return TRUE; + }); +} + +int CListCtrl::InsertColumn(int nCol, const LVCOLUMN* pColumn) { + return OnMain([&]() -> int { + wxListCtrl* lc = ListOf(this); + if (!lc || !pColumn || nCol < 0) + return -1; + long col = std::min(nCol, lc->GetColumnCount()); + wxString heading = (pColumn->mask & LVCF_TEXT) ? ItemText(pColumn->pszText) : wxString(); + wxListColumnFormat fmt = (pColumn->mask & LVCF_FMT) ? AlignFromFormat(pColumn->fmt) : wxLIST_FORMAT_LEFT; + int width = (pColumn->mask & LVCF_WIDTH) ? pColumn->cx : wxLIST_DEFAULT_COL_WIDTH; + return static_cast(lc->InsertColumn(col, heading, fmt, width)); + }); +} + +int CListCtrl::InsertColumn(int nCol, const char* lpszColumnHeading, int nFormat, int nWidth, int nSubItem) { + LVCOLUMN column; + memset(&column, 0, sizeof column); + column.mask = LVCF_TEXT | LVCF_FMT; + column.pszText = const_cast(lpszColumnHeading); + column.fmt = nFormat; + if (nWidth != -1) { + column.mask |= LVCF_WIDTH; + column.cx = nWidth; + } + if (nSubItem != -1) { + column.mask |= LVCF_SUBITEM; + column.iSubItem = nSubItem; + } + return InsertColumn(nCol, &column); +} + +BOOL CListCtrl::DeleteColumn(int nCol) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + return lc && nCol >= 0 && nCol < lc->GetColumnCount() && lc->DeleteColumn(nCol); + }); +} + +BOOL CListCtrl::Update(int nItem) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !ValidItem(lc, nItem)) + return FALSE; + lc->RefreshItem(nItem); + return TRUE; + }); +} + +BOOL CListCtrl::SortItems(int (*pfnCompare)(LPARAM, LPARAM, LPARAM), DWORD_PTR dwData) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !pfnCompare) + return FALSE; + SortContext ctx{pfnCompare, static_cast(dwData)}; + return lc->SortItems(&SortTrampoline, reinterpret_cast(&ctx)); + }); +} + +BOOL CListCtrl::GetCheck(int nItem) const { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + return lc && ValidItem(lc, nItem) && lc->HasCheckBoxes() && lc->IsItemChecked(nItem); + }); +} + +BOOL CListCtrl::SetCheck(int nItem, BOOL fCheck) { + return OnMain([&]() -> BOOL { + wxListCtrl* lc = ListOf(this); + if (!lc || !ValidItem(lc, nItem) || !lc->HasCheckBoxes()) + return FALSE; + lc->CheckItem(nItem, fCheck != FALSE); + return TRUE; + }); +} + +void CListCtrl::DrawItem(LPDRAWITEMSTRUCT) {} diff --git a/port/mfcwx/src/menu.cpp b/port/mfcwx/src/menu.cpp new file mode 100644 index 000000000..e8467cac5 --- /dev/null +++ b/port/mfcwx/src/menu.cpp @@ -0,0 +1,709 @@ +#include "windows_impl.h" + +#include +#include +#include +#include + +namespace mfcwx { + +struct MenuHandle { + wxMenuBar* bar = nullptr; + wxMenu* menu = nullptr; +}; + +namespace { + +std::unordered_map& Handles() { + static auto* m = new std::unordered_map(); + return *m; +} + +std::unordered_map& TempMenus() { + static auto* m = new std::unordered_map(); + return *m; +} + +MenuHandle* FromH(HMENU h) { return reinterpret_cast(h); } + +wxString AccelText(const rc::Accel& a) { + wxString s; + if (a.flags & FCONTROL) + s += "Ctrl+"; + if (a.flags & FALT) + s += "Alt+"; + if (a.flags & FSHIFT) + s += "Shift+"; + if (a.flags & FVIRTKEY) { + int key = WxKeyFromVirtual(static_cast(a.key)); + if (key >= WXK_F1 && key <= WXK_F24) + s += wxString::Format("F%d", key - WXK_F1 + 1); + else if (key == WXK_DELETE) + s += "Del"; + else if (key == WXK_INSERT) + s += "Ins"; + else if (key == WXK_BACK) + s += "Back"; + else if (key == WXK_RETURN) + s += "Enter"; + else if (key == WXK_ESCAPE) + s += "Esc"; + else if (key == WXK_TAB) + s += "Tab"; + else if (key == WXK_SPACE) + s += "Space"; + else if (key > 32 && key < 127) + s += static_cast(key); + else + return wxString(); + } else if (a.key > 0 && a.key < 32) { + s = "Ctrl+" + wxString(static_cast('A' + a.key - 1)); + } else { + s += static_cast(a.key); + } + return s; +} + +const rc::AccelTable*& CurrentAccelTable() { + static const rc::AccelTable* t = nullptr; + return t; +} + +wxString LabelFor(const rc::MenuItem& item) { + wxString label = MenuTextToWx(item.text); + if (const rc::AccelTable* t = CurrentAccelTable()) { + for (int i = 0; i < t->itemCount; ++i) + if (t->items[i].id == item.id) { + wxString accel = AccelText(t->items[i]); + if (!accel.empty()) + return label + "\t" + accel; + } + } + return label; +} + +void AppendItems(wxMenu* menu, const rc::Menu& res, int& index, int depth) { + while (index < res.itemCount && res.items[index].depth >= depth) { + const rc::MenuItem& item = res.items[index]; + if (item.depth > depth) { + ++index; + continue; + } + ++index; + if (item.flags & MF_POPUP) { + auto* sub = new wxMenu; + AppendItems(sub, res, index, depth + 1); + menu->AppendSubMenu(sub, MenuTextToWx(item.text)); + } else if ((item.flags & MF_SEPARATOR) || item.id == 0) { + menu->AppendSeparator(); + } else { + wxMenuItem* mi = menu->Append(MenuWxId(item.id), LabelFor(item)); + if (item.flags & MF_CHECKED) { + mi->SetCheckable(true); + mi->Check(true); + } + if (item.flags & (MF_GRAYED | MF_DISABLED)) + mi->Enable(false); + } + } +} + +void AppendItemsTopLevel(wxMenu* menu, const rc::Menu& res, int& index) { AppendItems(menu, res, index, 0); } + +wxMenu* CloneMenu(wxMenu* src) { + auto* copy = new wxMenu; + for (wxMenuItem* item : src->GetMenuItems()) { + if (item->IsSeparator()) { + copy->AppendSeparator(); + } else if (item->IsSubMenu()) { + copy->AppendSubMenu(CloneMenu(item->GetSubMenu()), item->GetItemLabel()); + } else { + wxMenuItem* mi = copy->Append(item->GetId(), item->GetItemLabel(), wxString(), + item->IsCheckable() ? wxITEM_CHECK : wxITEM_NORMAL); + if (item->IsCheckable()) + mi->Check(item->IsChecked()); + mi->Enable(item->IsEnabled()); + } + } + return copy; +} + +} // namespace + +namespace { + +constexpr int kCompactBase = wxID_HIGHEST + 1; + +struct CompactIds { + std::mutex mutex; + std::unordered_map toWx; + std::vector toWin; +}; + +CompactIds& Compact() { + static CompactIds ids; + return ids; +} + +} // namespace + +int ToWxId(int winId) { + if (winId == -1 || winId == 0xFFFF) + return wxID_ANY; + if (winId + kIdOffset < 0x7fff) + return winId + kIdOffset; + CompactIds& c = Compact(); + std::lock_guard lock(c.mutex); + auto it = c.toWx.find(winId); + if (it != c.toWx.end()) + return it->second; + int compact = kCompactBase + static_cast(c.toWin.size()); + c.toWx.emplace(winId, compact); + c.toWin.push_back(winId); + return compact; +} + +int FromWxId(int wxId) { + if (wxId == wxID_ANY) + return -1; + if (wxId >= kIdOffset) + return wxId - kIdOffset; + CompactIds& c = Compact(); + std::lock_guard lock(c.mutex); + if (wxId >= kCompactBase && wxId < kCompactBase + static_cast(c.toWin.size())) + return c.toWin[static_cast(wxId - kCompactBase)]; + return wxId; +} + +bool IsCommandWxId(int wxId) { + if (wxId >= kIdOffset - 1) + return true; + CompactIds& c = Compact(); + std::lock_guard lock(c.mutex); + return wxId >= kCompactBase && wxId < kCompactBase + static_cast(c.toWin.size()); +} + +int MenuWxId(int winId) { + if (winId == ID_APP_ABOUT) + return wxID_ABOUT; + if (winId == ID_APP_EXIT) + return wxID_EXIT; + return ToWxId(winId); +} + +int MenuWinId(int wxId) { + if (wxId == wxID_ABOUT) + return ID_APP_ABOUT; + if (wxId == wxID_EXIT) + return ID_APP_EXIT; + return FromWxId(wxId); +} + +void SetMenuAccelerators(const rc::AccelTable* table) { CurrentAccelTable() = table; } + +wxMenuBar* BuildMenuBar(const rc::Menu& res) { + auto* bar = new wxMenuBar; + int index = 0; + while (index < res.itemCount) { + const rc::MenuItem& item = res.items[index++]; + if (item.depth != 0) + continue; + auto* menu = new wxMenu; + AppendItems(menu, res, index, 1); + bar->Append(menu, MenuTextToWx(item.text)); + } + return bar; +} + +wxMenu* BuildPopupMenu(const rc::Menu& res, int popupIndex) { + int index = 0; + int seen = 0; + while (index < res.itemCount) { + const rc::MenuItem& item = res.items[index++]; + if (item.depth != 0) + continue; + if (seen++ == popupIndex) { + auto* menu = new wxMenu; + AppendItems(menu, res, index, 1); + return menu; + } + } + return nullptr; +} + +HMENU HandleFromWxMenu(wxMenu* menu) { + if (!menu) + return nullptr; + auto& h = Handles()[menu]; + if (!h) { + h = new MenuHandle; + h->menu = menu; + } + return reinterpret_cast(h); +} + +HMENU HandleFromWxMenuBar(wxMenuBar* bar) { + if (!bar) + return nullptr; + auto& h = Handles()[bar]; + if (!h) { + h = new MenuHandle; + h->bar = bar; + } + return reinterpret_cast(h); +} + +wxMenu* WxMenuFromHandle(HMENU h) { return h ? FromH(h)->menu : nullptr; } +wxMenuBar* WxMenuBarFromHandle(HMENU h) { return h ? FromH(h)->bar : nullptr; } + +namespace { + +// Finds a menu item by command id or position in a menu or menu bar. +struct ItemRef { + wxMenu* parent = nullptr; + wxMenuItem* item = nullptr; + wxMenuBar* bar = nullptr; + int barIndex = -1; +}; + +ItemRef FindItem(HMENU h, UINT pos, UINT flags) { + ItemRef r; + MenuHandle* mh = FromH(h); + if (!mh) + return r; + if (flags & MF_BYPOSITION) { + if (mh->bar) { + if (pos < mh->bar->GetMenuCount()) { + r.bar = mh->bar; + r.barIndex = static_cast(pos); + } + } else if (mh->menu && pos < mh->menu->GetMenuItemCount()) { + r.parent = mh->menu; + r.item = mh->menu->FindItemByPosition(pos); + } + return r; + } + int id = MenuWxId(static_cast(pos)); + wxMenu* owner = nullptr; + wxMenuItem* item = mh->bar ? mh->bar->FindItem(id, &owner) : (mh->menu ? mh->menu->FindItem(id, &owner) : nullptr); + r.item = item; + r.parent = owner; + return r; +} + +} // namespace + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CMenu + +IMPLEMENT_DYNCREATE(CMenu, CObject) + +CMenu::CMenu() : m_hMenu(nullptr) {} + +CMenu::~CMenu() {} + +CMenu* CMenu::FromHandle(HMENU hMenu) { + if (!hMenu) + return nullptr; + auto& m = TempMenus()[FromH(hMenu)]; + if (!m) { + m = new CMenu; + m->m_hMenu = hMenu; + } + return m; +} + +BOOL CMenu::Attach(HMENU hMenu) { + m_hMenu = hMenu; + return hMenu != nullptr; +} + +HMENU CMenu::Detach() { + HMENU h = m_hMenu; + m_hMenu = nullptr; + return h; +} + +BOOL CMenu::CreateMenu() { return Attach(::CreateMenu()); } +BOOL CMenu::CreatePopupMenu() { return Attach(::CreatePopupMenu()); } +BOOL CMenu::LoadMenu(const char* lpszResourceName) { return Attach(::LoadMenu(nullptr, lpszResourceName)); } +BOOL CMenu::LoadMenu(UINT nIDResource) { return Attach(::LoadMenu(nullptr, MAKEINTRESOURCE(nIDResource))); } + +BOOL CMenu::DestroyMenu() { + if (!m_hMenu) + return FALSE; + BOOL r = ::DestroyMenu(m_hMenu); + m_hMenu = nullptr; + return r; +} + +BOOL CMenu::DeleteMenu(UINT nPosition, UINT nFlags) { return ::DeleteMenu(m_hMenu, nPosition, nFlags); } +BOOL CMenu::RemoveMenu(UINT nPosition, UINT nFlags) { return ::RemoveMenu(m_hMenu, nPosition, nFlags); } +BOOL CMenu::AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, const char* lpszNewItem) { + return ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem); +} +BOOL CMenu::InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, const char* lpszNewItem) { + return ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); +} +BOOL CMenu::ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, const char* lpszNewItem) { + return ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); +} +UINT CMenu::CheckMenuItem(UINT nIDCheckItem, UINT nCheck) { return ::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck); } +BOOL CMenu::CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags) { + for (UINT id = nIDFirst; id <= nIDLast; ++id) + ::CheckMenuItem(m_hMenu, id, (nFlags & MF_BYPOSITION) | (id == nIDItem ? MF_CHECKED : MF_UNCHECKED)); + return TRUE; +} +UINT CMenu::EnableMenuItem(UINT nIDEnableItem, UINT nEnable) { return ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable); } +UINT CMenu::GetMenuItemCount() const { return static_cast(::GetMenuItemCount(m_hMenu)); } +UINT CMenu::GetMenuItemID(int nPos) const { return ::GetMenuItemID(m_hMenu, nPos); } +UINT CMenu::GetMenuState(UINT nID, UINT nFlags) const { return ::GetMenuState(m_hMenu, nID, nFlags); } +int CMenu::GetMenuString(UINT nIDItem, char* lpString, int nMaxCount, UINT nFlags) const { + return ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); +} +int CMenu::GetMenuString(UINT nIDItem, CString& rString, UINT nFlags) const { + char buf[512]; + int n = ::GetMenuString(m_hMenu, nIDItem, buf, sizeof buf, nFlags); + rString = buf; + return n; +} +CMenu* CMenu::GetSubMenu(int nPos) const { return FromHandle(::GetSubMenu(m_hMenu, nPos)); } +BOOL CMenu::TrackPopupMenu(UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect) { + return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, pWnd ? pWnd->m_hWnd : nullptr, lpRect); +} +wxMenu* CMenu::GetWxMenu() const { return WxMenuFromHandle(m_hMenu); } +wxMenuBar* CMenu::GetWxMenuBar() const { return WxMenuBarFromHandle(m_hMenu); } + +// --------------------------------------------------------------------------------------------- +// Win32 menu functions + +HMENU LoadMenu(HINSTANCE, const char* lpMenuName) { + const rc::Menu* res = FindMenu(ResRef::From(lpMenuName)); + if (!res) + return nullptr; + return OnMain([&]() -> HMENU { + bool hasTopLevelItems = false; + for (int i = 0; i < res->itemCount; ++i) + if (res->items[i].depth == 0 && !(res->items[i].flags & MF_POPUP)) + hasTopLevelItems = true; + if (hasTopLevelItems) { + auto* menu = new wxMenu; + int index = 0; + AppendItemsTopLevel(menu, *res, index); + return HandleFromWxMenu(menu); + } + return HandleFromWxMenuBar(BuildMenuBar(*res)); + }); +} + +HMENU GetMenu(HWND hWnd) { + if (!IsWindow(hWnd)) + return nullptr; + return OnMain([&]() -> HMENU { + auto* frame = wxDynamicCast(wxGetTopLevelParent(ToWx(hWnd)), wxFrame); + return frame ? HandleFromWxMenuBar(frame->GetMenuBar()) : nullptr; + }); +} + +BOOL SetMenu(HWND hWnd, HMENU hMenu) { + if (!IsWindow(hWnd)) + return FALSE; + return OnMain([&]() -> BOOL { + auto* frame = wxDynamicCast(ToWx(hWnd), wxFrame); + if (!frame) + return FALSE; + wxMenuBar* bar = WxMenuBarFromHandle(hMenu); + if (bar && frame->GetMenuBar() != bar) + frame->SetMenuBar(bar); + return TRUE; + }); +} + +HMENU GetSubMenu(HMENU hMenu, int nPos) { + MenuHandle* mh = FromH(hMenu); + if (!mh || nPos < 0) + return nullptr; + if (mh->bar) + return nPos < static_cast(mh->bar->GetMenuCount()) ? HandleFromWxMenu(mh->bar->GetMenu(static_cast(nPos))) : nullptr; + if (mh->menu && nPos < static_cast(mh->menu->GetMenuItemCount())) { + wxMenuItem* item = mh->menu->FindItemByPosition(static_cast(nPos)); + return item && item->GetSubMenu() ? HandleFromWxMenu(item->GetSubMenu()) : nullptr; + } + return nullptr; +} + +HMENU GetSystemMenu(HWND, BOOL) { return nullptr; } + +HMENU CreateMenu() { + return OnMain([]() -> HMENU { return HandleFromWxMenuBar(new wxMenuBar); }); +} + +HMENU CreatePopupMenu() { + return OnMain([]() -> HMENU { return HandleFromWxMenu(new wxMenu); }); +} + +BOOL DestroyMenu(HMENU hMenu) { + MenuHandle* mh = FromH(hMenu); + if (!mh) + return FALSE; + OnMain([&] { + auto tmp = TempMenus().find(mh); + if (tmp != TempMenus().end()) { + tmp->second->m_hMenu = nullptr; + delete tmp->second; + TempMenus().erase(tmp); + } + if (mh->menu && !mh->menu->GetParent() && !mh->menu->GetMenuBar()) + delete mh->menu; + if (mh->bar && !mh->bar->GetFrame()) + delete mh->bar; + Handles().erase(mh->menu ? static_cast(mh->menu) : static_cast(mh->bar)); + delete mh; + }); + return TRUE; +} + +namespace { + +BOOL InsertItem(HMENU hMenu, int position, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem) { + MenuHandle* mh = FromH(hMenu); + if (!mh) + return FALSE; + return OnMain([&]() -> BOOL { + wxString text = ToWx(lpNewItem ? lpNewItem : ""); + if (mh->bar) { + wxMenu* sub = (uFlags & MF_POPUP) ? WxMenuFromHandle(reinterpret_cast(uIDNewItem)) : new wxMenu; + if (position < 0 || position >= static_cast(mh->bar->GetMenuCount())) + mh->bar->Append(sub, text); + else + mh->bar->Insert(static_cast(position), sub, text); + return TRUE; + } + wxMenu* menu = mh->menu; + if (!menu) + return FALSE; + size_t pos = position < 0 || position > static_cast(menu->GetMenuItemCount()) ? menu->GetMenuItemCount() + : static_cast(position); + if (uFlags & MF_SEPARATOR) { + menu->InsertSeparator(pos); + } else if (uFlags & MF_POPUP) { + menu->Insert(pos, wxID_ANY, text, WxMenuFromHandle(reinterpret_cast(uIDNewItem))); + } else { + wxMenuItem* mi = menu->Insert(pos, MenuWxId(static_cast(uIDNewItem)), text); + if (uFlags & MF_CHECKED) { + mi->SetCheckable(true); + mi->Check(true); + } + if (uFlags & (MF_GRAYED | MF_DISABLED)) + mi->Enable(false); + } + return TRUE; + }); +} + +} // namespace + +BOOL AppendMenu(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem) { + return InsertItem(hMenu, -1, uFlags, uIDNewItem, lpNewItem); +} + +BOOL AppendMenuA(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem) { + return AppendMenu(hMenu, uFlags, uIDNewItem, lpNewItem); +} + +BOOL InsertMenu(HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem) { + int position = -1; + if (uFlags & MF_BYPOSITION) { + position = static_cast(uPosition); + } else { + MenuHandle* mh = FromH(hMenu); + if (mh && mh->menu) { + int id = MenuWxId(static_cast(uPosition)); + const wxMenuItemList& items = mh->menu->GetMenuItems(); + int i = 0; + for (auto* item : items) { + if (item->GetId() == id) { + position = i; + break; + } + ++i; + } + } + } + return InsertItem(hMenu, position, uFlags, uIDNewItem, lpNewItem); +} + +BOOL DeleteMenu(HMENU hMenu, UINT uPosition, UINT uFlags) { + return OnMain([&]() -> BOOL { + ItemRef r = FindItem(hMenu, uPosition, uFlags); + if (r.bar) { + delete r.bar->Remove(static_cast(r.barIndex)); + return TRUE; + } + if (r.parent && r.item) { + r.parent->Destroy(r.item); + return TRUE; + } + return FALSE; + }); +} + +BOOL RemoveMenu(HMENU hMenu, UINT uPosition, UINT uFlags) { + return OnMain([&]() -> BOOL { + ItemRef r = FindItem(hMenu, uPosition, uFlags); + if (r.bar) { + r.bar->Remove(static_cast(r.barIndex)); + return TRUE; + } + if (r.parent && r.item) { + r.parent->Remove(r.item); + return TRUE; + } + return FALSE; + }); +} + +BOOL ModifyMenu(HMENU hMnu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem) { + return OnMain([&]() -> BOOL { + ItemRef r = FindItem(hMnu, uPosition, uFlags); + if (r.bar) { + if (lpNewItem) + r.bar->SetMenuLabel(static_cast(r.barIndex), ToWx(lpNewItem)); + return TRUE; + } + if (!r.item) + return FALSE; + if (lpNewItem && !(uFlags & MF_SEPARATOR)) + r.item->SetItemLabel(ToWx(lpNewItem)); + if (!(uFlags & MF_POPUP) && uIDNewItem && static_cast(uIDNewItem) != MenuWinId(r.item->GetId())) { + size_t pos = 0; + r.parent->FindChildItem(r.item->GetId(), &pos); + wxString label = r.item->GetItemLabel(); + r.parent->Destroy(r.item); + r.parent->Insert(pos, MenuWxId(static_cast(uIDNewItem)), label); + } + return TRUE; + }); +} + +DWORD CheckMenuItem(HMENU hMenu, UINT uIDCheckItem, UINT uCheck) { + return OnMain([&]() -> DWORD { + ItemRef r = FindItem(hMenu, uIDCheckItem, uCheck); + if (!r.item) + return 0xFFFFFFFF; + DWORD old = r.item->IsCheckable() && r.item->IsChecked() ? MF_CHECKED : MF_UNCHECKED; + if (!r.item->IsCheckable()) + r.item->SetCheckable(true); + r.item->Check((uCheck & MF_CHECKED) != 0); + return old; + }); +} + +BOOL EnableMenuItem(HMENU hMenu, UINT uIDEnableItem, UINT uEnable) { + return OnMain([&]() -> BOOL { + ItemRef r = FindItem(hMenu, uIDEnableItem, uEnable); + bool enable = (uEnable & (MF_GRAYED | MF_DISABLED)) == 0; + if (r.bar) { + BOOL old = r.bar->IsEnabledTop(static_cast(r.barIndex)) ? MF_ENABLED : MF_GRAYED; + r.bar->EnableTop(static_cast(r.barIndex), enable); + return old; + } + if (!r.item) + return static_cast(0xFFFFFFFF); + BOOL old = r.item->IsEnabled() ? MF_ENABLED : MF_GRAYED; + r.item->Enable(enable); + return old; + }); +} + +int GetMenuItemCount(HMENU hMenu) { + MenuHandle* mh = FromH(hMenu); + if (!mh) + return -1; + return OnMain([&]() -> int { + return mh->bar ? static_cast(mh->bar->GetMenuCount()) : static_cast(mh->menu->GetMenuItemCount()); + }); +} + +UINT GetMenuItemID(HMENU hMenu, int nPos) { + return OnMain([&]() -> UINT { + ItemRef r = FindItem(hMenu, static_cast(nPos), MF_BYPOSITION); + if (!r.item) + return static_cast(-1); + if (r.item->IsSubMenu()) + return static_cast(-1); + if (r.item->IsSeparator()) + return 0; + return static_cast(MenuWinId(r.item->GetId())); + }); +} + +UINT GetMenuState(HMENU hMenu, UINT uId, UINT uFlags) { + return OnMain([&]() -> UINT { + ItemRef r = FindItem(hMenu, uId, uFlags); + if (r.bar) + return r.bar->IsEnabledTop(static_cast(r.barIndex)) ? MF_POPUP : (MF_POPUP | MF_GRAYED); + if (!r.item) + return static_cast(-1); + UINT state = 0; + if (r.item->IsSeparator()) + state |= MF_SEPARATOR; + if (r.item->IsSubMenu()) + state |= MF_POPUP | (static_cast(r.item->GetSubMenu()->GetMenuItemCount()) << 8); + if (!r.item->IsEnabled()) + state |= MF_GRAYED; + if (r.item->IsCheckable() && r.item->IsChecked()) + state |= MF_CHECKED; + return state; + }); +} + +int GetMenuString(HMENU hMenu, UINT uIDItem, char* lpString, int cchMax, UINT flags) { + return OnMain([&]() -> int { + ItemRef r = FindItem(hMenu, uIDItem, flags); + wxString label; + if (r.bar) + label = r.bar->GetMenuLabel(static_cast(r.barIndex)); + else if (r.item) + label = r.item->GetItemLabel(); + std::string a = FromWx(label); + if (lpString && cchMax > 0) { + strncpy(lpString, a.c_str(), static_cast(cchMax) - 1); + lpString[cchMax - 1] = 0; + } + return static_cast(a.size()); + }); +} + +BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, int, HWND hWnd, const RECT*) { + wxMenu* menu = WxMenuFromHandle(hMenu); + if (!menu || !IsWindow(hWnd)) + return FALSE; + return OnMain([&]() -> BOOL { + wxWindow* w = ToWx(hWnd); + wxPoint p = w->ScreenToClient(wxPoint(x, y)); + std::unique_ptr copy(CloneMenu(menu)); + int id = w->GetPopupMenuSelectionFromUser(*copy, p); + if (id == wxID_NONE) + return 0; + int cmd = MenuWinId(id); + if (uFlags & TPM_RETURNCMD) + return cmd; + DispatchMessageTo(hWnd, WM_COMMAND, MAKEWPARAM(cmd, 0), 0); + return TRUE; + }); +} + +BOOL DrawMenuBar(HWND hWnd) { + if (IsWindow(hWnd)) + OnMain([&] { + if (auto* frame = wxDynamicCast(wxGetTopLevelParent(ToWx(hWnd)), wxFrame)) + if (frame->GetMenuBar()) + frame->GetMenuBar()->Refresh(); + }); + return TRUE; +} diff --git a/port/mfcwx/src/ole.cpp b/port/mfcwx/src/ole.cpp new file mode 100644 index 000000000..7c65f5012 --- /dev/null +++ b/port/mfcwx/src/ole.cpp @@ -0,0 +1,44 @@ +#include "afxole.h" +#include "afxdlgs.h" + +#include "globalmem.h" + +BOOL COleDataObject::AttachClipboard() { return TRUE; } + +BOOL COleDataObject::IsDataAvailable(CLIPFORMAT cfFormat, void*) const { + return ::IsClipboardFormatAvailable(cfFormat); +} + +HGLOBAL COleDataObject::GetGlobalData(CLIPFORMAT cfFormat, void*) const { + if (!::OpenClipboard(nullptr)) + return nullptr; + HGLOBAL copy = nullptr; + if (HANDLE h = ::GetClipboardData(cfFormat)) + copy = mfcwx::GlobalFromData(mfcwx::GlobalData(h), mfcwx::GlobalDataSize(h)); + ::CloseClipboard(); + return copy; +} + +void COleDataSource::CacheGlobalData(CLIPFORMAT cfFormat, HGLOBAL hGlobal, void*) { + if (m_data && m_data != hGlobal) + ::GlobalFree(m_data); + m_data = hGlobal; + m_format = cfFormat; +} + +DROPEFFECT COleDataSource::DoDragDrop(DWORD, LPCRECT, void*) { return DROPEFFECT_NONE; } + +void COleDataSource::SetClipboard() { + if (!m_data || !::OpenClipboard(nullptr)) + return; + ::EmptyClipboard(); + if (::SetClipboardData(m_format, m_data)) + m_data = nullptr; + ::CloseClipboard(); +} + +BOOL CPrintDialog::PrintSelection() const { return (m_pd.Flags & PD_SELECTION) != 0; } +BOOL CPrintDialog::PrintRange() const { return (m_pd.Flags & PD_PAGENUMS) != 0; } +BOOL CPrintDialog::PrintAll() const { return !PrintRange() && !PrintSelection(); } +int CPrintDialog::GetFromPage() const { return PrintRange() ? m_pd.nFromPage : -1; } +int CPrintDialog::GetToPage() const { return PrintRange() ? m_pd.nToPage : -1; } diff --git a/port/mfcwx/src/profile.cpp b/port/mfcwx/src/profile.cpp new file mode 100644 index 000000000..4eefcc7ed --- /dev/null +++ b/port/mfcwx/src/profile.cpp @@ -0,0 +1,775 @@ +#include +#include +#include + +#include "afxwin.h" +#include "bridge.h" +#include "runtime.h" + +#include +#include +#include +#include +#include + +#include +#include + +#undef fopen +#undef rename +#undef remove + +namespace mfcwx { +namespace { + +// --------------------------------------------------------------------------------------------- +// INI files + +struct IniFile { + std::vector lines; + std::string eol = "\r\n"; +}; + +std::mutex& IniLock() { + static std::mutex* m = new std::mutex; + return *m; +} + +std::string Trim(const std::string& s) { + size_t b = s.find_first_not_of(" \t"); + if (b == std::string::npos) + return std::string(); + size_t e = s.find_last_not_of(" \t"); + return s.substr(b, e - b + 1); +} + +void MakeDirectories(const std::string& dir) { + for (size_t pos = 1; pos != std::string::npos;) { + pos = dir.find('/', pos + 1); + mkdir(dir.substr(0, pos).c_str(), 0755); + } +} + +std::string IniPath(LPCSTR file) { + std::string f = file ? file : "win.ini"; + if (f.find_first_of("\\/") == std::string::npos) { + std::string dir = UserConfigDirectory(); + MakeDirectories(dir); + return dir + "/" + NativePath(f.c_str()); + } + return FsPath(f.c_str()); +} + +bool LoadIni(const std::string& path, IniFile& ini) { + FILE* f = ::fopen(path.c_str(), "rb"); + if (!f) + return false; + std::string data; + char buf[8192]; + size_t n; + while ((n = fread(buf, 1, sizeof buf, f)) > 0) + data.append(buf, n); + fclose(f); + if (data.size() >= 3 && static_cast(data[0]) == 0xEF && static_cast(data[1]) == 0xBB && + static_cast(data[2]) == 0xBF) + data.erase(0, 3); + size_t firstNl = data.find('\n'); + ini.eol = firstNl != std::string::npos && firstNl > 0 && data[firstNl - 1] == '\r' ? "\r\n" + : firstNl != std::string::npos ? "\n" + : "\r\n"; + size_t start = 0; + while (start < data.size()) { + size_t nl = data.find('\n', start); + std::string line = data.substr(start, nl == std::string::npos ? std::string::npos : nl - start); + if (!line.empty() && line.back() == '\r') + line.pop_back(); + ini.lines.push_back(line); + if (nl == std::string::npos) + break; + start = nl + 1; + } + return true; +} + +bool SaveIni(const std::string& path, const IniFile& ini) { + FILE* f = ::fopen(path.c_str(), "wb"); + if (!f) { + SetLastErrorFromErrno(errno); + return false; + } + for (const std::string& line : ini.lines) { + fwrite(line.data(), 1, line.size(), f); + fwrite(ini.eol.data(), 1, ini.eol.size(), f); + } + return fclose(f) == 0; +} + +bool SectionName(const std::string& line, std::string& name) { + std::string t = Trim(line); + if (t.empty() || t[0] != '[') + return false; + size_t close = t.find(']'); + name = Trim(t.substr(1, close == std::string::npos ? std::string::npos : close - 1)); + return true; +} + +bool KeyValue(const std::string& line, std::string& key, std::string& value) { + std::string t = Trim(line); + if (t.empty() || t[0] == ';') + return false; + size_t eq = t.find('='); + key = Trim(t.substr(0, eq)); + value = eq == std::string::npos ? std::string() : Trim(t.substr(eq + 1)); + return true; +} + +// Returns the index of the section header line and sets end to the first line after the section. +long FindSection(const IniFile& ini, const char* app, size_t& end) { + std::string name; + for (size_t i = 0; i < ini.lines.size(); ++i) { + if (SectionName(ini.lines[i], name) && strcasecmp(name.c_str(), app) == 0) { + end = i + 1; + std::string other; + while (end < ini.lines.size() && !SectionName(ini.lines[end], other)) + ++end; + return static_cast(i); + } + } + return -1; +} + +DWORD CopyList(const std::vector& items, LPSTR ret, DWORD size) { + if (!ret || size == 0) + return 0; + if (size == 1) { + ret[0] = 0; + return 0; + } + DWORD o = 0; + for (const std::string& item : items) { + if (o + item.size() + 1 > size - 1) { + size_t room = size - 1 - o; + if (room > 0) { + memcpy(ret + o, item.data(), room - 1); + ret[o + room - 1] = 0; + } + ret[size - 2] = 0; + ret[size - 1] = 0; + return size - 2; + } + memcpy(ret + o, item.c_str(), item.size() + 1); + o += static_cast(item.size() + 1); + } + ret[o] = 0; + return o; +} + +DWORD CopyString(const std::string& s, LPSTR ret, DWORD size) { + if (!ret || size == 0) + return 0; + size_t n = std::min(s.size(), static_cast(size - 1)); + memcpy(ret, s.data(), n); + ret[n] = 0; + return static_cast(n); +} + +// --------------------------------------------------------------------------------------------- +// Registry + +constexpr unsigned kKeyMagic = 0x5245474Bu; + +struct RegKey { + unsigned magic; + std::string path; +}; + +std::mutex& RegLock() { + static std::mutex* m = new std::mutex; + return *m; +} + +std::set& RegKeys() { + static auto* s = new std::set; + return *s; +} + +std::string RegistryFile() { + const char* env = getenv("MFCWX_REGISTRY_FILE"); + if (env && *env) + return env; +#ifdef __APPLE__ + return UserConfigDirectory() + "/CrypTool1.ini"; +#else + return UserConfigDirectory() + "/cryptool1.ini"; +#endif +} + +wxFileConfig* Config() { + static wxFileConfig* config = nullptr; + if (!config) { + std::string path = RegistryFile(); + size_t slash = path.rfind('/'); + if (slash != std::string::npos && slash > 0) + MakeDirectories(path.substr(0, slash)); + wxLogNull noLog; + config = new wxFileConfig(wxEmptyString, wxEmptyString, wxString::FromUTF8(path.c_str()), wxEmptyString, + wxCONFIG_USE_LOCAL_FILE); + config->SetExpandEnvVars(false); + config->SetRecordDefaults(false); + } + return config; +} + +void Flush() { + wxLogNull noLog; + Config()->Flush(); +} + +std::string Escape(const std::string& s) { + std::string out; + for (char c : s) { + if (c == '%') + out += "%25"; + else if (c == '/') + out += "%2F"; + else + out += c; + } + return out; +} + +std::string Unescape(const std::string& s) { + std::string out; + for (size_t i = 0; i < s.size(); ++i) { + if (s[i] == '%' && i + 2 < s.size()) { + if (s.compare(i, 3, "%25") == 0) { + out += '%'; + i += 2; + continue; + } + if (s.compare(i, 3, "%2F") == 0) { + out += '/'; + i += 2; + continue; + } + } + out += s[i]; + } + return out; +} + +const char* RootName(HKEY key) { + switch (reinterpret_cast(key)) { + case 0x80000000u: + return "HKEY_CLASSES_ROOT"; + case 0x80000001u: + return "HKEY_CURRENT_USER"; + case 0x80000002u: + return "HKEY_LOCAL_MACHINE"; + case 0x80000003u: + return "HKEY_USERS"; + case 0x80000005u: + return "HKEY_CURRENT_CONFIG"; + default: + return nullptr; + } +} + +// Must be called with RegLock held. Returns false for an invalid handle. +bool BasePath(HKEY key, std::string& path) { + if (const char* root = RootName(key)) { + path = std::string("/") + root; + return true; + } + auto* k = reinterpret_cast(key); + if (!RegKeys().count(k)) + return false; + path = k->path; + return true; +} + +std::string Append(const std::string& base, LPCSTR sub) { + std::string path = base; + if (!sub) + return path; + std::string s = sub; + size_t start = 0; + while (start <= s.size()) { + size_t sep = s.find('\\', start); + std::string part = s.substr(start, sep == std::string::npos ? std::string::npos : sep - start); + if (!part.empty()) + path += "/" + Escape(part); + if (sep == std::string::npos) + break; + start = sep + 1; + } + return path; +} + +bool IsRootPath(const std::string& path) { return std::count(path.begin(), path.end(), '/') == 1; } + +wxString WxPath(const std::string& path) { return ToWx(path.c_str()); } + +std::string ValueEntry(const std::string& keyPath, LPCSTR name) { + return keyPath + "/" + (name && *name ? Escape(name) : std::string("@")); +} + +HKEY NewKey(const std::string& path) { + auto* k = new RegKey{kKeyMagic, path}; + RegKeys().insert(k); + return reinterpret_cast(k); +} + +std::string ToHex(const BYTE* data, size_t n) { + static const char digits[] = "0123456789abcdef"; + std::string out; + for (size_t i = 0; i < n; ++i) { + out += digits[data[i] >> 4]; + out += digits[data[i] & 15]; + } + return out; +} + +std::vector FromHex(const std::string& s) { + std::vector out; + auto val = [](char c) { return c >= 'a' ? c - 'a' + 10 : c >= 'A' ? c - 'A' + 10 : c - '0'; }; + for (size_t i = 0; i + 1 < s.size(); i += 2) + out.push_back(static_cast(val(s[i]) * 16 + val(s[i + 1]))); + return out; +} + +void Decode(const wxString& raw, DWORD& type, std::vector& bytes) { + std::string utf8(raw.utf8_str()); + auto text = [&](size_t prefix) { + std::string ansi = FromWx(raw.Mid(prefix)); + bytes.assign(ansi.begin(), ansi.end()); + bytes.push_back(0); + }; + if (utf8.compare(0, 3, "sz:") == 0) { + type = REG_SZ; + text(3); + } else if (utf8.compare(0, 7, "expand:") == 0) { + type = REG_EXPAND_SZ; + text(7); + } else if (utf8.compare(0, 6, "dword:") == 0) { + type = REG_DWORD; + DWORD v = static_cast(strtoul(utf8.c_str() + 6, nullptr, 16)); + bytes.resize(4); + memcpy(bytes.data(), &v, 4); + } else if (utf8.compare(0, 4, "hex:") == 0) { + type = REG_BINARY; + bytes = FromHex(utf8.substr(4)); + } else if (utf8.size() > 1 && utf8[0] == 't' && utf8.find(':') != std::string::npos) { + type = static_cast(strtoul(utf8.c_str() + 1, nullptr, 10)); + bytes = FromHex(utf8.substr(utf8.find(':') + 1)); + } else { + type = REG_SZ; + text(0); + } +} + +wxString Encode(DWORD type, const BYTE* data, DWORD size) { + if (type == REG_SZ || type == REG_EXPAND_SZ) { + const char* s = reinterpret_cast(data); + size_t n = s ? strnlen(s, size) : 0; + return wxString(type == REG_SZ ? "sz:" : "expand:") + ToWx(s ? s : "", static_cast(n)); + } + if (type == REG_DWORD) { + DWORD v = 0; + memcpy(&v, data, 4); + return wxString::Format("dword:%08x", static_cast(v)); + } + std::string hex = data ? ToHex(data, size) : std::string(); + if (type == REG_BINARY) + return wxString("hex:") + wxString::FromUTF8(hex.c_str()); + return wxString::Format("t%u:", static_cast(type)) + wxString::FromUTF8(hex.c_str()); +} + +} // namespace +} // namespace mfcwx + +using namespace mfcwx; + +DWORD GetPrivateProfileStringA(LPCSTR app, LPCSTR key, LPCSTR def, LPSTR ret, DWORD size, LPCSTR file) { + std::lock_guard lk(IniLock()); + IniFile ini; + LoadIni(IniPath(file), ini); + if (!app) { + std::vector sections; + std::string name; + for (const std::string& line : ini.lines) + if (SectionName(line, name)) + sections.push_back(name); + return CopyList(sections, ret, size); + } + size_t end = 0; + long start = FindSection(ini, app, end); + if (!key) { + std::vector keys; + std::string k, v; + for (size_t i = start < 0 ? end : static_cast(start) + 1; start >= 0 && i < end; ++i) + if (KeyValue(ini.lines[i], k, v)) + keys.push_back(k); + return CopyList(keys, ret, size); + } + if (start >= 0) { + std::string k, v; + for (size_t i = static_cast(start) + 1; i < end; ++i) { + if (KeyValue(ini.lines[i], k, v) && strcasecmp(k.c_str(), key) == 0) { + if (v.size() >= 2 && (v[0] == '"' || v[0] == '\'') && v.back() == v[0]) + v = v.substr(1, v.size() - 2); + return CopyString(v, ret, size); + } + } + } + std::string d = def ? def : ""; + while (!d.empty() && d.back() == ' ') + d.pop_back(); + return CopyString(d, ret, size); +} + +UINT GetPrivateProfileIntA(LPCSTR app, LPCSTR key, INT def, LPCSTR file) { + char buf[64]; + GetPrivateProfileStringA(app, key, "", buf, sizeof buf, file); + if (!buf[0]) + return static_cast(def); + return static_cast(strtol(buf, nullptr, 10)); +} + +DWORD GetPrivateProfileSectionA(LPCSTR app, LPSTR ret, DWORD size, LPCSTR file) { + std::lock_guard lk(IniLock()); + IniFile ini; + LoadIni(IniPath(file), ini); + std::vector items; + size_t end = 0; + long start = app ? FindSection(ini, app, end) : -1; + for (size_t i = start < 0 ? end : static_cast(start) + 1; start >= 0 && i < end; ++i) { + std::string t = Trim(ini.lines[i]); + if (!t.empty() && t[0] != ';') + items.push_back(t); + } + return CopyList(items, ret, size); +} + +BOOL WritePrivateProfileStringA(LPCSTR app, LPCSTR key, LPCSTR value, LPCSTR file) { + if (!app) { + if (!key && !value) + return TRUE; + SetLastError(87); + return FALSE; + } + std::lock_guard lk(IniLock()); + std::string path = IniPath(file); + IniFile ini; + LoadIni(path, ini); + size_t end = 0; + long start = FindSection(ini, app, end); + if (!key) { + if (start < 0) + return TRUE; + ini.lines.erase(ini.lines.begin() + start, ini.lines.begin() + static_cast(end)); + return SaveIni(path, ini) ? TRUE : FALSE; + } + std::string entry = std::string(key) + "=" + (value ? value : ""); + if (start < 0) { + if (!value) + return TRUE; + ini.lines.push_back(std::string("[") + app + "]"); + ini.lines.push_back(entry); + return SaveIni(path, ini) ? TRUE : FALSE; + } + size_t insertAt = static_cast(start) + 1; + std::string k, v; + for (size_t i = static_cast(start) + 1; i < end; ++i) { + if (!Trim(ini.lines[i]).empty()) + insertAt = i + 1; + if (KeyValue(ini.lines[i], k, v) && strcasecmp(k.c_str(), key) == 0) { + if (value) + ini.lines[i] = k + "=" + value; + else + ini.lines.erase(ini.lines.begin() + static_cast(i)); + return SaveIni(path, ini) ? TRUE : FALSE; + } + } + if (!value) + return TRUE; + ini.lines.insert(ini.lines.begin() + static_cast(insertAt), entry); + return SaveIni(path, ini) ? TRUE : FALSE; +} + +LONG RegOpenKeyExA(HKEY key, LPCSTR sub, DWORD, REGSAM, PHKEY result) { + if (!result) + return 87; + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + std::string path = Append(base, sub); + if (!IsRootPath(path) && !Config()->HasGroup(WxPath(path))) + return ERROR_FILE_NOT_FOUND; + *result = NewKey(path); + return ERROR_SUCCESS; +} + +LONG RegOpenKeyA(HKEY key, LPCSTR sub, PHKEY result) { return RegOpenKeyExA(key, sub, 0, KEY_ALL_ACCESS, result); } + +LONG RegCreateKeyExA(HKEY key, LPCSTR sub, DWORD, LPSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY result, + LPDWORD disposition) { + if (!result) + return 87; + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + std::string path = Append(base, sub); + bool existed = IsRootPath(path) || Config()->HasGroup(WxPath(path)); + if (!existed) { + wxString old = Config()->GetPath(); + Config()->SetPath(WxPath(path)); + Config()->SetPath(old.empty() ? wxString("/") : old); + Flush(); + } + if (disposition) + *disposition = existed ? REG_OPENED_EXISTING_KEY : REG_CREATED_NEW_KEY; + *result = NewKey(path); + return ERROR_SUCCESS; +} + +LONG RegCreateKeyA(HKEY key, LPCSTR sub, PHKEY result) { + return RegCreateKeyExA(key, sub, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, result, nullptr); +} + +LONG RegCloseKey(HKEY key) { + if (RootName(key)) + return ERROR_SUCCESS; + std::lock_guard lk(RegLock()); + auto* k = reinterpret_cast(key); + if (!RegKeys().erase(k)) + return ERROR_INVALID_HANDLE; + k->magic = 0; + delete k; + return ERROR_SUCCESS; +} + +LONG RegQueryValueExA(HKEY key, LPCSTR name, LPDWORD, LPDWORD type, LPBYTE data, LPDWORD size) { + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + wxString entry = WxPath(ValueEntry(base, name)); + if (!Config()->HasEntry(entry)) + return ERROR_FILE_NOT_FOUND; + wxString raw; + Config()->Read(entry, &raw); + DWORD t; + std::vector bytes; + Decode(raw, t, bytes); + if (type) + *type = t; + if (!size) + return data ? 87 : ERROR_SUCCESS; + DWORD needed = static_cast(bytes.size()); + if (!data) { + *size = needed; + return ERROR_SUCCESS; + } + if (*size < needed) { + *size = needed; + return ERROR_MORE_DATA; + } + if (needed) + memcpy(data, bytes.data(), needed); + *size = needed; + return ERROR_SUCCESS; +} + +LONG RegSetValueExA(HKEY key, LPCSTR name, DWORD, DWORD type, const BYTE* data, DWORD size) { + if (type == REG_DWORD && (!data || size < 4)) + return 87; + if (!data && size) + return 87; + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + wxLogNull noLog; + if (!Config()->Write(WxPath(ValueEntry(base, name)), Encode(type, data, size))) + return ERROR_ACCESS_DENIED; + Config()->SetPath("/"); + Flush(); + return ERROR_SUCCESS; +} + +LONG RegDeleteValueA(HKEY key, LPCSTR name) { + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + wxString entry = WxPath(ValueEntry(base, name)); + if (!Config()->HasEntry(entry)) + return ERROR_FILE_NOT_FOUND; + Config()->DeleteEntry(entry, false); + Config()->SetPath("/"); + Flush(); + return ERROR_SUCCESS; +} + +LONG RegDeleteKeyA(HKEY key, LPCSTR sub) { + if (!sub || !*sub) + return 87; + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + std::string path = Append(base, sub); + if (IsRootPath(path) || !Config()->HasGroup(WxPath(path))) + return ERROR_FILE_NOT_FOUND; + Config()->DeleteGroup(WxPath(path)); + Config()->SetPath("/"); + Flush(); + return ERROR_SUCCESS; +} + +LONG RegEnumKeyExA(HKEY key, DWORD index, LPSTR name, LPDWORD nameSize, LPDWORD, LPSTR cls, LPDWORD clsSize, + PFILETIME lastWrite) { + if (!name || !nameSize) + return 87; + std::vector names; + { + std::lock_guard lk(RegLock()); + std::string base; + if (!BasePath(key, base)) + return ERROR_INVALID_HANDLE; + wxFileConfig* config = Config(); + if (!config->HasGroup(WxPath(base))) + return 259; + wxString old = config->GetPath(); + config->SetPath(WxPath(base)); + wxString group; + long cookie; + for (bool more = config->GetFirstGroup(group, cookie); more; more = config->GetNextGroup(group, cookie)) + names.push_back(Unescape(FromWx(group))); + config->SetPath(old.empty() ? wxString("/") : old); + } + std::sort(names.begin(), names.end(), + [](const std::string& a, const std::string& b) { return strcasecmp(a.c_str(), b.c_str()) < 0; }); + if (index >= names.size()) + return 259; + const std::string& n = names[index]; + if (*nameSize <= n.size()) { + *nameSize = static_cast(n.size() + 1); + return ERROR_MORE_DATA; + } + memcpy(name, n.c_str(), n.size() + 1); + *nameSize = static_cast(n.size()); + if (cls && clsSize && *clsSize) + cls[0] = 0; + if (clsSize) + *clsSize = 0; + if (lastWrite) + GetSystemTimeAsFileTime(lastWrite); + return ERROR_SUCCESS; +} + +LONG CRegKey::Create(HKEY hKeyParent, const char* lpszKeyName, LPSTR lpszClass, DWORD dwOptions, REGSAM samDesired, + LPSECURITY_ATTRIBUTES lpSecAttr, LPDWORD lpdwDisposition) { + HKEY hKey = nullptr; + LONG r = RegCreateKeyExA(hKeyParent, lpszKeyName, 0, lpszClass, dwOptions, samDesired, lpSecAttr, &hKey, + lpdwDisposition); + if (r == ERROR_SUCCESS) { + Close(); + m_hKey = hKey; + } + return r; +} + +LONG CRegKey::Open(HKEY hKeyParent, const char* lpszKeyName, REGSAM samDesired) { + HKEY hKey = nullptr; + LONG r = RegOpenKeyExA(hKeyParent, lpszKeyName, 0, samDesired, &hKey); + if (r == ERROR_SUCCESS) { + Close(); + m_hKey = hKey; + } + return r; +} + +LONG CRegKey::Close() { + LONG r = ERROR_SUCCESS; + if (m_hKey) { + r = RegCloseKey(m_hKey); + m_hKey = nullptr; + } + return r; +} + +LONG CRegKey::QueryDWORDValue(const char* pszValueName, DWORD& dwValue) { + DWORD type = 0; + DWORD size = sizeof(DWORD); + DWORD value = 0; + LONG r = RegQueryValueExA(m_hKey, pszValueName, nullptr, &type, reinterpret_cast(&value), &size); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + return r; + if (type != REG_DWORD) + return 13; + if (r != ERROR_SUCCESS) + return r; + dwValue = value; + return ERROR_SUCCESS; +} + +LONG CRegKey::QueryStringValue(const char* pszValueName, LPSTR pszValue, ULONG* pnChars) { + if (!pnChars) + return 87; + DWORD type = 0; + DWORD size = *pnChars; + LONG r = RegQueryValueExA(m_hKey, pszValueName, nullptr, &type, reinterpret_cast(pszValue), &size); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + return r; + if (type != REG_SZ && type != REG_EXPAND_SZ) + return 13; + *pnChars = size; + return r; +} + +LONG CRegKey::QueryValue(LPSTR szValue, const char* lpszValueName, DWORD* pdwCount) { + if (!pdwCount) + return 87; + DWORD type = 0; + LONG r = RegQueryValueExA(m_hKey, lpszValueName, nullptr, &type, reinterpret_cast(szValue), pdwCount); + if (r == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ && type != 7) + return 13; + return r; +} + +LONG CRegKey::QueryBinaryValue(const char* pszValueName, void* pValue, ULONG* pnBytes) { + if (!pnBytes) + return 87; + DWORD type = 0; + DWORD size = *pnBytes; + LONG r = RegQueryValueExA(m_hKey, pszValueName, nullptr, &type, static_cast(pValue), &size); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + return r; + if (type != REG_BINARY) + return 13; + *pnBytes = size; + return r; +} + +LONG CRegKey::SetDWORDValue(const char* pszValueName, DWORD dwValue) { + return RegSetValueExA(m_hKey, pszValueName, 0, REG_DWORD, reinterpret_cast(&dwValue), sizeof dwValue); +} + +LONG CRegKey::SetStringValue(const char* pszValueName, const char* pszValue, DWORD dwType) { + if (!pszValue) + return 87; + return RegSetValueExA(m_hKey, pszValueName, 0, dwType, reinterpret_cast(pszValue), + static_cast(strlen(pszValue) + 1)); +} + +LONG CRegKey::SetBinaryValue(const char* pszValueName, const void* pValue, ULONG nBytes) { + return RegSetValueExA(m_hKey, pszValueName, 0, REG_BINARY, static_cast(pValue), nBytes); +} + +LONG CRegKey::DeleteValue(const char* lpszValue) { return RegDeleteValueA(m_hKey, lpszValue); } + +LONG CRegKey::DeleteSubKey(const char* lpszSubKey) { return RegDeleteKeyA(m_hKey, lpszSubKey); } diff --git a/port/mfcwx/src/resources.cpp b/port/mfcwx/src/resources.cpp new file mode 100644 index 000000000..904e2a507 --- /dev/null +++ b/port/mfcwx/src/resources.cpp @@ -0,0 +1,355 @@ +#include "internal.h" + +#include +#include +#include + +#include +#include +#include +#include + +namespace mfcwx { + +namespace { + +struct ResourceContext { + std::vector modules; + std::string language = "en"; + std::string dataDir; + std::string defaultDataDir; + std::mutex bitmapMutex; + std::unordered_map bitmapCache; +}; + +ResourceContext& Ctx() { + static ResourceContext ctx; + return ctx; +} + +bool SameName(const char* a, const char* b) { return a && b && strcasecmp(a, b) == 0; } + +// Languages to search, in order of preference. +std::vector SearchOrder() { + std::vector order; + const std::string& lang = Ctx().language; + auto add = [&order](const rc::Language* l) { + if (l && std::find(order.begin(), order.end(), l) == order.end()) + order.push_back(l); + }; + for (const rc::Module* m : Ctx().modules) { + for (int i = 0; i < m->languageCount; ++i) + if (lang == m->languages[i]->code) + add(m->languages[i]); + } + for (const char* fallback : {"en", "de", "neutral"}) { + for (const rc::Module* m : Ctx().modules) + for (int i = 0; i < m->languageCount; ++i) + if (strcmp(m->languages[i]->code, fallback) == 0) + add(m->languages[i]); + } + for (const rc::Module* m : Ctx().modules) + for (int i = 0; i < m->languageCount; ++i) + add(m->languages[i]); + return order; +} + +int CodePageForLanguage(const char* code) { + for (const rc::Module* m : Ctx().modules) + for (int i = 0; i < m->languageCount; ++i) + if (strcmp(m->languages[i]->code, code) == 0 && m->languages[i]->codepage) + return m->languages[i]->codepage; + return 1252; +} + +} // namespace + +ResRef ResRef::From(const char* lpszName) { + ResRef r; + if (!lpszName) + return r; + if (IS_INTRESOURCE(lpszName)) { + r.id = static_cast(reinterpret_cast(lpszName)); + } else if (lpszName[0] == '#') { + r.id = atoi(lpszName + 1); + } else { + r.name = lpszName; + } + return r; +} + +bool ResRef::Matches(int otherId, const char* otherName) const { + if (!name.empty()) + return SameName(name.c_str(), otherName); + return id != 0 && id == otherId; +} + +void RegisterResourceModule(const rc::Module* module) { + if (module && std::find(Ctx().modules.begin(), Ctx().modules.end(), module) == Ctx().modules.end()) + Ctx().modules.push_back(module); +} + +void SetResourceLanguage(const char* code) { + Ctx().language = code ? code : "en"; + SetAnsiCodePage(CodePageForLanguage(Ctx().language.c_str())); +} + +const char* GetResourceLanguage() { return Ctx().language.c_str(); } + +std::vector AvailableResourceLanguages() { + std::vector codes; + for (const rc::Module* m : Ctx().modules) + for (int i = 0; i < m->languageCount; ++i) { + const rc::Language* l = m->languages[i]; + if (l->dialogCount > 10 && std::find(codes.begin(), codes.end(), l->code) == codes.end()) + codes.push_back(l->code); + } + return codes; +} + +const rc::Dialog* FindDialog(const ResRef& ref) { + for (const rc::Language* l : SearchOrder()) + for (int i = 0; i < l->dialogCount; ++i) + if (ref.Matches(l->dialogs[i].id, l->dialogs[i].name)) + return &l->dialogs[i]; + return nullptr; +} + +const rc::Menu* FindMenu(const ResRef& ref) { + for (const rc::Language* l : SearchOrder()) + for (int i = 0; i < l->menuCount; ++i) + if (ref.Matches(l->menus[i].id, l->menus[i].name)) + return &l->menus[i]; + return nullptr; +} + +const rc::AccelTable* FindAccelTable(const ResRef& ref) { + for (const rc::Language* l : SearchOrder()) + for (int i = 0; i < l->accelCount; ++i) + if (ref.Matches(l->accels[i].id, l->accels[i].name)) + return &l->accels[i]; + return nullptr; +} + +const rc::Toolbar* FindToolbar(const ResRef& ref) { + for (const rc::Language* l : SearchOrder()) + for (int i = 0; i < l->toolbarCount; ++i) + if (ref.Matches(l->toolbars[i].id, l->toolbars[i].name)) + return &l->toolbars[i]; + return nullptr; +} + +std::string FindFileResource(const char* type, const ResRef& ref) { + for (const rc::Language* l : SearchOrder()) + for (int i = 0; i < l->fileCount; ++i) { + const rc::FileResource& f = l->files[i]; + if ((!type || SameName(type, f.type)) && ref.Matches(f.id, f.name)) + return GetDataDirectory() + "/" + f.path; + } + return std::string(); +} + +std::vector FindDlgInit(int dialogId) { + std::vector result; + for (const rc::Language* l : SearchOrder()) { + for (int i = 0; i < l->dlgInitCount; ++i) + if (l->dlgInits[i].dialogId == dialogId) + result.push_back(&l->dlgInits[i]); + if (!result.empty()) + break; + } + return result; +} + +bool LoadResourceString(UINT id, std::string& out) { + for (const rc::Language* l : SearchOrder()) { + const rc::StringEntry* begin = l->strings; + const rc::StringEntry* end = l->strings + l->stringCount; + const rc::StringEntry* it = std::lower_bound( + begin, end, static_cast(id), [](const rc::StringEntry& e, int v) { return e.id < v; }); + if (it != end && it->id == static_cast(id)) { + out = Utf8ToAnsi(it->text); + return true; + } + } + return false; +} + +const rc::VersionInfo* GetVersionInfo() { + for (const rc::Language* l : SearchOrder()) + if (l->version) + return l->version; + return nullptr; +} + +std::string GetDataDirectory() { + if (Ctx().dataDir.empty()) { + wxString env; + if (wxGetEnv("MFCWX_DATA_DIR", &env) && wxDirExists(env)) { + Ctx().dataDir = std::string(env.utf8_str()); + } else { + wxString installed = wxStandardPaths::Get().GetResourcesDir(); +#if !defined(__WXOSX__) + wxFileName exe(wxStandardPaths::Get().GetExecutablePath()); + wxString relative = exe.GetPath() + "/../share/" + exe.GetName(); + if (wxDirExists(relative + "/res")) { + wxFileName dir = wxFileName::DirName(relative); + dir.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE); + installed = dir.GetPath(); + } +#endif + if (wxDirExists(installed + "/res") || Ctx().defaultDataDir.empty()) + Ctx().dataDir = std::string(installed.utf8_str()); + else + Ctx().dataDir = Ctx().defaultDataDir; + } + } + return Ctx().dataDir; +} + +void SetDefaultDataDirectory(const std::string& dir) { Ctx().defaultDataDir = dir; } + +void SetDataDirectory(const std::string& dir) { Ctx().dataDir = dir; } + +wxBitmap LoadBitmapResource(const ResRef& ref) { + std::string path = FindFileResource("BITMAP", ref); + if (path.empty()) + path = FindFileResource(nullptr, ref); + if (path.empty()) + return wxBitmap(); + std::lock_guard lock(Ctx().bitmapMutex); + auto it = Ctx().bitmapCache.find(path); + if (it != Ctx().bitmapCache.end()) + return it->second; + if (!wxImage::FindHandler(wxBITMAP_TYPE_BMP)) + wxInitAllImageHandlers(); + wxLogNull noLog; + wxImage image; + if (!image.LoadFile(wxString::FromUTF8(path), wxBITMAP_TYPE_ANY)) + return wxBitmap(); + wxBitmap bitmap(image); + Ctx().bitmapCache.emplace(path, bitmap); + return bitmap; +} + +wxIcon LoadIconResource(const ResRef& ref) { + std::string path = FindFileResource("ICON", ref); + wxIcon icon; + if (path.empty()) + return icon; + if (!wxImage::FindHandler(wxBITMAP_TYPE_ICO)) + wxInitAllImageHandlers(); + wxLogNull noLog; + wxImage image; + if (image.LoadFile(wxString::FromUTF8(path), wxBITMAP_TYPE_ICO)) + icon.CopyFromBitmap(wxBitmap(image)); + return icon; +} + +wxCursor LoadCursorResource(const ResRef& ref) { + std::string path = FindFileResource("CURSOR", ref); + if (path.empty()) + return wxCursor(); + if (!wxImage::FindHandler(wxBITMAP_TYPE_CUR)) + wxInitAllImageHandlers(); + wxLogNull noLog; + wxImage image; + if (!image.LoadFile(wxString::FromUTF8(path), wxBITMAP_TYPE_CUR)) + return wxCursor(); + return wxCursor(image); +} + +wxString MenuTextToWx(const char* utf8Text) { + wxString text = wxString::FromUTF8(utf8Text ? utf8Text : ""); + int tab = text.Find('\t'); + if (tab != wxNOT_FOUND) + text = text.Left(tab); + return text; +} + +} // namespace mfcwx + +// --------------------------------------------------------------------------------------------- +// Win32 resource functions + +int LoadString(HINSTANCE, UINT uID, char* lpBuffer, int cchBufferMax) { + if (!lpBuffer || cchBufferMax <= 0) + return 0; + std::string s; + if (!mfcwx::LoadResourceString(uID, s)) { + lpBuffer[0] = 0; + return 0; + } + int n = std::min(static_cast(s.size()), cchBufferMax - 1); + memcpy(lpBuffer, s.data(), static_cast(n)); + lpBuffer[n] = 0; + return n; +} + +int LoadStringA(HINSTANCE hInstance, UINT uID, char* lpBuffer, int cchBufferMax) { + return LoadString(hInstance, uID, lpBuffer, cchBufferMax); +} + +namespace { + +struct ResourceHandle { + std::string type; + mfcwx::ResRef ref; + std::vector data; +}; + +} // namespace + +HRSRC FindResource(HMODULE, const char* lpName, const char* lpType) { + mfcwx::ResRef ref = mfcwx::ResRef::From(lpName); + std::string type; + if (IS_INTRESOURCE(lpType)) { + switch (static_cast(reinterpret_cast(lpType))) { + case 1: type = "CURSOR"; break; + case 2: type = "BITMAP"; break; + case 3: type = "ICON"; break; + case 23: type = "HTML"; break; + default: break; + } + } else if (lpType) { + type = lpType; + } + if (type == "RT_DLGINIT" || (IS_INTRESOURCE(lpType) && reinterpret_cast(lpType) == 240)) + return nullptr; + std::string path = mfcwx::FindFileResource(type.empty() ? nullptr : type.c_str(), ref); + if (path.empty()) + return nullptr; + auto* h = new ResourceHandle{type, ref, {}}; + FILE* f = fopen(path.c_str(), "rb"); + if (!f) { + delete h; + return nullptr; + } + char buf[65536]; + size_t n; + while ((n = fread(buf, 1, sizeof buf, f)) > 0) + h->data.insert(h->data.end(), buf, buf + n); + fclose(f); + return reinterpret_cast(h); +} + +HRSRC FindResourceA(HMODULE hModule, const char* lpName, const char* lpType) { + return FindResource(hModule, lpName, lpType); +} + +HGLOBAL LoadResource(HMODULE, HRSRC hResInfo) { return reinterpret_cast(hResInfo); } + +LPVOID LockResource(HGLOBAL hResData) { + if (!hResData) + return nullptr; + auto* h = reinterpret_cast(hResData); + return h->data.empty() ? nullptr : h->data.data(); +} + +DWORD SizeofResource(HMODULE, HRSRC hResInfo) { + if (!hResInfo) + return 0; + return static_cast(reinterpret_cast(hResInfo)->data.size()); +} + +BOOL FreeResource(HGLOBAL) { return TRUE; } diff --git a/port/mfcwx/src/runtime.h b/port/mfcwx/src/runtime.h new file mode 100644 index 000000000..930094624 --- /dev/null +++ b/port/mfcwx/src/runtime.h @@ -0,0 +1,70 @@ +#pragma once + +// Internal contracts of the non-GUI runtime (kernel objects, paths, errors). + +#include "mfcwx/win32.h" + +#include +#include + +namespace mfcwx { + +// Thrown by ExitThread/AfxEndThread and caught by the thread trampoline. +struct ThreadExit { + DWORD code; + bool deleteThread; +}; + +// Creates a kernel thread object running body (now, or on ResumeThread with CREATE_SUSPENDED). +// The thread is signaled after body returns; body's result is the exit code. +HANDLE StartThread(std::function body, DWORD flags, size_t stackSize, DWORD* threadId); +bool IsProcessMainThread(); + +// File kernel objects wrap a POSIX descriptor. With owns == false CloseHandle leaves fd open. +HANDLE HandleFromFd(int fd, const std::string& nativePath, bool owns = true); +int FdFromHandle(HANDLE h); + +// Native path for a path given by the application, resolving letter case per component +// when the exact path does not exist (Windows paths are case-insensitive). +std::string FsPath(const char* appPath); +// Absolute, normalized native path ("." and ".." removed); relative paths are based on the cwd. +std::string AbsoluteNativePath(const char* appPath); +// Absolute path in the application's form ('\\' separators, ANSI). +std::string FullAppPath(const char* appPath); + +std::string ExecutablePath(); +// LoadLibrary/GetModuleHandle succeed for this DLL base name (case-insensitive) with a pseudo module +// whose GetProcAddress returns NULL; used for libraries built into the toolkit (Scintilla). +void RegisterBuiltinModule(const char* baseName); +std::string TempDirectory(); +std::string UserConfigDirectory(); +void SetCommandLineOverride(const char* commandLine); + +DWORD ErrnoToWin32(int err); +void SetLastErrorFromErrno(int err); + +// FILETIME counts 100 ns intervals since 1601-01-01 UTC. +constexpr LONGLONG kFileTimeUnixEpoch = 116444736000000000LL; +inline FILETIME MakeFileTime(time_t sec, long nsec = 0) { + ULONGLONG v = static_cast(static_cast(sec) * 10000000LL + nsec / 100 + kFileTimeUnixEpoch); + FILETIME ft; + ft.dwLowDateTime = static_cast(v); + ft.dwHighDateTime = static_cast(v >> 32); + return ft; +} +inline LONGLONG FileTimeTicks(const FILETIME& ft) { + return static_cast((static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime); +} +inline time_t FileTimeToUnix(const FILETIME& ft) { + LONGLONG t = FileTimeTicks(ft) - kFileTimeUnixEpoch; + return static_cast(t >= 0 ? t / 10000000LL : -((-t + 9999999LL) / 10000000LL)); +} + +// Case mapping and classification of single ANSI characters in the current code page. +char AnsiToUpper(char ch); +char AnsiToLower(char ch); +bool AnsiIsAlpha(char ch); +bool AnsiIsUpper(char ch); +bool AnsiIsLower(char ch); + +} // namespace mfcwx diff --git a/port/mfcwx/src/scintilla.cpp b/port/mfcwx/src/scintilla.cpp new file mode 100644 index 000000000..b94305974 --- /dev/null +++ b/port/mfcwx/src/scintilla.cpp @@ -0,0 +1,1343 @@ +#include "windows_impl.h" + +#include + +// The application's Scintilla 1.77 headers; message ids are unchanged in wx's Scintilla. +#include "../../../scintilla/include/Scintilla.h" +#include "../../../scintilla/include/SciLexer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static_assert(offsetof(SCNotification, nmhdr) == 0, "SCNotification must start with its header"); +static_assert(sizeof(NotifyHeader) == sizeof(NMHDR), "NotifyHeader must match NMHDR"); +static_assert(offsetof(NotifyHeader, code) == offsetof(NMHDR, code), "NotifyHeader must match NMHDR"); + +namespace mfcwx { +namespace { + +constexpr int kModInsertCheck = 0x100000; +constexpr int kWrapWhitespace = 3; +constexpr int kCrypToolLexer = SCLEX_AUTOMATIC + 1; +constexpr int kAlwaysWatched = SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT | SC_MOD_BEFOREDELETE | kModInsertCheck; + +struct Codec { + int cp = 0; + unsigned char encLen[256]; + char enc[256][3]; + std::vector dec; +}; + +const Codec& CurrentCodec() { + static Codec codec; + int cp = GetAnsiCodePage(); + if (codec.cp == cp && !codec.dec.empty()) + return codec; + codec.cp = cp; + codec.dec.assign(0x10000, -1); + for (int b = 0; b < 256; ++b) { + uint32_t u = b < 0x80 ? static_cast(b) + : static_cast(AnsiToUnicode(static_cast(b))) & 0xFFFF; + char* o = codec.enc[b]; + if (u < 0x80) { + o[0] = static_cast(u); + codec.encLen[b] = 1; + } else if (u < 0x800) { + o[0] = static_cast(0xC0 | (u >> 6)); + o[1] = static_cast(0x80 | (u & 0x3F)); + codec.encLen[b] = 2; + } else { + o[0] = static_cast(0xE0 | (u >> 12)); + o[1] = static_cast(0x80 | ((u >> 6) & 0x3F)); + o[2] = static_cast(0x80 | (u & 0x3F)); + codec.encLen[b] = 3; + } + codec.dec[u] = static_cast(b); + } + return codec; +} + +// Like Scintilla, every byte of an invalid sequence counts as a character. +int Utf8Width(const unsigned char* s, size_t avail) { + unsigned c = s[0]; + if (c < 0xC2) + return 1; + int n; + if (c < 0xE0) + n = 2; + else if (c < 0xF0) + n = 3; + else if (c < 0xF5) + n = 4; + else + return 1; + if (static_cast(n) > avail) + return 1; + for (int i = 1; i < n; ++i) + if ((s[i] & 0xC0) != 0x80) + return 1; + if (n == 3) { + if ((c == 0xE0 && s[1] < 0xA0) || (c == 0xED && s[1] >= 0xA0)) + return 1; + if (c == 0xEF && s[1] == 0xBF && (s[2] == 0xBE || s[2] == 0xBF)) + return 1; + } else if (n == 4) { + if ((c == 0xF0 && s[1] < 0x90) || (c == 0xF4 && s[1] >= 0x90)) + return 1; + } + return n; +} + +uint32_t Utf8Decode(const unsigned char* s, int n) { + switch (n) { + case 1: + return s[0]; + case 2: + return ((s[0] & 0x1Fu) << 6) | (s[1] & 0x3Fu); + case 3: + return ((s[0] & 0x0Fu) << 12) | ((s[1] & 0x3Fu) << 6) | (s[2] & 0x3Fu); + default: + return ((s[0] & 0x07u) << 18) | ((s[1] & 0x3Fu) << 12) | ((s[2] & 0x3Fu) << 6) | (s[3] & 0x3Fu); + } +} + +bool AnsiFromCodePoint(const Codec& c, uint32_t u, char& out) { + if (u < 0x80) { + out = static_cast(u); + return true; + } + if (u < 0x10000 && c.dec[u] >= 0) { + out = static_cast(c.dec[u]); + return true; + } + out = '?'; + return false; +} + +bool AnsiAt(const Codec& c, const unsigned char* s, int n, char& out) { + if (n == 1 && s[0] >= 0x80) { + out = '?'; + return false; + } + return AnsiFromCodePoint(c, Utf8Decode(s, n), out); +} + +std::string Utf8FromAnsi(const char* s, size_t n) { + const Codec& c = CurrentCodec(); + std::string out; + out.reserve(n + n / 2); + for (size_t i = 0; i < n; ++i) { + unsigned char b = static_cast(s[i]); + if (b < 0x80) + out.push_back(static_cast(b)); + else + out.append(c.enc[b], c.encLen[b]); + } + return out; +} + +std::string Utf8FromAnsi(const char* s) { return s ? Utf8FromAnsi(s, strlen(s)) : std::string(); } + +std::string AnsiFromUtf8(const char* s, size_t n) { + const Codec& c = CurrentCodec(); + std::string out; + out.reserve(n); + const unsigned char* p = reinterpret_cast(s); + for (size_t i = 0; i < n;) { + if (p[i] < 0x80) { + out.push_back(static_cast(p[i++])); + continue; + } + int w = Utf8Width(p + i, n - i); + char a; + AnsiAt(c, p + i, w, a); + out.push_back(a); + i += static_cast(w); + } + return out; +} + +std::string AnsiFromWx(const wxString& s) { + const Codec& c = CurrentCodec(); + std::string out; + out.reserve(s.length()); + for (wxString::const_iterator it = s.begin(); it != s.end(); ++it) { + char a; + AnsiFromCodePoint(c, static_cast((*it).GetValue()), a); + out.push_back(a); + } + return out; +} + +const unsigned char* RangeBytes(wxStyledTextCtrl* s, int pos, int len) { + return reinterpret_cast(s->GetRangePointer(pos, len)); +} + +int CountRange(wxStyledTextCtrl* s, int pos, int len, bool* high) { + if (high) + *high = false; + if (len <= 0) + return 0; + const unsigned char* p = RangeBytes(s, pos, len); + int chars = 0; + for (int i = 0; i < len; ++chars) { + if (p[i] < 0x80) { + ++i; + continue; + } + if (high) + *high = true; + i += Utf8Width(p + i, static_cast(len - i)); + } + return chars; +} + +class PosMap { +public: + static constexpr int kStride = 256; + static constexpr int kChunk = 1 << 16; + + void Reset() { Restart(); } + + void Changed(wxStyledTextCtrl* s, int pos, int byteDelta, int charDelta, bool charsKnown, bool insertedNonAscii) { + if (ascii_) { + if (!insertedNonAscii) + return; + int before = s->GetLength() - byteDelta; + int keep = std::max(0, std::min(pos, before)) / kStride; + ascii_ = false; + complete_ = false; + firstHigh_ = INT_MAX; + marks_.resize(static_cast(keep) + 1); + for (int k = 0; k <= keep; ++k) + marks_[static_cast(k)] = k * kStride; + chars_ = bytes_ = keep * kStride; + total_ = charsKnown ? before + charDelta : -1; + return; + } + if (pos < 0) + pos = 0; + size_t k = static_cast(std::upper_bound(marks_.begin(), marks_.end(), pos) - marks_.begin()) - 1; + marks_.resize(k + 1); + chars_ = static_cast(k) * kStride; + bytes_ = marks_[k]; + complete_ = false; + if (firstHigh_ >= bytes_) + firstHigh_ = INT_MAX; + total_ = total_ >= 0 && charsKnown ? total_ + charDelta : -1; + } + + int ToBytes(wxStyledTextCtrl* s, int ansi) { + if (ansi <= 0 || ascii_) + return ansi; + Validate(s); + if (!complete_ && chars_ < ansi) + Scan(s, ansi, 0); + if (ascii_) + return ansi; + if (ansi >= chars_) + return bytes_ + (ansi - chars_); + size_t k = static_cast(ansi / kStride); + int off = marks_[k]; + int count = ansi - static_cast(k) * kStride; + int span = std::min(s->GetLength() - off, count * 4 + 4); + const unsigned char* p = RangeBytes(s, off, span); + int i = 0; + for (; count > 0 && i < span; --count) + i += p[i] < 0x80 ? 1 : Utf8Width(p + i, static_cast(span - i)); + return off + i; + } + + int ToAnsi(wxStyledTextCtrl* s, int bytes) { + if (bytes <= 0 || ascii_) + return bytes; + Validate(s); + if (!complete_ && bytes_ < bytes) + Scan(s, 0, bytes); + if (ascii_) + return bytes; + if (bytes >= bytes_) + return chars_ + (bytes - bytes_); + size_t k = static_cast(std::upper_bound(marks_.begin(), marks_.end(), bytes) - marks_.begin()) - 1; + int off = marks_[k]; + int idx = static_cast(k) * kStride; + int span = std::min(s->GetLength() - off, bytes - off + 4); + const unsigned char* p = RangeBytes(s, off, span); + for (int i = 0; off + i < bytes;) { + int w = p[i] < 0x80 ? 1 : Utf8Width(p + i, static_cast(span - i)); + if (off + i + w > bytes) + break; + i += w; + ++idx; + } + return idx; + } + + int AnsiLength(wxStyledTextCtrl* s) { + if (ascii_) + return s->GetLength(); + Validate(s); + if (total_ >= 0) + return total_; + Scan(s, INT_MAX, INT_MAX); + return ascii_ ? s->GetLength() : chars_; + } + +private: + void Restart() { + ascii_ = false; + complete_ = false; + chars_ = bytes_ = 0; + total_ = -1; + firstHigh_ = INT_MAX; + marks_.assign(1, 0); + } + + // Safety net against changes that bypassed the modification events. + void Validate(wxStyledTextCtrl* s) { + int n = s->GetLength(); + if (bytes_ > n || (complete_ && bytes_ != n) || total_ > n) + Restart(); + } + + void Scan(wxStyledTextCtrl* s, int targetChars, int targetBytes) { + int n = s->GetLength(); + while (bytes_ < n && (chars_ < targetChars || bytes_ < targetBytes)) { + int base = bytes_; + int chunk = std::min(n - base, kChunk); + const unsigned char* p = RangeBytes(s, base, chunk); + int i = 0; + while (i < chunk && (chars_ < targetChars || base + i < targetBytes)) { + int w = 1; + if (p[i] >= 0x80) { + if (chunk - i < 4 && base + chunk < n) + break; + w = Utf8Width(p + i, static_cast(chunk - i)); + if (firstHigh_ == INT_MAX) + firstHigh_ = base + i; + } + i += w; + ++chars_; + if (chars_ % kStride == 0) + marks_.push_back(base + i); + } + bytes_ = base + i; + } + if (bytes_ >= n) { + complete_ = true; + total_ = chars_; + if (firstHigh_ == INT_MAX) + ascii_ = true; + } + } + + bool ascii_ = true; + bool complete_ = true; + int chars_ = 0; + int bytes_ = 0; + int total_ = 0; + int firstHigh_ = INT_MAX; + std::vector marks_{0}; +}; + +struct SciData { + wxStyledTextCtrl* stc = nullptr; + PosMap map; + int appModMask = SC_MODEVENTMASKALL; + int appCodePage = 0; + bool cryptoolLexer = false; + std::map props; + bool alphabet[256] = {}; + bool alphabetEmpty = true; + int nonAlphabetStyle = 0; + int stylingAnsi = 0; + int lengthForEncode = -1; + std::string mirror; + bool mirrorValid = false; + int pendingDeletePos = -1; + int pendingDeleteLength = 0; + int pendingDeleteChars = 0; +}; + +std::unordered_map>& Registry() { + static std::unordered_map> registry; + return registry; +} + +SciData* FindData(wxWindow* w) { + auto it = Registry().find(w); + return it == Registry().end() ? nullptr : it->second.get(); +} + +int ControlModMask(int appMask) { return appMask | kAlwaysWatched; } + +int PosArg(uintptr_t v) { return static_cast(static_cast(v)); } +int PosArg(intptr_t v) { return static_cast(v); } +WPARAM PosW(int pos) { return static_cast(static_cast(pos)); } +LPARAM PosL(int pos) { return static_cast(pos); } + +LRESULT Pass(SciData& d, UINT msg, WPARAM wp, LPARAM lp) { + return static_cast(d.stc->SendMsg(static_cast(msg), static_cast(wp), static_cast(lp))); +} + +LPARAM Ptr(const std::string& s) { return reinterpret_cast(s.c_str()); } + +int A2B(SciData& d, int ansi) { return d.map.ToBytes(d.stc, ansi); } +int B2A(SciData& d, int bytes) { return d.map.ToAnsi(d.stc, bytes); } +LRESULT B2A(SciData& d, LRESULT bytes) { return B2A(d, static_cast(bytes)); } + +std::string AnsiOfBytes(SciData& d, int b0, int b1) { + int n = d.stc->GetLength(); + b0 = std::max(0, std::min(b0, n)); + b1 = std::max(b0, std::min(b1, n)); + if (b1 == b0) + return std::string(); + return AnsiFromUtf8(d.stc->GetRangePointer(b0, b1 - b0), static_cast(b1 - b0)); +} + +std::string AnsiRange(SciData& d, int a0, int a1) { + if (a1 <= a0) + return std::string(); + return AnsiOfBytes(d, A2B(d, std::max(a0, 0)), A2B(d, a1)); +} + +LRESULT PutString(const std::string& s, LPARAM buf) { + if (buf) { + char* out = reinterpret_cast(buf); + memcpy(out, s.data(), s.size()); + out[s.size()] = '\0'; + } + return static_cast(s.size()); +} + +std::string FetchString(SciData& d, UINT msg, WPARAM wp, bool sizeIncludesNul) { + LRESULT n = Pass(d, msg, wp, 0); + if (sizeIncludesNul) + --n; + if (n <= 0) + return std::string(); + std::vector buf(static_cast(n) + 2, '\0'); + Pass(d, msg, wp, reinterpret_cast(buf.data())); + return AnsiFromUtf8(buf.data(), static_cast(n)); +} + +void RememberCopied(std::string ansiBytes, size_t minSize = 0) { + if (ansiBytes.empty()) + return; + RememberClipboardText(std::move(ansiBytes), minSize); +} + +void RebuildAlphabet(SciData& d) { + const std::string& a = d.props["cryptool.alphabet"]; + std::fill(std::begin(d.alphabet), std::end(d.alphabet), false); + for (unsigned char ch : a) + d.alphabet[ch] = true; + d.alphabetEmpty = a.empty(); + d.nonAlphabetStyle = atoi(d.props["cryptool.nonalphabetstyle"].c_str()); +} + +void Notify(wxWindow* w, SCNotification& scn) { NotifyParentNM(w, reinterpret_cast(&scn.nmhdr)); } + +SCNotification MakeNotification(unsigned code) { + SCNotification scn; + memset(&scn, 0, sizeof scn); + scn.nmhdr.code = code; + return scn; +} + +void LexCrypTool(SciData& d, int endPos) { + wxStyledTextCtrl* s = d.stc; + int length = s->GetLength(); + int end = std::min(endPos, length); + int start = s->PositionFromLine(s->LineFromPosition(s->GetEndStyled())); + if (end <= start) + return; + int n = end - start; + const unsigned char* p = reinterpret_cast(s->GetRangePointer(start, n)); + std::vector styles(static_cast(n), 0); + if (!d.alphabetEmpty) { + const Codec& c = CurrentCodec(); + char other = static_cast(d.nonAlphabetStyle); + for (int i = 0; i < n;) { + int w = p[i] < 0x80 ? 1 : Utf8Width(p + i, static_cast(n - i)); + char a; + bool known = AnsiAt(c, p + i, w, a); + if (!known || !d.alphabet[static_cast(a)]) + std::fill(styles.begin() + i, styles.begin() + i + w, other); + i += w; + } + } + s->SendMsg(SCI_STARTSTYLING, start, 0xff); + s->SendMsg(SCI_SETSTYLINGEX, n, reinterpret_cast(styles.data())); +} + +// Text typed, pasted or dropped is reduced to the ANSI code page, as on Windows. +void SanitizeInsertion(SciData& d, wxStyledTextEvent& e) { + wxString text = e.GetString(); + const Codec& c = CurrentCodec(); + bool bad = false; + for (wxString::const_iterator it = text.begin(); it != text.end() && !bad; ++it) { + char a; + bad = !AnsiFromCodePoint(c, static_cast((*it).GetValue()), a); + } + if (!bad) + return; + wxString clean; + clean.reserve(text.length()); + for (wxString::const_iterator it = text.begin(); it != text.end(); ++it) { + char a; + clean += AnsiFromCodePoint(c, static_cast((*it).GetValue()), a) ? *it : wxUniChar('?'); + } + d.stc->ChangeInsertion(static_cast(clean.utf8_str().length()), clean); +} + +void OnModified(wxWindow* w, wxStyledTextEvent& e) { + SciData* d = FindData(w); + if (!d) + return; + int type = e.GetModificationType(); + if (type & kModInsertCheck) { + SanitizeInsertion(*d, e); + return; + } + int pos = e.GetPosition(); + int len = e.GetLength(); + int ansiLength = -1; + if (type & SC_MOD_BEFOREDELETE) { + d->pendingDeletePos = pos; + d->pendingDeleteLength = len; + d->pendingDeleteChars = ansiLength = CountRange(d->stc, pos, len, nullptr); + } else if (type & SC_MOD_INSERTTEXT) { + bool high = false; + ansiLength = CountRange(d->stc, pos, len, &high); + d->map.Changed(d->stc, pos, len, ansiLength, true, high); + d->mirrorValid = false; + } else if (type & SC_MOD_DELETETEXT) { + bool known = d->pendingDeletePos == pos && d->pendingDeleteLength == len; + if (known) + ansiLength = d->pendingDeleteChars; + d->pendingDeletePos = -1; + d->map.Changed(d->stc, pos, -len, known ? -ansiLength : 0, known, false); + d->mirrorValid = false; + } + if (!(type & d->appModMask)) + return; + SCNotification scn = MakeNotification(SCN_MODIFIED); + scn.modificationType = type; + scn.linesAdded = e.GetLinesAdded(); + scn.line = e.GetLine(); + scn.foldLevelNow = e.GetFoldLevelNow(); + scn.foldLevelPrev = e.GetFoldLevelPrev(); + scn.position = B2A(*d, pos); + std::string text; + if (type & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT | SC_MOD_BEFOREINSERT)) { + text = AnsiFromWx(e.GetString()); + scn.text = text.c_str(); + if (ansiLength < 0) + ansiLength = text.empty() && len > 0 ? len : static_cast(text.size()); + } else if (ansiLength < 0 && len > 0) { + ansiLength = B2A(*d, pos + len) - scn.position; + } + scn.length = std::max(ansiLength, 0); + if (!(type & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR))) + NotifyParent(w, SCEN_CHANGE); + Notify(w, scn); +} + +void OnStyleNeeded(wxWindow* w, wxStyledTextEvent& e) { + SciData* d = FindData(w); + if (!d) + return; + if (d->cryptoolLexer) { + LexCrypTool(*d, e.GetPosition()); + return; + } + SCNotification scn = MakeNotification(SCN_STYLENEEDED); + scn.position = B2A(*d, e.GetPosition()); + Notify(w, scn); +} + +int MacroLParam(const wxStyledTextEvent& e) { + switch (e.GetMessage()) { + case SCI_REPLACESEL: + case SCI_ADDTEXT: + case SCI_INSERTTEXT: + case SCI_APPENDTEXT: + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + return 0; + default: + return e.GetLParam(); + } +} + +void ForwardEvent(wxWindow* w, wxStyledTextEvent& e) { + SciData* d = FindData(w); + if (!d || w->IsBeingDeleted()) + return; + wxEventType t = e.GetEventType(); + SCNotification scn = MakeNotification(0); + std::string text; + scn.modifiers = e.GetModifiers(); + if (t == wxEVT_STC_CHARADDED) { + char a; + AnsiFromCodePoint(CurrentCodec(), static_cast(e.GetKey()), a); + scn.nmhdr.code = SCN_CHARADDED; + scn.ch = static_cast(a); + } else if (t == wxEVT_STC_SAVEPOINTREACHED) { + scn.nmhdr.code = SCN_SAVEPOINTREACHED; + } else if (t == wxEVT_STC_SAVEPOINTLEFT) { + scn.nmhdr.code = SCN_SAVEPOINTLEFT; + } else if (t == wxEVT_STC_ROMODIFYATTEMPT) { + scn.nmhdr.code = SCN_MODIFYATTEMPTRO; + } else if (t == wxEVT_STC_DOUBLECLICK) { + scn.nmhdr.code = SCN_DOUBLECLICK; + scn.position = B2A(*d, e.GetPosition()); + scn.line = e.GetLine(); + } else if (t == wxEVT_STC_UPDATEUI) { + scn.nmhdr.code = SCN_UPDATEUI; + } else if (t == wxEVT_STC_MACRORECORD) { + scn.nmhdr.code = SCN_MACRORECORD; + scn.message = e.GetMessage(); + scn.wParam = static_cast(e.GetWParam()); + scn.lParam = MacroLParam(e); + } else if (t == wxEVT_STC_MARGINCLICK) { + scn.nmhdr.code = SCN_MARGINCLICK; + scn.position = B2A(*d, e.GetPosition()); + scn.margin = e.GetMargin(); + } else if (t == wxEVT_STC_NEEDSHOWN) { + scn.nmhdr.code = SCN_NEEDSHOWN; + scn.position = B2A(*d, e.GetPosition()); + scn.length = B2A(*d, e.GetPosition() + e.GetLength()) - scn.position; + } else if (t == wxEVT_STC_PAINTED) { + scn.nmhdr.code = SCN_PAINTED; + } else if (t == wxEVT_STC_USERLISTSELECTION || t == wxEVT_STC_AUTOCOMP_SELECTION) { + scn.nmhdr.code = t == wxEVT_STC_USERLISTSELECTION ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION; + scn.listType = e.GetListType(); + text = AnsiFromWx(e.GetString()); + scn.text = text.c_str(); + scn.lParam = B2A(*d, e.GetPosition()); + } else if (t == wxEVT_STC_DWELLSTART || t == wxEVT_STC_DWELLEND) { + scn.nmhdr.code = t == wxEVT_STC_DWELLSTART ? SCN_DWELLSTART : SCN_DWELLEND; + scn.position = B2A(*d, e.GetPosition()); + scn.x = e.GetX(); + scn.y = e.GetY(); + } else if (t == wxEVT_STC_ZOOM) { + scn.nmhdr.code = SCN_ZOOM; + } else if (t == wxEVT_STC_HOTSPOT_CLICK || t == wxEVT_STC_HOTSPOT_DCLICK) { + scn.nmhdr.code = t == wxEVT_STC_HOTSPOT_CLICK ? SCN_HOTSPOTCLICK : SCN_HOTSPOTDOUBLECLICK; + scn.position = B2A(*d, e.GetPosition()); + } else if (t == wxEVT_STC_CALLTIP_CLICK) { + scn.nmhdr.code = SCN_CALLTIPCLICK; + scn.position = e.GetPosition(); + } else if (t == wxEVT_STC_INDICATOR_CLICK || t == wxEVT_STC_INDICATOR_RELEASE) { + scn.nmhdr.code = t == wxEVT_STC_INDICATOR_CLICK ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE; + scn.position = B2A(*d, e.GetPosition()); + } else if (t == wxEVT_STC_AUTOCOMP_CANCELLED) { + scn.nmhdr.code = SCN_AUTOCCANCELLED; + } else { + return; + } + Notify(w, scn); +} + +void BindEvents(wxWindow* w, wxStyledTextCtrl* s) { + s->Bind(wxEVT_STC_MODIFIED, [w](wxStyledTextEvent& e) { OnModified(w, e); }); + s->Bind(wxEVT_STC_STYLENEEDED, [w](wxStyledTextEvent& e) { OnStyleNeeded(w, e); }); + const wxEventTypeTag forwarded[] = { + wxEVT_STC_CHARADDED, wxEVT_STC_SAVEPOINTREACHED, wxEVT_STC_SAVEPOINTLEFT, wxEVT_STC_ROMODIFYATTEMPT, + wxEVT_STC_DOUBLECLICK, wxEVT_STC_UPDATEUI, wxEVT_STC_MACRORECORD, wxEVT_STC_MARGINCLICK, + wxEVT_STC_NEEDSHOWN, wxEVT_STC_PAINTED, wxEVT_STC_USERLISTSELECTION, wxEVT_STC_DWELLSTART, + wxEVT_STC_DWELLEND, wxEVT_STC_ZOOM, wxEVT_STC_HOTSPOT_CLICK, wxEVT_STC_HOTSPOT_DCLICK, + wxEVT_STC_CALLTIP_CLICK, wxEVT_STC_AUTOCOMP_SELECTION, wxEVT_STC_INDICATOR_CLICK, + wxEVT_STC_INDICATOR_RELEASE, wxEVT_STC_AUTOCOMP_CANCELLED, + }; + for (const auto& t : forwarded) + s->Bind(t, [w](wxStyledTextEvent& e) { ForwardEvent(w, e); }); + s->Bind(wxEVT_SET_FOCUS, [w](wxFocusEvent& e) { + e.Skip(); + if (FindData(w) && !w->IsBeingDeleted()) + NotifyParent(w, SCEN_SETFOCUS); + }); + s->Bind(wxEVT_KILL_FOCUS, [w](wxFocusEvent& e) { + e.Skip(); + if (FindData(w) && !w->IsBeingDeleted()) + NotifyParent(w, SCEN_KILLFOCUS); + }); + s->Bind(wxEVT_DESTROY, [w](wxWindowDestroyEvent& e) { + e.Skip(); + if (e.GetWindow() == w) + Registry().erase(w); + }); +} + +SciData* DataFor(wxWindow* w) { + if (SciData* d = FindData(w)) + return d; + auto* s = wxDynamicCast(w, wxStyledTextCtrl); + if (!s) + return nullptr; + std::unique_ptr owned(new SciData()); + SciData* d = owned.get(); + d->stc = s; + Registry()[w] = std::move(owned); + s->SendMsg(SCI_SETCODEPAGE, SC_CP_UTF8); + s->SendMsg(SCI_SETMODEVENTMASK, ControlModMask(d->appModMask)); + s->SendMsg(SCI_SETEOLMODE, SC_EOL_CRLF); + d->map.Reset(); + BindEvents(w, s); + return d; +} + +struct AppRangeToFormat { + void* hdc; + void* hdcTarget; + struct { + int left, top, right, bottom; + } rc, rcPage; + CharacterRange chrg; +}; + +LRESULT GetTextRange(SciData& d, long cpMin, long cpMax, char* out) { + if (!out) + return 0; + int total = d.map.AnsiLength(d.stc); + long end = cpMax == -1 ? total : cpMax; + long len = end - cpMin; + if (len < 0) + return 0; + std::string a = AnsiRange(d, static_cast(std::max(cpMin, 0L)), static_cast(std::min(end, total))); + size_t lead = cpMin < 0 ? static_cast(std::min(-cpMin, len)) : 0; + memset(out, 0, static_cast(len) + 1); + memcpy(out + lead, a.data(), std::min(a.size(), static_cast(len) - lead)); + return static_cast(len); +} + +LRESULT GetStyledText(SciData& d, TextRange* tr) { + if (!tr || !tr->lpstrText) + return 0; + int total = d.map.AnsiLength(d.stc); + int a0 = static_cast(std::max(0L, std::min(tr->chrg.cpMin, total))); + int a1 = static_cast(std::max(a0, std::min(tr->chrg.cpMax, total))); + int b0 = A2B(d, a0); + int b1 = A2B(d, a1); + std::vector cells(static_cast(b1 - b0) * 2 + 2, '\0'); + TextRange utf; + utf.chrg.cpMin = b0; + utf.chrg.cpMax = b1; + utf.lpstrText = cells.data(); + Pass(d, SCI_GETSTYLEDTEXT, 0, reinterpret_cast(&utf)); + std::vector chars(static_cast(b1 - b0)); + for (size_t i = 0; i < chars.size(); ++i) + chars[i] = static_cast(cells[i * 2]); + const Codec& c = CurrentCodec(); + char* out = tr->lpstrText; + int place = 0; + for (size_t i = 0; i < chars.size();) { + int w = chars[i] < 0x80 ? 1 : Utf8Width(&chars[i], chars.size() - i); + char a; + AnsiAt(c, &chars[i], w, a); + out[place++] = a; + out[place++] = cells[i * 2 + 1]; + i += static_cast(w); + } + out[place] = '\0'; + out[place + 1] = '\0'; + return place; +} + +LRESULT AddStyledText(SciData& d, WPARAM length, LPARAM cellsPtr) { + if (!cellsPtr) + return 0; + const char* cells = reinterpret_cast(cellsPtr); + const Codec& c = CurrentCodec(); + std::string out; + size_t n = static_cast(length) / 2; + out.reserve(n * 2 + n); + for (size_t i = 0; i < n; ++i) { + unsigned char ch = static_cast(cells[i * 2]); + char style = cells[i * 2 + 1]; + if (ch < 0x80) { + out.push_back(static_cast(ch)); + out.push_back(style); + continue; + } + for (int k = 0; k < c.encLen[ch]; ++k) { + out.push_back(c.enc[ch][k]); + out.push_back(style); + } + } + return Pass(d, SCI_ADDSTYLEDTEXT, out.size(), reinterpret_cast(out.data())); +} + +template +LRESULT FindTextIn(SciData& d, WPARAM flags, Find* ft) { + if (!ft || !ft->lpstrText) + return -1; + std::string text = Utf8FromAnsi(ft->lpstrText); + TextToFind utf; + utf.chrg.cpMin = A2B(d, static_cast(ft->chrg.cpMin)); + utf.chrg.cpMax = A2B(d, static_cast(ft->chrg.cpMax)); + utf.lpstrText = const_cast(text.c_str()); + utf.chrgText.cpMin = utf.chrgText.cpMax = -1; + LRESULT pos = Pass(d, SCI_FINDTEXT, flags, reinterpret_cast(&utf)); + if (pos < 0) + return pos; + ft->chrgText.cpMin = static_castchrgText.cpMin)>(B2A(d, static_cast(utf.chrgText.cpMin))); + ft->chrgText.cpMax = static_castchrgText.cpMax)>(B2A(d, static_cast(utf.chrgText.cpMax))); + return B2A(d, pos); +} + +wxDC* DCOf(void* hdc) { + if (!hdc) + return nullptr; + CDC* dc = CDC::FromHandle(reinterpret_cast(hdc)); + return dc ? dc->GetWx() : nullptr; +} + +LRESULT FormatRange(SciData& d, bool draw, AppRangeToFormat* fr) { + if (!fr) + return 0; + int total = d.map.AnsiLength(d.stc); + int cpMin = static_cast(std::max(0L, std::min(fr->chrg.cpMin, total))); + int cpMax = fr->chrg.cpMax < 0 || fr->chrg.cpMax > total ? total : static_cast(fr->chrg.cpMax); + wxDC* surface = DCOf(fr->hdc); + if (!surface) + return cpMax; + wxDC* target = DCOf(fr->hdcTarget); + wxRect render(wxPoint(fr->rc.left, fr->rc.top), wxPoint(fr->rc.right, fr->rc.bottom)); + wxRect page(wxPoint(fr->rcPage.left, fr->rcPage.top), wxPoint(fr->rcPage.right, fr->rcPage.bottom)); + int end = d.stc->FormatRange(draw, A2B(d, cpMin), A2B(d, cpMax), surface, target ? target : surface, render, page); + return B2A(d, end); +} + +LRESULT GetCharacterPointer(SciData& d) { + if (!d.mirrorValid) { + d.mirror = AnsiOfBytes(d, 0, d.stc->GetLength()); + d.mirrorValid = true; + } + return reinterpret_cast(d.mirror.c_str()); +} + +sptr_t DirectFunction(sptr_t ptr, unsigned int msg, uptr_t wp, sptr_t lp); + +LRESULT Proc(wxWindow* w, SciData& d, UINT msg, WPARAM wp, LPARAM lp, bool& handled); + +// Win32 edit messages that Scintilla 1.77 (ScintillaWin) maps onto its own messages. +UINT SciFromEM(UINT msg) { + switch (msg) { + case EM_CANPASTE: return SCI_CANPASTE; + case EM_CANUNDO: return SCI_CANUNDO; + case EM_EMPTYUNDOBUFFER: return SCI_EMPTYUNDOBUFFER; + case EM_GETFIRSTVISIBLELINE: return SCI_GETFIRSTVISIBLELINE; + case EM_GETLINECOUNT: return SCI_GETLINECOUNT; + case EM_GETSELTEXT: return SCI_GETSELTEXT; + case EM_HIDESELECTION: return SCI_HIDESELECTION; + case EM_LINEINDEX: return SCI_POSITIONFROMLINE; + case EM_LINESCROLL: return SCI_LINESCROLL; + case EM_REPLACESEL: return SCI_REPLACESEL; + case EM_SCROLLCARET: return SCI_SCROLLCARET; + case EM_SETREADONLY: return SCI_SETREADONLY; + case WM_CLEAR: return SCI_CLEAR; + case WM_COPY: return SCI_COPY; + case WM_CUT: return SCI_CUT; + case WM_SETTEXT: return SCI_SETTEXT; + case WM_GETTEXTLENGTH: return SCI_GETTEXTLENGTH; + case WM_PASTE: return SCI_PASTE; + case WM_UNDO: return SCI_UNDO; + default: return msg; + } +} + +void SetSelectionAnsi(SciData& d, int nStart, int nEnd) { + if (nStart > nEnd) + std::swap(nStart, nEnd); + Pass(d, SCI_SETSEL, PosW(A2B(d, nEnd)), PosL(A2B(d, nStart))); + Pass(d, SCI_SCROLLCARET, 0, 0); +} + +LRESULT EditProc(wxWindow* w, SciData& d, UINT msg, WPARAM wp, LPARAM lp, bool& handled) { + UINT mapped = SciFromEM(msg); + if (mapped != msg) + return Proc(w, d, mapped, wp, lp, handled); + switch (msg) { + case WM_GETTEXT: { + if (!wp || !lp) + return 0; + std::string a = AnsiRange(d, 0, d.map.AnsiLength(d.stc)); + size_t n = std::min(a.size(), static_cast(wp) - 1); + char* out = reinterpret_cast(lp); + memcpy(out, a.data(), n); + out[n] = '\0'; + return static_cast(n); + } + case EM_LINEFROMCHAR: { + int pos = PosArg(wp); + int b = pos < 0 ? static_cast(Pass(d, SCI_GETSELECTIONSTART, 0, 0)) : A2B(d, pos); + return Pass(d, SCI_LINEFROMPOSITION, PosW(b), 0); + } + case EM_EXLINEFROMCHAR: + return Pass(d, SCI_LINEFROMPOSITION, PosW(A2B(d, PosArg(lp))), 0); + case EM_GETSEL: { + int a = B2A(d, static_cast(Pass(d, SCI_GETSELECTIONSTART, 0, 0))); + int b = B2A(d, static_cast(Pass(d, SCI_GETSELECTIONEND, 0, 0))); + if (wp) + *reinterpret_cast(wp) = a; + if (lp) + *reinterpret_cast(lp) = b; + return MAKELONG(a, b); + } + case EM_EXGETSEL: { + if (!lp) + return 0; + auto* cr = reinterpret_cast(lp); + cr->cpMin = B2A(d, static_cast(Pass(d, SCI_GETSELECTIONSTART, 0, 0))); + cr->cpMax = B2A(d, static_cast(Pass(d, SCI_GETSELECTIONEND, 0, 0))); + return 0; + } + case EM_SETSEL: { + int nStart = PosArg(wp); + int nEnd = PosArg(lp); + if (nStart == 0 && nEnd == -1) + nEnd = d.map.AnsiLength(d.stc); + if (nStart == -1) + nStart = nEnd; + SetSelectionAnsi(d, nStart, nEnd); + return 0; + } + case EM_EXSETSEL: { + if (!lp) + return 0; + auto* cr = reinterpret_cast(lp); + int nEnd = cr->cpMin == 0 && cr->cpMax == -1 ? d.map.AnsiLength(d.stc) : static_cast(cr->cpMax); + Pass(d, SCI_SETSEL, PosW(A2B(d, static_cast(cr->cpMin))), PosL(A2B(d, nEnd))); + Pass(d, SCI_SCROLLCARET, 0, 0); + return Pass(d, SCI_LINEFROMPOSITION, static_cast(Pass(d, SCI_GETSELECTIONSTART, 0, 0)), 0); + } + case EM_GETTEXTRANGE: { + auto* tr = reinterpret_cast(lp); + return tr ? GetTextRange(d, tr->chrg.cpMin, tr->chrg.cpMax, tr->lpstrText) : 0; + } + case EM_FINDTEXTEX: + return FindTextIn(d, wp, reinterpret_cast(lp)); + case EM_FORMATRANGE: + return 0; + default: + handled = false; + return 0; + } +} + +LRESULT Proc(wxWindow* w, SciData& d, UINT msg, WPARAM wp, LPARAM lp, bool& handled) { + handled = true; + if (msg < SCI_START) + return EditProc(w, d, msg, wp, lp, handled); + switch (msg) { + case SCI_GETDIRECTFUNCTION: + return reinterpret_cast(&DirectFunction); + case SCI_GETDIRECTPOINTER: + return reinterpret_cast(w); + + case SCI_SETCODEPAGE: + d.appCodePage = static_cast(wp); + return 0; + case SCI_GETCODEPAGE: + return d.appCodePage; + case SCI_SETMODEVENTMASK: + d.appModMask = static_cast(wp); + return Pass(d, msg, static_cast(ControlModMask(d.appModMask)), 0); + case SCI_GETMODEVENTMASK: + return d.appModMask; + case SCI_SETWRAPMODE: + return Pass(d, msg, wp == SC_WRAP_WORD ? static_cast(kWrapWhitespace) : wp, lp); + case SCI_GETWRAPMODE: { + LRESULT r = Pass(d, msg, wp, lp); + return r == kWrapWhitespace ? SC_WRAP_WORD : r; + } + case SCI_SETDOCPOINTER: { + LRESULT r = Pass(d, msg, wp, lp); + Pass(d, SCI_SETCODEPAGE, SC_CP_UTF8, 0); + d.map.Reset(); + d.mirrorValid = false; + return r; + } + + case SCI_GETLENGTH: + case SCI_GETTEXTLENGTH: + return d.map.AnsiLength(d.stc); + case SCI_LINELENGTH: { + LRESULT start = Pass(d, SCI_POSITIONFROMLINE, wp, 0); + LRESULT len = Pass(d, msg, wp, lp); + if (start < 0) + return len; + return B2A(d, static_cast(start + len)) - B2A(d, static_cast(start)); + } + case SCI_GETCHARAT: { + int b = A2B(d, PosArg(wp)); + int n = d.stc->GetLength(); + if (b < 0 || b >= n) + return 0; + const unsigned char* p = reinterpret_cast(d.stc->GetRangePointer(b, std::min(4, n - b))); + char a; + AnsiAt(CurrentCodec(), p, p[0] < 0x80 ? 1 : Utf8Width(p, static_cast(std::min(4, n - b))), a); + return static_cast(a); + } + + case SCI_GOTOPOS: + case SCI_SETANCHOR: + case SCI_SETCURRENTPOS: + case SCI_SETSELECTIONSTART: + case SCI_SETSELECTIONEND: + case SCI_SETTARGETSTART: + case SCI_SETTARGETEND: + case SCI_LINEFROMPOSITION: + case SCI_GETCOLUMN: + case SCI_GETSTYLEAT: + case SCI_BRACEBADLIGHT: + case SCI_INDICATORALLONFOR: + return Pass(d, msg, PosW(A2B(d, PosArg(wp))), lp); + case SCI_BRACEMATCH: + case SCI_POSITIONBEFORE: + case SCI_POSITIONAFTER: + case SCI_WORDSTARTPOSITION: + case SCI_WORDENDPOSITION: + return B2A(d, Pass(d, msg, PosW(A2B(d, PosArg(wp))), lp)); + case SCI_SETSEL: + case SCI_BRACEHIGHLIGHT: + case SCI_COLOURISE: + return Pass(d, msg, PosW(A2B(d, PosArg(wp))), PosL(A2B(d, PosArg(lp)))); + case SCI_COPYRANGE: { + int a = PosArg(wp); + int b = PosArg(lp); + if (a > b) + std::swap(a, b); + RememberCopied(AnsiRange(d, a, b)); + return Pass(d, msg, PosW(A2B(d, PosArg(wp))), PosL(A2B(d, PosArg(lp)))); + } + case SCI_POINTXFROMPOSITION: + case SCI_POINTYFROMPOSITION: + case SCI_INDICATORVALUEAT: + return Pass(d, msg, wp, PosL(A2B(d, PosArg(lp)))); + case SCI_INDICATORSTART: + case SCI_INDICATOREND: + return B2A(d, Pass(d, msg, wp, PosL(A2B(d, PosArg(lp))))); + case SCI_INDICATORFILLRANGE: + case SCI_INDICATORCLEARRANGE: { + int a = PosArg(wp); + int b0 = A2B(d, a); + int b1 = A2B(d, a + PosArg(lp)); + return Pass(d, msg, PosW(b0), PosL(b1 - b0)); + } + + case SCI_GETCURRENTPOS: + case SCI_GETANCHOR: + case SCI_GETSELECTIONSTART: + case SCI_GETSELECTIONEND: + case SCI_GETTARGETSTART: + case SCI_GETTARGETEND: + case SCI_GETENDSTYLED: + case SCI_POSITIONFROMLINE: + case SCI_GETLINEENDPOSITION: + case SCI_GETLINEINDENTPOSITION: + case SCI_POSITIONFROMPOINT: + case SCI_POSITIONFROMPOINTCLOSE: + case SCI_CALLTIPPOSSTART: + case SCI_AUTOCPOSSTART: + case SCI_GETLINESELSTARTPOSITION: + case SCI_GETLINESELENDPOSITION: + case SCI_FINDCOLUMN: + return B2A(d, Pass(d, msg, wp, lp)); + + case SCI_SETTEXT: { + if (!lp) + return 0; + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return Pass(d, msg, 0, Ptr(u)); + } + case SCI_ADDTEXT: + case SCI_APPENDTEXT: + case SCI_COPYTEXT: { + if (!lp || static_cast(wp) < 0) + return 0; + if (msg == SCI_COPYTEXT) + RememberCopied(std::string(reinterpret_cast(lp), static_cast(wp))); + std::string u = Utf8FromAnsi(reinterpret_cast(lp), static_cast(wp)); + return Pass(d, msg, u.size(), Ptr(u)); + } + case SCI_INSERTTEXT: { + if (!lp) + return 0; + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return Pass(d, msg, PosW(A2B(d, PosArg(wp))), Ptr(u)); + } + case SCI_REPLACESEL: { + if (!lp) + return 0; + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return Pass(d, msg, 0, Ptr(u)); + } + case SCI_REPLACETARGET: + case SCI_REPLACETARGETRE: { + if (!lp) + return 0; + const char* t = reinterpret_cast(lp); + std::string u = static_cast(wp) < 0 ? Utf8FromAnsi(t) : Utf8FromAnsi(t, static_cast(wp)); + Pass(d, msg, u.size(), Ptr(u)); + int start = static_cast(Pass(d, SCI_GETTARGETSTART, 0, 0)); + int end = static_cast(Pass(d, SCI_GETTARGETEND, 0, 0)); + return B2A(d, end) - B2A(d, start); + } + case SCI_SEARCHINTARGET: { + if (!lp) + return -1; + const char* t = reinterpret_cast(lp); + std::string u = static_cast(wp) < 0 ? Utf8FromAnsi(t) : Utf8FromAnsi(t, static_cast(wp)); + return B2A(d, Pass(d, msg, u.size(), Ptr(u))); + } + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: { + if (!lp) + return -1; + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return B2A(d, Pass(d, msg, wp, Ptr(u))); + } + case SCI_TEXTWIDTH: + case SCI_STYLESETFONT: + case SCI_SETKEYWORDS: + case SCI_AUTOCSTOPS: + case SCI_AUTOCSELECT: + case SCI_AUTOCSETFILLUPS: + case SCI_USERLISTSHOW: { + if (!lp) + return Pass(d, msg, wp, lp); + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return Pass(d, msg, wp, Ptr(u)); + } + case SCI_CALLTIPSHOW: { + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return Pass(d, msg, PosW(A2B(d, PosArg(wp))), Ptr(u)); + } + case SCI_AUTOCSHOW: { + int caret = static_cast(Pass(d, SCI_GETCURRENTPOS, 0, 0)); + int entered = caret - A2B(d, B2A(d, caret) - PosArg(wp)); + std::string u = Utf8FromAnsi(reinterpret_cast(lp)); + return Pass(d, msg, PosW(entered), Ptr(u)); + } + case SCI_SETWORDCHARS: + case SCI_SETWHITESPACECHARS: { + if (!lp) + return Pass(d, msg, wp, lp); + std::string ascii; + for (const char* p = reinterpret_cast(lp); *p; ++p) + if (static_cast(*p) < 0x80) + ascii.push_back(*p); + return Pass(d, msg, wp, Ptr(ascii)); + } + case SCI_SETLENGTHFORENCODE: + d.lengthForEncode = PosArg(wp); + return Pass(d, msg, wp, lp); + case SCI_ENCODEDFROMUTF8: { + const char* src = reinterpret_cast(wp); + if (!src) + return 0; + size_t n = d.lengthForEncode < 0 ? strlen(src) : static_cast(d.lengthForEncode); + return PutString(AnsiFromUtf8(src, n), lp); + } + + case SCI_GETTEXT: { + int total = d.map.AnsiLength(d.stc); + if (!lp) + return total + 1; + if (!wp) + return 0; + size_t want = static_cast(wp) - 1; + std::string a = AnsiRange(d, 0, static_cast(std::min(want, static_cast(total)))); + char* out = reinterpret_cast(lp); + memcpy(out, a.data(), a.size()); + memset(out + a.size(), 0, want - a.size() + 1); + return static_cast(want); + } + case SCI_GETSELTEXT: { + std::string a = FetchString(d, msg, 0, true); + if (!lp) + return static_cast(a.size()) + 1; + char* out = reinterpret_cast(lp); + memcpy(out, a.data(), a.size()); + out[a.size()] = '\0'; + return a.empty() ? 0 : static_cast(a.size()) + 1; + } + case SCI_GETLINE: { + std::string a = FetchString(d, msg, wp, false); + if (lp) + memcpy(reinterpret_cast(lp), a.data(), a.size()); + return static_cast(a.size()); + } + case SCI_GETCURLINE: { + int caret = static_cast(Pass(d, SCI_GETCURRENTPOS, 0, 0)); + LRESULT line = Pass(d, SCI_LINEFROMPOSITION, PosW(caret), 0); + int start = static_cast(Pass(d, SCI_POSITIONFROMLINE, static_cast(line), 0)); + int end = start + static_cast(Pass(d, SCI_LINELENGTH, static_cast(line), 0)); + std::string a = AnsiOfBytes(d, start, end); + if (!lp) + return static_cast(a.size()) + 1; + int caretInLine = B2A(d, caret) - B2A(d, start); + if (!wp) + return caretInLine; + size_t n = std::min(a.size(), static_cast(wp) - 1); + char* out = reinterpret_cast(lp); + memcpy(out, a.data(), n); + out[n] = '\0'; + return caretInLine; + } + case SCI_STYLEGETFONT: + return PutString(FetchString(d, msg, wp, false), lp); + case SCI_GETTEXTRANGE: { + auto* tr = reinterpret_cast(lp); + return tr ? GetTextRange(d, tr->chrg.cpMin, tr->chrg.cpMax, tr->lpstrText) : 0; + } + case SCI_GETSTYLEDTEXT: + return GetStyledText(d, reinterpret_cast(lp)); + case SCI_GETCHARACTERPOINTER: + return GetCharacterPointer(d); + case SCI_FINDTEXT: + return FindTextIn(d, wp, reinterpret_cast(lp)); + case SCI_FORMATRANGE: + return FormatRange(d, wp != 0, reinterpret_cast(lp)); + + case SCI_STARTSTYLING: + d.stylingAnsi = PosArg(wp); + return Pass(d, msg, PosW(A2B(d, d.stylingAnsi)), lp); + case SCI_SETSTYLING: { + int len = PosArg(wp); + int b0 = A2B(d, d.stylingAnsi); + int b1 = A2B(d, d.stylingAnsi + len); + d.stylingAnsi += len; + return Pass(d, msg, PosW(b1 - b0), lp); + } + case SCI_SETSTYLINGEX: { + int len = PosArg(wp); + if (len <= 0 || !lp) + return 0; + const char* styles = reinterpret_cast(lp); + int b0 = A2B(d, d.stylingAnsi); + int b1 = A2B(d, d.stylingAnsi + len); + int n = d.stc->GetLength(); + int bytes = std::min(b1, n) - b0; + std::vector expanded; + expanded.reserve(static_cast(std::max(bytes, 0))); + if (bytes > 0) { + const unsigned char* p = reinterpret_cast(d.stc->GetRangePointer(b0, bytes)); + for (int i = 0, ch = 0; i < bytes && ch < len; ++ch) { + int width = p[i] < 0x80 ? 1 : Utf8Width(p + i, static_cast(bytes - i)); + expanded.insert(expanded.end(), static_cast(width), styles[ch]); + i += width; + } + } + d.stylingAnsi += len; + return Pass(d, msg, expanded.size(), reinterpret_cast(expanded.data())); + } + case SCI_ADDSTYLEDTEXT: + return AddStyledText(d, wp, lp); + + case SCI_SETLEXER: + d.cryptoolLexer = static_cast(wp) == kCrypToolLexer; + return Pass(d, msg, d.cryptoolLexer ? static_cast(SCLEX_CONTAINER) : wp, lp); + case SCI_GETLEXER: + return d.cryptoolLexer ? kCrypToolLexer : Pass(d, msg, wp, lp); + case SCI_SETLEXERLANGUAGE: { + const char* name = reinterpret_cast(lp); + if (name && strcasecmp(name, "cryptool") == 0) { + d.cryptoolLexer = true; + return Pass(d, SCI_SETLEXER, SCLEX_CONTAINER, 0); + } + d.cryptoolLexer = false; + std::string u = Utf8FromAnsi(name); + return Pass(d, msg, wp, Ptr(u)); + } + case SCI_LOADLEXERLIBRARY: + return 0; + case SCI_SETPROPERTY: { + const char* key = reinterpret_cast(wp); + const char* value = reinterpret_cast(lp); + if (!key) + return 0; + d.props[key] = value ? value : ""; + if (!strcmp(key, "cryptool.alphabet") || !strcmp(key, "cryptool.nonalphabetstyle")) + RebuildAlphabet(d); + std::string k = Utf8FromAnsi(key); + std::string v = Utf8FromAnsi(value); + return Pass(d, msg, reinterpret_cast(k.c_str()), Ptr(v)); + } + case SCI_GETPROPERTY: + case SCI_GETPROPERTYEXPANDED: { + const char* key = reinterpret_cast(wp); + if (!key) + return 0; + auto it = d.props.find(key); + if (msg == SCI_GETPROPERTY && it != d.props.end()) + return PutString(it->second, lp); + std::string k = Utf8FromAnsi(key); + return PutString(FetchString(d, msg, reinterpret_cast(k.c_str()), false), lp); + } + case SCI_GETPROPERTYINT: { + const char* key = reinterpret_cast(wp); + if (!key) + return lp; + std::string k = Utf8FromAnsi(key); + return Pass(d, msg, reinterpret_cast(k.c_str()), lp); + } + + case SCI_COPY: + case SCI_CUT: { + int b0 = static_cast(Pass(d, SCI_GETSELECTIONSTART, 0, 0)); + int b1 = static_cast(Pass(d, SCI_GETSELECTIONEND, 0, 0)); + size_t ansiLen = static_cast(std::max(B2A(d, b1) - B2A(d, b0), 0)); + // SCI_GETSELTEXT replaces NUL bytes, so a stream selection is read from the document + bool rect = Pass(d, SCI_SELECTIONISRECTANGLE, 0, 0) != 0; + RememberCopied(rect ? FetchString(d, SCI_GETSELTEXT, 0, true) : AnsiOfBytes(d, b0, b1), ansiLen); + return Pass(d, msg, wp, lp); + } + + case SCI_PASTE: { + LRESULT r = Pass(d, msg, wp, lp); + NotifyParent(w, SCEN_CHANGE); + return r; + } + + default: + return Pass(d, msg, wp, lp); + } +} + +sptr_t DirectFunction(sptr_t ptr, unsigned int msg, uptr_t wp, sptr_t lp) { + wxWindow* w = reinterpret_cast(ptr); + return OnMain([&]() -> sptr_t { + bool handled = false; + return static_cast(ScintillaWindowProc(w, msg, static_cast(wp), static_cast(lp), handled)); + }); +} + +} // namespace + +void BindScintillaEvents(wxWindow* window) { DataFor(window); } + +LRESULT ScintillaWindowProc(wxWindow* window, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled) { + SciData* d = DataFor(window); + if (!d) { + handled = false; + return 0; + } + return Proc(window, *d, msg, wParam, lParam, handled); +} + +} // namespace mfcwx diff --git a/port/mfcwx/src/snapshot.cpp b/port/mfcwx/src/snapshot.cpp new file mode 100644 index 000000000..886568845 --- /dev/null +++ b/port/mfcwx/src/snapshot.cpp @@ -0,0 +1,94 @@ +#include "windows_impl.h" + +#include +#include +#include +#include +#include + +#include + +namespace mfcwx { + +bool SnapshotWxWindow(wxWindow* w, const std::string& pngPath); + +#ifndef __APPLE__ +bool SnapshotWxWindow(wxWindow* w, const std::string& pngPath) { + if (!w) + return false; + wxClientDC src(w); + wxSize size = w->GetClientSize(); + if (size.x <= 0 || size.y <= 0) + return false; + wxBitmap bmp(size); + wxMemoryDC dst(bmp); + dst.Blit(0, 0, size.x, size.y, &src, 0, 0); + dst.SelectObject(wxNullBitmap); + return bmp.SaveFile(wxString::FromUTF8(pngPath.c_str()), wxBITMAP_TYPE_PNG); +} +#endif + +namespace { + +// Development aid: MFCWX_SNAPSHOT_DIR=dir saves PNGs of all shown top-level windows every +// MFCWX_SNAPSHOT_INTERVAL ms (default 1500) for MFCWX_SNAPSHOT_COUNT rounds (default 1). +// MFCWX_SNAPSHOT_DISMISS=1 cancels the active modal dialog after each round; the process exits +// after the last round. +class SnapshotTimer : public wxTimer { +public: + SnapshotTimer(std::string dir, int rounds, bool dismiss) : m_dir(std::move(dir)), m_rounds(rounds), m_dismiss(dismiss) {} + + void Notify() override { + ++m_round; + int index = 0; + for (wxWindow* w : wxTopLevelWindows) { + if (!w->IsShown()) + continue; + wxString title = w->GetLabel(); + std::string name; + for (wxUniChar c : title) + name += (c.IsAscii() && isalnum(static_cast(c.GetValue()))) ? static_cast(c.GetValue()) : '_'; + char path[1024]; + snprintf(path, sizeof path, "%s/%02d_%d_%s.png", m_dir.c_str(), m_round, index++, name.substr(0, 40).c_str()); + bool ok = SnapshotWxWindow(w, path); + fprintf(stderr, "mfcwx snapshot %s %s (%dx%d)\n", ok ? "saved" : "FAILED", path, w->GetSize().x, w->GetSize().y); + } + if (m_round >= m_rounds) { + fflush(stderr); + _exit(0); + } + if (m_dismiss) { + for (wxWindow* w : wxTopLevelWindows) { + auto* d = wxDynamicCast(w, wxDialog); + if (d && d->IsModal()) { + if (CWnd* wnd = WrapperFor(d)) + wnd->PostMessage(WM_COMMAND, IDCANCEL, 0); + else + d->EndModal(wxID_CANCEL); + break; + } + } + } + } + +private: + std::string m_dir; + int m_rounds; + bool m_dismiss; + int m_round = 0; +}; + +} // namespace + +void StartSnapshotTimerFromEnvironment() { + const char* dir = getenv("MFCWX_SNAPSHOT_DIR"); + if (!dir || !*dir) + return; + const char* interval = getenv("MFCWX_SNAPSHOT_INTERVAL"); + const char* count = getenv("MFCWX_SNAPSHOT_COUNT"); + const char* dismiss = getenv("MFCWX_SNAPSHOT_DISMISS"); + static SnapshotTimer timer(dir, count ? std::max(1, atoi(count)) : 1, dismiss && *dismiss == '1'); + timer.Start(interval ? std::max(100, atoi(interval)) : 1500); +} + +} // namespace mfcwx diff --git a/port/mfcwx/src/snapshot_mac.mm b/port/mfcwx/src/snapshot_mac.mm new file mode 100644 index 000000000..fa4880445 --- /dev/null +++ b/port/mfcwx/src/snapshot_mac.mm @@ -0,0 +1,48 @@ +#import + +#include + +#include + +namespace mfcwx { + +namespace { + +NSView* FindToolbarView(NSView* root) { + if ([NSStringFromClass([root class]) isEqualToString:@"NSToolbarView"]) + return root; + for (NSView* child in root.subviews) + if (NSView* found = FindToolbarView(child)) + return found; + return nil; +} + +bool WritePng(NSView* view, const std::string& path) { + NSBitmapImageRep* rep = [view bitmapImageRepForCachingDisplayInRect:view.bounds]; + if (!rep) + return false; + [view cacheDisplayInRect:view.bounds toBitmapImageRep:rep]; + NSData* png = [rep representationUsingType:NSBitmapImageFileTypePNG properties:@{}]; + return [png writeToFile:[NSString stringWithUTF8String:path.c_str()] atomically:YES]; +} + +} // namespace + +bool SnapshotWxWindow(wxWindow* w, const std::string& pngPath) { + if (!w) + return false; + NSView* view = (NSView*)w->GetHandle(); + NSView* content = [[view window] contentView]; + if (!content) + content = view; + if (!content) + return false; + [content displayIfNeeded]; + if (NSView* toolbar = FindToolbarView(content.superview ? content.superview : content)) { + if (toolbar.bounds.size.height > 0 && pngPath.size() > 4) + WritePng(toolbar, pngPath.substr(0, pngPath.size() - 4) + "_toolbar.png"); + } + return WritePng(content, pngPath); +} + +} // namespace mfcwx diff --git a/port/mfcwx/src/thread.cpp b/port/mfcwx/src/thread.cpp new file mode 100644 index 000000000..f1db24d1d --- /dev/null +++ b/port/mfcwx/src/thread.cpp @@ -0,0 +1,141 @@ +#include "afxwin.h" +#include "runtime.h" + +IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget) + +namespace { + +thread_local CWinThread* t_currentThread = nullptr; + +DWORD RunThread(CWinThread* pThread) { + t_currentThread = pThread; + // Like MFC, a secondary thread sees the application's main window as its own. + CWnd* inherited = nullptr; + if (!pThread->m_pMainWnd) { + CWinApp* app = AfxGetApp(); + if (app && app != pThread && app->m_pMainWnd) + inherited = pThread->m_pMainWnd = app->m_pMainWnd; + } + DWORD code = 0; + bool deleteThread = true; + try { + if (pThread->m_pfnThreadProc) + code = pThread->m_pfnThreadProc(pThread->m_pThreadParams); + else if (!pThread->InitInstance()) + code = static_cast(pThread->ExitInstance()); + else + code = static_cast(pThread->Run()); + } catch (mfcwx::ThreadExit& e) { + code = e.code; + deleteThread = e.deleteThread; + } + t_currentThread = nullptr; + if (deleteThread && pThread->m_bAutoDelete) { + delete pThread; + } else if (inherited && pThread->m_pMainWnd == inherited) { + pThread->m_pMainWnd = nullptr; + } + return code; +} + +CWinThread* StartWinThread(CWinThread* pThread, int nPriority, UINT nStackSize, DWORD dwCreateFlags, + LPSECURITY_ATTRIBUTES lpSecurityAttrs) { + if (!pThread->CreateThread(dwCreateFlags | CREATE_SUSPENDED, nStackSize, lpSecurityAttrs)) { + pThread->m_bAutoDelete = FALSE; + delete pThread; + return nullptr; + } + pThread->SetThreadPriority(nPriority); + if (!(dwCreateFlags & CREATE_SUSPENDED)) + pThread->ResumeThread(); + return pThread; +} + +} // namespace + +CWinThread::CWinThread() + : m_pMainWnd(nullptr), m_pActiveWnd(nullptr), m_bAutoDelete(TRUE), m_hThread(nullptr), m_nThreadID(0), + m_pfnThreadProc(nullptr), m_pThreadParams(nullptr) { + memset(&m_msgCur, 0, sizeof m_msgCur); +} + +CWinThread::CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam) : CWinThread() { + m_pfnThreadProc = pfnThreadProc; + m_pThreadParams = pParam; +} + +CWinThread::~CWinThread() { + if (m_hThread) + CloseHandle(m_hThread); + m_hThread = nullptr; + if (t_currentThread == this) + t_currentThread = nullptr; +} + +BOOL CWinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize, LPSECURITY_ATTRIBUTES) { + if (m_hThread) + return FALSE; + CWinThread* self = this; + DWORD id = 0; + // Start suspended so the members are set before an auto-deleting thread can finish. + HANDLE h = mfcwx::StartThread([self]() { return RunThread(self); }, CREATE_SUSPENDED, nStackSize, &id); + if (!h) + return FALSE; + m_hThread = h; + m_nThreadID = id; + if (!(dwCreateFlags & CREATE_SUSPENDED)) + ::ResumeThread(h); + return TRUE; +} + +int CWinThread::GetThreadPriority() { return ::GetThreadPriority(m_hThread); } + +BOOL CWinThread::SetThreadPriority(int nPriority) { return ::SetThreadPriority(m_hThread, nPriority); } + +DWORD CWinThread::SuspendThread() { return ::SuspendThread(m_hThread); } + +DWORD CWinThread::ResumeThread() { return ::ResumeThread(m_hThread); } + +BOOL CWinThread::PostThreadMessage(UINT, WPARAM, LPARAM) { return FALSE; } + +BOOL CWinThread::InitInstance() { return FALSE; } + +int CWinThread::ExitInstance() { return static_cast(m_msgCur.wParam); } + +int CWinThread::Run() { return ExitInstance(); } + +BOOL CWinThread::PreTranslateMessage(MSG*) { return FALSE; } + +BOOL CWinThread::PumpMessage() { return FALSE; } + +BOOL CWinThread::OnIdle(LONG) { return FALSE; } + +CWnd* CWinThread::GetMainWnd() { return m_pActiveWnd ? m_pActiveWnd : m_pMainWnd; } + +BOOL CWinThread::ProcessMessageFilter(int, LPMSG) { return FALSE; } + +CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority, UINT nStackSize, + DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs) { + return StartWinThread(new CWinThread(pfnThreadProc, pParam), nPriority, nStackSize, dwCreateFlags, + lpSecurityAttrs); +} + +CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass, int nPriority, UINT nStackSize, DWORD dwCreateFlags, + LPSECURITY_ATTRIBUTES lpSecurityAttrs) { + CObject* object = pThreadClass ? pThreadClass->CreateObject() : nullptr; + if (!object) + AfxThrowMemoryException(); + return StartWinThread(static_cast(object), nPriority, nStackSize, dwCreateFlags, lpSecurityAttrs); +} + +void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete) { + if (mfcwx::IsProcessMainThread()) + exit(static_cast(nExitCode)); + throw mfcwx::ThreadExit{nExitCode, bDelete != FALSE}; +} + +CWinThread* AFXAPI AfxGetThread() { + if (t_currentThread) + return t_currentThread; + return mfcwx::IsProcessMainThread() ? AfxGetApp() : nullptr; +} diff --git a/port/mfcwx/src/win32.cpp b/port/mfcwx/src/win32.cpp new file mode 100644 index 000000000..5554694ad --- /dev/null +++ b/port/mfcwx/src/win32.cpp @@ -0,0 +1,1505 @@ +#include +#include +#include +#include + +#include "afx.h" +#include "globalmem.h" +#include "runtime.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#include +#include +#endif + +#undef fopen +#undef rename +#undef remove + +extern char** environ; + +namespace mfcwx { + +extern const uint16_t kCp1250High[128]; +extern const uint16_t kCp1251High[128]; +extern const uint16_t kCp1252High[128]; +extern const uint16_t kCp1253High[128]; +extern const uint16_t kCp1254High[128]; +extern const uint16_t kCp1257High[128]; + +namespace { + +wchar_t UniUpper(wchar_t c) { + if (c < 0x80) + return c >= 'a' && c <= 'z' ? c - 0x20 : c; + if (c >= 0xE0 && c <= 0xFE && c != 0xF7) + return c - 0x20; + if (c == 0xFF) + return 0x178; + if (c == 0x131) + return 'I'; + if ((c >= 0x100 && c <= 0x137) || (c >= 0x14A && c <= 0x177)) + return (c & 1) ? c - 1 : c; + if ((c >= 0x139 && c <= 0x148) || (c >= 0x179 && c <= 0x17E)) + return (c & 1) ? c : c - 1; + if (c == 0x192) + return 0x191; + if ((c >= 0x3B1 && c <= 0x3CB && c != 0x3C2)) + return c - 0x20; + if (c == 0x3C2) + return 0x3A3; + if (c == 0x3AC) + return 0x386; + if (c >= 0x3AD && c <= 0x3AF) + return c - 0x25; + if (c == 0x3CC) + return 0x38C; + if (c == 0x3CD || c == 0x3CE) + return c - 0x3F; + if (c >= 0x430 && c <= 0x44F) + return c - 0x20; + if (c >= 0x450 && c <= 0x45F) + return c - 0x50; + if (c == 0x491) + return 0x490; + return c; +} + +wchar_t UniLower(wchar_t c) { + if (c < 0x80) + return c >= 'A' && c <= 'Z' ? c + 0x20 : c; + if (c >= 0xC0 && c <= 0xDE && c != 0xD7) + return c + 0x20; + if (c == 0x178) + return 0xFF; + if (c == 0x130) + return 'i'; + if ((c >= 0x100 && c <= 0x137) || (c >= 0x14A && c <= 0x177)) + return (c & 1) ? c : c + 1; + if ((c >= 0x139 && c <= 0x148) || (c >= 0x179 && c <= 0x17E)) + return (c & 1) ? c + 1 : c; + if (c == 0x191) + return 0x192; + if (c >= 0x391 && c <= 0x3AB && c != 0x3A2) + return c + 0x20; + if (c == 0x386) + return 0x3AC; + if (c >= 0x388 && c <= 0x38A) + return c + 0x25; + if (c == 0x38C) + return 0x3CC; + if (c == 0x38E || c == 0x38F) + return c + 0x3F; + if (c >= 0x410 && c <= 0x42F) + return c + 0x20; + if (c >= 0x400 && c <= 0x40F) + return c + 0x50; + if (c == 0x490) + return 0x491; + return c; +} + +bool UniIsCaselessLetter(wchar_t c) { + return c == 0xAA || c == 0xB5 || c == 0xBA || c == 0xDF || c == 0x138 || c == 0x149 || c == 0x17F || + c == 0x390 || c == 0x3B0; +} + +const uint16_t* CodePageTable(UINT cp) { + switch (cp) { + case 1250: + return kCp1250High; + case 1251: + return kCp1251High; + case 1252: + return kCp1252High; + case 1253: + return kCp1253High; + case 1254: + return kCp1254High; + case 1257: + return kCp1257High; + default: + return nullptr; + } +} + +UINT EffectiveCodePage(UINT cp) { + if (cp == CP_ACP || cp == CP_OEMCP || cp == 2 || cp == 3) + return static_cast(GetAnsiCodePage()); + return cp; +} + +bool DecodeUtf8(const unsigned char* s, size_t n, std::wstring& out, bool strict) { + for (size_t i = 0; i < n;) { + unsigned char c = s[i]; + uint32_t cp; + size_t len; + if (c < 0x80) { + cp = c; + len = 1; + } else if ((c & 0xE0) == 0xC0) { + cp = c & 0x1F; + len = 2; + } else if ((c & 0xF0) == 0xE0) { + cp = c & 0x0F; + len = 3; + } else if ((c & 0xF8) == 0xF0) { + cp = c & 0x07; + len = 4; + } else { + if (strict) + return false; + out.push_back(0xFFFD); + ++i; + continue; + } + bool ok = i + len <= n; + for (size_t k = 1; ok && k < len; ++k) { + if ((s[i + k] & 0xC0) != 0x80) + ok = false; + else + cp = (cp << 6) | (s[i + k] & 0x3F); + } + if (ok && ((len == 2 && cp < 0x80) || (len == 3 && cp < 0x800) || (len == 4 && cp < 0x10000) || cp > 0x10FFFF || + (cp >= 0xD800 && cp <= 0xDFFF))) + ok = false; + if (!ok) { + if (strict) + return false; + out.push_back(0xFFFD); + ++i; + continue; + } + out.push_back(static_cast(cp)); + i += len; + } + return true; +} + +void EncodeUtf8(uint32_t cp, std::string& out) { + if (cp >= 0xD800 && cp <= 0xDFFF) + cp = 0xFFFD; + if (cp < 0x80) { + out.push_back(static_cast(cp)); + } else if (cp < 0x800) { + out.push_back(static_cast(0xC0 | (cp >> 6))); + out.push_back(static_cast(0x80 | (cp & 0x3F))); + } else if (cp < 0x10000) { + out.push_back(static_cast(0xE0 | (cp >> 12))); + out.push_back(static_cast(0x80 | ((cp >> 6) & 0x3F))); + out.push_back(static_cast(0x80 | (cp & 0x3F))); + } else if (cp <= 0x10FFFF) { + out.push_back(static_cast(0xF0 | (cp >> 18))); + out.push_back(static_cast(0x80 | ((cp >> 12) & 0x3F))); + out.push_back(static_cast(0x80 | ((cp >> 6) & 0x3F))); + out.push_back(static_cast(0x80 | (cp & 0x3F))); + } else { + EncodeUtf8(0xFFFD, out); + } +} + +wxString CodePageCharsetName(UINT cp) { return wxString::Format("windows-%u", cp); } + +bool MultiByteToUnicode(UINT cp, const char* src, size_t n, std::wstring& out, bool strict) { + cp = EffectiveCodePage(cp); + if (cp == CP_UTF8) + return DecodeUtf8(reinterpret_cast(src), n, out, strict); + if (cp == static_cast(GetAnsiCodePage())) { + for (size_t i = 0; i < n; ++i) + out.push_back(AnsiToUnicode(static_cast(src[i]))); + return true; + } + if (const uint16_t* table = CodePageTable(cp)) { + for (size_t i = 0; i < n; ++i) { + unsigned char c = static_cast(src[i]); + out.push_back(c < 0x80 ? c : static_cast(table[c - 0x80])); + } + return true; + } + if (cp == 28591 || cp == 20127) { + for (size_t i = 0; i < n; ++i) { + unsigned char c = static_cast(src[i]); + out.push_back(cp == 20127 && c >= 0x80 ? L'?' : c); + } + return true; + } + wxCSConv conv(CodePageCharsetName(cp)); + if (!conv.IsOk()) + return false; + std::string tmp(src, n); + wxWCharBuffer wide = conv.cMB2WC(tmp.c_str(), n, nullptr); + if (!wide.data()) + return false; + out.append(wide.data()); + return true; +} + +bool UnicodeToMultiByte(UINT cp, const wchar_t* src, size_t n, std::string& out, char defChar, bool& usedDef) { + cp = EffectiveCodePage(cp); + if (cp == CP_UTF8) { + for (size_t i = 0; i < n; ++i) + EncodeUtf8(static_cast(src[i]), out); + return true; + } + const uint16_t* table = CodePageTable(cp); + bool current = cp == static_cast(GetAnsiCodePage()); + if (!table && !current && cp != 28591 && cp != 20127) { + wxCSConv conv(CodePageCharsetName(cp)); + if (!conv.IsOk()) + return false; + for (size_t i = 0; i < n; ++i) { + wchar_t one[2] = {src[i], 0}; + wxCharBuffer mb = conv.cWC2MB(one, 1, nullptr); + if (mb.data() && mb.length() > 0) + out.append(mb.data(), mb.length()); + else { + out.push_back(defChar); + usedDef = true; + } + } + return true; + } + for (size_t i = 0; i < n; ++i) { + wchar_t w = src[i]; + if (static_cast(w) < 0x80) { + out.push_back(static_cast(w)); + continue; + } + char ch = 0; + bool ok = false; + if (current) { + ok = UnicodeToAnsi(w, ch); + } else if (table) { + for (int k = 0; k < 128 && !ok; ++k) + if (table[k] == static_cast(w)) { + ch = static_cast(0x80 + k); + ok = true; + } + } else if (cp == 28591 && static_cast(w) <= 0xFF) { + ch = static_cast(w); + ok = true; + } + if (!ok) { + ch = defChar; + usedDef = true; + } + out.push_back(ch); + } + return true; +} + +const char* SystemMessage(DWORD code) { + switch (code) { + case 0: + return "The operation completed successfully."; + case 1: + return "Incorrect function."; + case 2: + return "The system cannot find the file specified."; + case 3: + return "The system cannot find the path specified."; + case 4: + return "The system cannot open the file."; + case 5: + return "Access is denied."; + case 6: + return "The handle is invalid."; + case 8: + return "Not enough storage is available to process this command."; + case 11: + return "An attempt was made to load a program with an incorrect format."; + case 17: + return "The system cannot move the file to a different disk drive."; + case 18: + return "There are no more files."; + case 19: + return "The media is write protected."; + case 31: + return "A device attached to the system is not functioning."; + case 32: + return "The process cannot access the file because it is being used by another process."; + case 50: + return "The request is not supported."; + case 80: + return "The file exists."; + case 87: + return "The parameter is incorrect."; + case 112: + return "There is not enough space on the disk."; + case 122: + return "The data area passed to a system call is too small."; + case 126: + return "The specified module could not be found."; + case 127: + return "The specified procedure could not be found."; + case 131: + return "An attempt was made to move the file pointer before the beginning of the file."; + case 145: + return "The directory is not empty."; + case 183: + return "Cannot create a file when that file already exists."; + case 193: + return "%1 is not a valid Win32 application."; + case 203: + return "The system could not find the environment option that was entered."; + case 206: + return "The filename or extension is too long."; + case 234: + return "More data is available."; + case 259: + return "No more data is available."; + case 288: + return "Attempt to release mutex not owned by caller."; + case 298: + return "Too many posts were made to a semaphore."; + case 1117: + return "The request could not be performed because of an I/O device error."; + case 1223: + return "The operation was canceled by the user."; + default: + return nullptr; + } +} + +std::string ExpandInserts(const char* tmpl, bool argArray, va_list* args) { + std::string typeSpec[100]; + int maxArg = 0; + for (const char* p = tmpl; *p; ++p) { + if (*p == '%' && p[1] >= '1' && p[1] <= '9') { + int n = p[1] - '0'; + const char* q = p + 2; + if (*q >= '0' && *q <= '9') + n = n * 10 + (*q++ - '0'); + if (*q == '!') { + const char* e = strchr(q + 1, '!'); + if (e) + typeSpec[n] = std::string(q + 1, e); + } + maxArg = std::max(maxArg, n); + } else if (*p == '%' && p[1]) { + ++p; + } + } + const char* strArgs[100] = {}; + long long intArgs[100] = {}; + va_list ap; + if (args && !argArray) + va_copy(ap, *args); + for (int i = 1; i <= maxArg && args; ++i) { + bool isString = typeSpec[i].empty() || typeSpec[i].back() == 's'; + bool isWide = typeSpec[i].find("I64") != std::string::npos || typeSpec[i].find("ll") != std::string::npos; + if (argArray) { + DWORD_PTR v = reinterpret_cast(args)[i - 1]; + if (isString) + strArgs[i] = reinterpret_cast(v); + else + intArgs[i] = static_cast(v); + } else if (isString) { + strArgs[i] = va_arg(ap, const char*); + } else if (isWide) { + intArgs[i] = va_arg(ap, long long); + } else { + intArgs[i] = va_arg(ap, int); + } + } + if (args && !argArray) + va_end(ap); + std::string out; + for (const char* p = tmpl; *p; ++p) { + if (*p != '%') { + out += *p; + continue; + } + char c = p[1]; + if (c >= '1' && c <= '9') { + int n = c - '0'; + const char* q = p + 2; + if (*q >= '0' && *q <= '9') + n = n * 10 + (*q++ - '0'); + if (*q == '!') { + const char* e = strchr(q + 1, '!'); + if (e) + q = e + 1; + } + if (typeSpec[n].empty() || typeSpec[n].back() == 's') { + out += strArgs[n] ? strArgs[n] : ""; + } else { + char fmt[64]; + char buf[128]; + std::string spec = typeSpec[n]; + size_t i64 = spec.find("I64"); + if (i64 != std::string::npos) + spec.replace(i64, 3, "ll"); + snprintf(fmt, sizeof fmt, "%%%s", spec.c_str()); + if (spec.find("ll") != std::string::npos) + snprintf(buf, sizeof buf, fmt, intArgs[n]); + else + snprintf(buf, sizeof buf, fmt, static_cast(intArgs[n])); + out += buf; + } + p = q - 1; + } else if (c == 'n') { + out += "\r\n"; + ++p; + } else if (c == '0') { + break; + } else if (c) { + out += c; + ++p; + } + } + return out; +} + +struct Module { + void* dl; + std::string path; + int refs; +}; + +std::mutex& ModuleLock() { + static std::mutex* m = new std::mutex; + return *m; +} + +std::vector& Modules() { + static auto* v = new std::vector; + return *v; +} + +char g_mainModuleTag; + +std::vector& BuiltinNames() { + static auto* v = new std::vector{"scilexer.dll", "scintilla.dll"}; + return *v; +} + +std::string BaseName(const char* path) { + std::string s = path ? path : ""; + size_t slash = s.find_last_of("\\/"); + return slash == std::string::npos ? s : s.substr(slash + 1); +} + +// Must be called with ModuleLock held. +Module* BuiltinModuleLocked(const char* name) { + std::string base = BaseName(name); + bool known = false; + for (const std::string& b : BuiltinNames()) + known = known || strcasecmp(b.c_str(), base.c_str()) == 0; + if (!known) + return nullptr; + for (Module* m : Modules()) + if (!m->dl && strcasecmp(m->path.c_str(), base.c_str()) == 0) + return m; + auto* m = new Module{nullptr, base, 0}; + Modules().push_back(m); + return m; +} + +Module* FindModuleLocked(HMODULE h) { + for (Module* m : Modules()) + if (reinterpret_cast(m) == h) + return m; + return nullptr; +} + +std::mutex& CommandLineLock() { + static std::mutex* m = new std::mutex; + return *m; +} + +std::string& CommandLineStore() { + static auto* s = new std::string; + return *s; +} + +std::string QuoteArg(const std::string& a) { + if (!a.empty() && a.find_first_of(" \t\"") == std::string::npos) + return a; + std::string out = "\""; + for (char c : a) { + if (c == '"') + out += '\\'; + out += c; + } + return out + "\""; +} + +std::vector ProcessArguments() { + std::vector args; +#ifdef __APPLE__ + int argc = *_NSGetArgc(); + char** argv = *_NSGetArgv(); + for (int i = 0; i < argc; ++i) + args.push_back(argv[i] ? argv[i] : ""); +#else + if (FILE* f = ::fopen("/proc/self/cmdline", "rb")) { + std::string cur; + int c; + while ((c = fgetc(f)) != EOF) { + if (c == 0) { + args.push_back(cur); + cur.clear(); + } else { + cur += static_cast(c); + } + } + if (!cur.empty()) + args.push_back(cur); + fclose(f); + } +#endif + return args; +} + +std::string BuildCommandLine() { + std::vector args = ProcessArguments(); + std::string exe = ExecutablePath(); + std::string line = QuoteArg(AppPath(exe.empty() ? (args.empty() ? "" : args[0].c_str()) : exe.c_str())); + for (size_t i = 1; i < args.size(); ++i) { + struct stat st; + const std::string& a = args[i]; + std::string conv = !a.empty() && a[0] == '/' && stat(a.c_str(), &st) == 0 ? AppPath(a.c_str()) : Utf8ToAnsi(a.c_str()); + line += " " + QuoteArg(conv); + } + return line; +} + +const char* FindEnv(const char* name) { + if (!name) + return nullptr; + if (const char* v = getenv(name)) + return v; + size_t len = strlen(name); + for (char** e = environ; e && *e; ++e) + if (strncasecmp(*e, name, len) == 0 && (*e)[len] == '=') + return *e + len + 1; + return nullptr; +} + +WORD LanguageFromCode(const std::string& code) { + static const struct { + const char* code; + WORD primary; + } kLanguages[] = { + {"ar", 0x01}, {"bg", 0x02}, {"ca", 0x03}, {"zh", 0x04}, {"cs", 0x05}, {"da", 0x06}, {"de", 0x07}, + {"el", 0x08}, {"en", 0x09}, {"es", 0x0a}, {"fi", 0x0b}, {"fr", 0x0c}, {"he", 0x0d}, {"hu", 0x0e}, + {"is", 0x0f}, {"it", 0x10}, {"ja", 0x11}, {"ko", 0x12}, {"nl", 0x13}, {"nb", 0x14}, {"no", 0x14}, + {"pl", 0x15}, {"pt", 0x16}, {"ro", 0x18}, {"ru", 0x19}, {"hr", 0x1a}, {"sr", 0x1a}, {"sk", 0x1b}, + {"sq", 0x1c}, {"sv", 0x1d}, {"th", 0x1e}, {"tr", 0x1f}, {"uk", 0x22}, {"sl", 0x24}, {"et", 0x25}, + {"lv", 0x26}, {"lt", 0x27}, + }; + std::string primary = code.substr(0, code.find_first_of("_-")); + for (const auto& l : kLanguages) + if (primary == l.code) { + WORD sub = SUBLANG_DEFAULT; + std::string region = code.size() > primary.size() + 1 ? code.substr(primary.size() + 1, 2) : ""; + if (primary == "en" && region == "GB") + sub = SUBLANG_ENGLISH_UK; + else if (primary == "de" && region == "CH") + sub = SUBLANG_GERMAN_SWISS; + else if (primary == "sr" && code.find("Latn") != std::string::npos) + sub = SUBLANG_SERBIAN_LATIN; + return static_cast(MAKELANGID(l.primary, sub)); + } + return static_cast(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); +} + +WORD SystemLangId() { + static const WORD id = []() { + int lang = wxLocale::GetSystemLanguage(); + if (lang == wxLANGUAGE_UNKNOWN || lang == wxLANGUAGE_DEFAULT) + return static_cast(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); + wxString name = wxLocale::GetLanguageCanonicalName(lang); + return LanguageFromCode(std::string(name.utf8_str())); + }(); + return id; +} + +thread_local LCID t_threadLocale = 0; +UINT g_errorMode = 0; + +} // namespace + +char AnsiToUpper(char ch) { + wchar_t u = UniUpper(AnsiToUnicode(static_cast(ch))); + char out; + return UnicodeToAnsi(u, out) ? out : ch; +} + +char AnsiToLower(char ch) { + wchar_t u = UniLower(AnsiToUnicode(static_cast(ch))); + char out; + return UnicodeToAnsi(u, out) ? out : ch; +} + +bool AnsiIsAlpha(char ch) { + wchar_t u = AnsiToUnicode(static_cast(ch)); + return UniUpper(u) != u || UniLower(u) != u || UniIsCaselessLetter(u); +} + +bool AnsiIsUpper(char ch) { + wchar_t u = AnsiToUnicode(static_cast(ch)); + return UniLower(u) != u; +} + +bool AnsiIsLower(char ch) { + wchar_t u = AnsiToUnicode(static_cast(ch)); + return UniUpper(u) != u || (UniIsCaselessLetter(u) && u != 0xAA && u != 0xBA); +} + +HGLOBAL GlobalFromData(const void* data, size_t size, UINT flags) { + HGLOBAL h = ::GlobalAlloc(flags | GMEM_ZEROINIT, size); + if (h && data && size) + memcpy(h, data, size); + return h; +} + +bool GlobalIsValid(HGLOBAL h) { return GlobalHeaderOf(h) != nullptr; } + +void RegisterBuiltinModule(const char* baseName) { + if (!baseName || !*baseName) + return; + std::lock_guard lk(ModuleLock()); + for (const std::string& b : BuiltinNames()) + if (strcasecmp(b.c_str(), baseName) == 0) + return; + BuiltinNames().push_back(baseName); +} + +void SetCommandLineOverride(const char* commandLine) { + std::lock_guard lk(CommandLineLock()); + CommandLineStore() = commandLine ? commandLine : ""; +} + +} // namespace mfcwx + +using namespace mfcwx; + +DWORD GetTickCount(void) { return static_cast(GetTickCount64()); } + +ULONGLONG GetTickCount64(void) { + return static_cast( + std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); +} + +BOOL QueryPerformanceCounter(LARGE_INTEGER* c) { + if (!c) + return FALSE; + c->QuadPart = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count() / 100; + return TRUE; +} + +BOOL QueryPerformanceFrequency(LARGE_INTEGER* f) { + if (!f) + return FALSE; + f->QuadPart = 10000000; + return TRUE; +} + +static void FillSystemTime(const struct tm& tm, long nsec, LPSYSTEMTIME st) { + st->wYear = static_cast(tm.tm_year + 1900); + st->wMonth = static_cast(tm.tm_mon + 1); + st->wDayOfWeek = static_cast(tm.tm_wday); + st->wDay = static_cast(tm.tm_mday); + st->wHour = static_cast(tm.tm_hour); + st->wMinute = static_cast(tm.tm_min); + st->wSecond = static_cast(tm.tm_sec > 59 ? 59 : tm.tm_sec); + st->wMilliseconds = static_cast(nsec / 1000000); +} + +void GetSystemTime(LPSYSTEMTIME st) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + struct tm tm; + gmtime_r(&ts.tv_sec, &tm); + FillSystemTime(tm, ts.tv_nsec, st); +} + +void GetLocalTime(LPSYSTEMTIME st) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + struct tm tm; + localtime_r(&ts.tv_sec, &tm); + FillSystemTime(tm, ts.tv_nsec, st); +} + +void GetSystemTimeAsFileTime(LPFILETIME ft) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + *ft = MakeFileTime(ts.tv_sec, ts.tv_nsec); +} + +BOOL SystemTimeToFileTime(const SYSTEMTIME* st, LPFILETIME ft) { + if (!st || !ft || st->wMonth < 1 || st->wMonth > 12 || st->wDay < 1 || st->wDay > 31 || st->wHour > 23 || + st->wMinute > 59 || st->wSecond > 59 || st->wMilliseconds > 999 || st->wYear < 1601 || st->wYear > 30827) { + SetLastError(87); + return FALSE; + } + long long y = st->wYear - (st->wMonth <= 2); + long long era = (y >= 0 ? y : y - 399) / 400; + long long yoe = y - era * 400; + long long doy = (153 * (st->wMonth > 2 ? st->wMonth - 3 : st->wMonth + 9) + 2) / 5 + st->wDay - 1; + long long days = era * 146097 + yoe * 365 + yoe / 4 - yoe / 100 + doy - 719468; + time_t t = static_cast(days * 86400 + st->wHour * 3600 + st->wMinute * 60 + st->wSecond); + *ft = MakeFileTime(t, static_cast(st->wMilliseconds) * 1000000L); + return TRUE; +} + +BOOL FileTimeToSystemTime(const FILETIME* ft, LPSYSTEMTIME st) { + if (!ft || !st) + return FALSE; + LONGLONG ticks = FileTimeTicks(*ft) - kFileTimeUnixEpoch; + LONGLONG sec = ticks >= 0 ? ticks / 10000000LL : -((-ticks + 9999999LL) / 10000000LL); + LONGLONG rem = ticks - sec * 10000000LL; + time_t t = static_cast(sec); + struct tm tm; + if (!gmtime_r(&t, &tm)) + return FALSE; + FillSystemTime(tm, static_cast(rem * 100), st); + return TRUE; +} + +BOOL FileTimeToLocalFileTime(const FILETIME* ft, LPFILETIME lft) { + if (!ft || !lft) + return FALSE; + time_t t = FileTimeToUnix(*ft); + struct tm tm; + localtime_r(&t, &tm); + ULONGLONG v = static_cast(FileTimeTicks(*ft) + static_cast(tm.tm_gmtoff) * 10000000LL); + lft->dwLowDateTime = static_cast(v); + lft->dwHighDateTime = static_cast(v >> 32); + return TRUE; +} + +void GetSystemInfo(LPSYSTEM_INFO si) { + memset(si, 0, sizeof *si); +#if defined(__x86_64__) + si->wProcessorArchitecture = 9; + si->dwProcessorType = 8664; +#elif defined(__aarch64__) + si->wProcessorArchitecture = 12; +#elif defined(__i386__) + si->wProcessorArchitecture = 0; + si->dwProcessorType = 586; +#endif + long page = sysconf(_SC_PAGESIZE); + si->dwPageSize = page > 0 ? static_cast(page) : 4096; + si->lpMinimumApplicationAddress = reinterpret_cast(0x10000); + si->lpMaximumApplicationAddress = reinterpret_cast(static_cast(0x7FFFFFFEFFFFULL)); + unsigned n = std::thread::hardware_concurrency(); + si->dwNumberOfProcessors = n ? n : 1; + si->dwActiveProcessorMask = si->dwNumberOfProcessors >= 64 ? ~static_cast(0) + : (static_cast(1) << si->dwNumberOfProcessors) - 1; + si->dwAllocationGranularity = 65536; +} + +BOOL GetVersionEx(LPOSVERSIONINFO vi) { + if (!vi) + return FALSE; + vi->dwMajorVersion = 5; + vi->dwMinorVersion = 1; + vi->dwBuildNumber = 2600; + vi->dwPlatformId = 2; + strcpy(vi->szCSDVersion, "Service Pack 3"); + return TRUE; +} + +DWORD GetVersion(void) { return 5u | (1u << 8) | (2600u << 16); } + +void GlobalMemoryStatus(LPMEMORYSTATUS ms) { + ULONGLONG total = 0, avail = 0; +#ifdef __APPLE__ + uint64_t mem = 0; + size_t len = sizeof mem; + if (sysctlbyname("hw.memsize", &mem, &len, nullptr, 0) == 0) + total = mem; + vm_statistics64_data_t vm; + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + if (host_statistics64(mach_host_self(), HOST_VM_INFO64, reinterpret_cast(&vm), &count) == KERN_SUCCESS) + avail = (static_cast(vm.free_count) + vm.inactive_count) * static_cast(sysconf(_SC_PAGESIZE)); +#else + long pages = sysconf(_SC_PHYS_PAGES); + long availPages = sysconf(_SC_AVPHYS_PAGES); + long page = sysconf(_SC_PAGESIZE); + if (pages > 0 && page > 0) + total = static_cast(pages) * static_cast(page); + if (availPages > 0 && page > 0) + avail = static_cast(availPages) * static_cast(page); +#endif + if (!total) + total = 4ULL << 30; + if (!avail || avail > total) + avail = total / 2; + memset(ms, 0, sizeof *ms); + ms->dwLength = sizeof *ms; + ms->dwMemoryLoad = static_cast(100 - avail * 100 / total); + ms->dwTotalPhys = static_cast(total); + ms->dwAvailPhys = static_cast(avail); + ms->dwTotalPageFile = static_cast(total * 2); + ms->dwAvailPageFile = static_cast(avail * 2); + ms->dwTotalVirtual = static_cast(0x7FFFFFFEFFFFULL); + ms->dwAvailVirtual = static_cast(0x7FFFFFFEFFFFULL); +} + +DWORD FormatMessageA(DWORD flags, LPCVOID source, DWORD msgId, DWORD, LPSTR buffer, DWORD size, va_list* args) { + std::string tmpl; + if (flags & FORMAT_MESSAGE_FROM_STRING) { + tmpl = source ? static_cast(source) : ""; + } else { + const char* known = SystemMessage(msgId); + if (known) { + tmpl = known; + } else { + const char* text = strerror(static_cast(msgId)); + char buf[64]; + if (!text || strncmp(text, "Unknown error", 13) == 0) { + snprintf(buf, sizeof buf, "Unknown error 0x%08X.", static_cast(msgId)); + text = buf; + } + tmpl = text; + if (!tmpl.empty() && tmpl.back() != '.') + tmpl += '.'; + } + tmpl += "\r\n"; + } + std::string text = (flags & FORMAT_MESSAGE_IGNORE_INSERTS) ? tmpl : ExpandInserts(tmpl.c_str(), (flags & 0x2000) != 0, args); + if (flags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { + if (!buffer) + return 0; + size_t bytes = std::max(text.size() + 1, size); + auto* out = static_cast(LocalAlloc(GMEM_ZEROINIT, bytes)); + if (!out) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + memcpy(out, text.c_str(), text.size() + 1); + *reinterpret_cast(buffer) = out; + return static_cast(text.size()); + } + if (!buffer || size < text.size() + 1) { + SetLastError(122); + return 0; + } + memcpy(buffer, text.c_str(), text.size() + 1); + return static_cast(text.size()); +} + +HLOCAL LocalAlloc(UINT flags, SIZE_T bytes) { return GlobalAlloc(flags, bytes); } + +HLOCAL LocalFree(HLOCAL mem) { return GlobalFree(mem); } + +HGLOBAL GlobalAlloc(UINT flags, SIZE_T bytes) { + size_t total = sizeof(GlobalHeader) + bytes; + void* block = (flags & GMEM_ZEROINIT) ? calloc(1, total) : malloc(total); + if (!block) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return nullptr; + } + auto* header = static_cast(block); + header->magic = kGlobalMagic; + header->flags = flags; + header->size = bytes; + header->lockCount = 0; + header->reserved = 0; + return header + 1; +} + +HGLOBAL GlobalFree(HGLOBAL mem) { + if (!mem) + return nullptr; + GlobalHeader* header = GlobalHeaderOf(mem); + if (!header) { + SetLastError(ERROR_INVALID_HANDLE); + return mem; + } + header->magic = 0; + free(header); + return nullptr; +} + +LPVOID GlobalLock(HGLOBAL mem) { + GlobalHeader* header = GlobalHeaderOf(mem); + if (!header) { + SetLastError(ERROR_INVALID_HANDLE); + return nullptr; + } + ++header->lockCount; + return mem; +} + +BOOL GlobalUnlock(HGLOBAL mem) { + GlobalHeader* header = GlobalHeaderOf(mem); + if (!header) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (header->lockCount > 0) + --header->lockCount; + SetLastError(0); + return header->lockCount > 0; +} + +SIZE_T GlobalSize(HGLOBAL mem) { + GlobalHeader* header = GlobalHeaderOf(mem); + if (!header) { + SetLastError(ERROR_INVALID_HANDLE); + return 0; + } + return header->size; +} + +HGLOBAL GlobalReAlloc(HGLOBAL mem, SIZE_T bytes, UINT flags) { + GlobalHeader* header = GlobalHeaderOf(mem); + if (!header) { + SetLastError(ERROR_INVALID_HANDLE); + return nullptr; + } + if (flags & 0x80) { + header->flags = (header->flags & ~GMEM_MOVEABLE) | (flags & GMEM_MOVEABLE); + return mem; + } + size_t old = header->size; + auto* fresh = static_cast(realloc(header, sizeof(GlobalHeader) + bytes)); + if (!fresh) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return nullptr; + } + if ((flags & GMEM_ZEROINIT) && bytes > old) + memset(reinterpret_cast(fresh + 1) + old, 0, bytes - old); + fresh->size = bytes; + return fresh + 1; +} + +DWORD GetEnvironmentVariableA(LPCSTR name, LPSTR buffer, DWORD size) { + const char* v = FindEnv(name); + if (!v) { + SetLastError(203); + return 0; + } + std::string ansi = Utf8ToAnsi(v); + if (!buffer || size <= ansi.size()) + return static_cast(ansi.size() + 1); + memcpy(buffer, ansi.c_str(), ansi.size() + 1); + return static_cast(ansi.size()); +} + +BOOL SetEnvironmentVariableA(LPCSTR name, LPCSTR value) { + if (!name || !*name || strchr(name, '=')) { + SetLastError(87); + return FALSE; + } + int rc = value ? setenv(name, AnsiToUtf8(value).c_str(), 1) : unsetenv(name); + if (rc != 0) { + SetLastErrorFromErrno(errno); + return FALSE; + } + return TRUE; +} + +DWORD ExpandEnvironmentStringsA(LPCSTR src, LPSTR dst, DWORD size) { + std::string out; + for (const char* p = src ? src : ""; *p;) { + if (*p == '%') { + const char* end = strchr(p + 1, '%'); + if (end && end > p + 1) { + std::string name(p + 1, end); + if (const char* v = FindEnv(name.c_str())) { + out += Utf8ToAnsi(v); + p = end + 1; + continue; + } + } + } + out += *p++; + } + if (dst && size > out.size()) + memcpy(dst, out.c_str(), out.size() + 1); + return static_cast(out.size() + 1); +} + +LPSTR GetCommandLineA(void) { + std::lock_guard lk(CommandLineLock()); + std::string& line = CommandLineStore(); + if (line.empty()) + line = BuildCommandLine(); + return &line[0]; +} + +UINT SetErrorMode(UINT mode) { + UINT previous = g_errorMode; + g_errorMode = mode; + return previous; +} + +void OutputDebugStringA(LPCSTR s) { + if (s) + fputs(s, stderr); +} + +void DebugBreak(void) { fprintf(stderr, "mfcwx: DebugBreak()\n"); } + +BOOL Beep(DWORD, DWORD) { + wxBell(); + return TRUE; +} + +BOOL MessageBeep(UINT) { + wxBell(); + return TRUE; +} + +int MulDiv(int number, int numerator, int denominator) { + if (denominator == 0) + return -1; + long long product = static_cast(number) * numerator; + long long half = (denominator < 0 ? -static_cast(denominator) : denominator) / 2; + bool negative = (product < 0) != (denominator < 0); + long long a = product < 0 ? -product : product; + long long d = denominator < 0 ? -static_cast(denominator) : denominator; + long long q = (a + half) / d; + if (q > INT_MAX) + return -1; + return static_cast(negative ? -q : q); +} + +BOOL IsBadReadPtr(const void* p, UINT_PTR cb) { return !p && cb ? TRUE : FALSE; } + +BOOL IsBadWritePtr(LPVOID p, UINT_PTR cb) { return !p && cb ? TRUE : FALSE; } + +DWORD GetUserDefaultLangID(void) { return SystemLangId(); } + +LCID GetUserDefaultLCID(void) { return MAKELCID(SystemLangId(), 0); } + +LCID GetSystemDefaultLCID(void) { return MAKELCID(SystemLangId(), 0); } + +LCID GetThreadLocale(void) { return t_threadLocale ? t_threadLocale : GetUserDefaultLCID(); } + +BOOL SetThreadLocale(LCID lcid) { + t_threadLocale = lcid; + return TRUE; +} + +UINT GetACP(void) { return static_cast(GetAnsiCodePage()); } + +UINT GetOEMCP(void) { + switch (GetAnsiCodePage()) { + case 1250: + return 852; + case 1251: + return 866; + case 1253: + return 737; + case 1254: + return 857; + case 1257: + return 775; + default: + return 850; + } +} + +int MultiByteToWideChar(UINT cp, DWORD flags, LPCSTR src, int srcLen, LPWSTR dst, int dstLen) { + if (!src || srcLen == 0 || dstLen < 0 || (dstLen > 0 && !dst)) { + SetLastError(87); + return 0; + } + size_t n = srcLen < 0 ? strlen(src) + 1 : static_cast(srcLen); + std::wstring wide; + if (!MultiByteToUnicode(cp, src, n, wide, (flags & 0x8) != 0)) { + SetLastError(EffectiveCodePage(cp) == CP_UTF8 ? 1113 : 87); + return 0; + } + if (dstLen == 0) + return static_cast(wide.size()); + if (wide.size() > static_cast(dstLen)) { + SetLastError(122); + return 0; + } + std::copy(wide.begin(), wide.end(), dst); + return static_cast(wide.size()); +} + +int WideCharToMultiByte(UINT cp, DWORD, LPCWSTR src, int srcLen, LPSTR dst, int dstLen, LPCSTR defChar, LPBOOL usedDef) { + if (!src || srcLen == 0 || dstLen < 0 || (dstLen > 0 && !dst)) { + SetLastError(87); + return 0; + } + size_t n = srcLen < 0 ? wcslen(src) + 1 : static_cast(srcLen); + std::string out; + bool used = false; + if (!UnicodeToMultiByte(cp, src, n, out, defChar ? *defChar : '?', used)) { + SetLastError(87); + return 0; + } + if (usedDef) + *usedDef = used ? TRUE : FALSE; + if (dstLen == 0) + return static_cast(out.size()); + if (out.size() > static_cast(dstLen)) { + SetLastError(122); + return 0; + } + memcpy(dst, out.data(), out.size()); + return static_cast(out.size()); +} + +BOOL GetUserNameA(LPSTR buffer, LPDWORD size) { + std::string name; + if (struct passwd* pw = getpwuid(getuid())) + name = pw->pw_name; + if (name.empty()) { + const char* env = getenv("USER"); + name = env ? env : "user"; + } + name = Utf8ToAnsi(name.c_str()); + if (!size) + return FALSE; + if (!buffer || *size < name.size() + 1) { + *size = static_cast(name.size() + 1); + SetLastError(122); + return FALSE; + } + memcpy(buffer, name.c_str(), name.size() + 1); + *size = static_cast(name.size() + 1); + return TRUE; +} + +BOOL GetComputerNameA(LPSTR buffer, LPDWORD size) { + char host[256] = ""; + gethostname(host, sizeof host - 1); + std::string name(host); + name = name.substr(0, name.find('.')); + if (name.empty()) + name = "localhost"; + if (!size) + return FALSE; + if (!buffer || *size < name.size() + 1) { + *size = static_cast(name.size() + 1); + SetLastError(111); + return FALSE; + } + memcpy(buffer, name.c_str(), name.size() + 1); + *size = static_cast(name.size()); + return TRUE; +} + +HMODULE LoadLibraryA(LPCSTR name) { return LoadLibraryExA(name, nullptr, 0); } + +HMODULE LoadLibraryExA(LPCSTR name, HANDLE, DWORD) { + if (!name || !*name) { + SetLastError(87); + return nullptr; + } + { + std::lock_guard lk(ModuleLock()); + if (Module* m = BuiltinModuleLocked(name)) { + ++m->refs; + return reinterpret_cast(m); + } + } + std::string path = FsPath(name); + void* dl = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); + if (!dl) { + SetLastError(126); + return nullptr; + } + std::lock_guard lk(ModuleLock()); + for (Module* m : Modules()) + if (m->dl == dl) { + ++m->refs; + dlclose(dl); + return reinterpret_cast(m); + } + auto* m = new Module{dl, path, 1}; + Modules().push_back(m); + return reinterpret_cast(m); +} + +BOOL FreeLibrary(HMODULE mod) { + std::lock_guard lk(ModuleLock()); + Module* m = FindModuleLocked(mod); + if (!m) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (!m->dl) { + if (m->refs > 0) + --m->refs; + return TRUE; + } + if (--m->refs == 0) { + dlclose(m->dl); + Modules().erase(std::find(Modules().begin(), Modules().end(), m)); + delete m; + } + return TRUE; +} + +FARPROC GetProcAddress(HMODULE mod, LPCSTR name) { + if (!name || IS_INTRESOURCE(name)) { + SetLastError(127); + return nullptr; + } + void* dl; + { + std::lock_guard lk(ModuleLock()); + Module* m = FindModuleLocked(mod); + if (m && !m->dl) { + SetLastError(127); + return nullptr; + } + dl = m ? m->dl : RTLD_DEFAULT; + } + void* sym = dlsym(dl, name); + if (!sym) { + SetLastError(127); + return nullptr; + } + return reinterpret_cast(sym); +} + +HMODULE GetModuleHandleA(LPCSTR name) { + if (!name) + return reinterpret_cast(&g_mainModuleTag); + std::string wanted = name; + size_t slash = wanted.find_last_of("\\/"); + if (slash != std::string::npos) + wanted = wanted.substr(slash + 1); + std::lock_guard lk(ModuleLock()); + if (Module* m = BuiltinModuleLocked(name)) + return reinterpret_cast(m); + for (Module* m : Modules()) { + size_t s = m->path.rfind('/'); + std::string base = m->path.substr(s == std::string::npos ? 0 : s + 1); + if (strcasecmp(base.c_str(), wanted.c_str()) == 0) + return reinterpret_cast(m); + } + std::string exe = ExecutablePath(); + size_t s = exe.rfind('/'); + std::string exeBase = exe.substr(s == std::string::npos ? 0 : s + 1); + if (strcasecmp(exeBase.c_str(), wanted.c_str()) == 0 || + strcasecmp((exeBase + ".exe").c_str(), wanted.c_str()) == 0) + return reinterpret_cast(&g_mainModuleTag); + SetLastError(126); + return nullptr; +} + +DWORD GetModuleFileNameA(HMODULE mod, LPSTR buffer, DWORD size) { + std::string path; + { + std::lock_guard lk(ModuleLock()); + if (Module* m = FindModuleLocked(mod)) + path = m->dl ? m->path : std::string(); + } + if (path.empty()) + path = ExecutablePath(); + std::string app = AppPath(path.c_str()); + if (!buffer || size == 0) { + SetLastError(122); + return 0; + } + if (app.size() + 1 > size) { + memcpy(buffer, app.c_str(), size - 1); + buffer[size - 1] = 0; + SetLastError(122); + return size; + } + memcpy(buffer, app.c_str(), app.size() + 1); + SetLastError(0); + return static_cast(app.size()); +} + +HINSTANCE ShellExecuteA(HWND, LPCSTR op, LPCSTR file, LPCSTR params, LPCSTR dir, int) { + auto result = [](int v) { return reinterpret_cast(static_cast(v)); }; + if (!file || !*file) + return result(2); + std::string verb = op ? op : ""; + std::transform(verb.begin(), verb.end(), verb.begin(), [](char c) { return static_cast(tolower(c)); }); + if (!verb.empty() && verb != "open" && verb != "explore" && verb != "edit") + return result(31); + std::string f = file; + bool url = f.find("://") != std::string::npos || strncasecmp(f.c_str(), "mailto:", 7) == 0 || + strncasecmp(f.c_str(), "www.", 4) == 0; + if (url) { + std::string target = strncasecmp(f.c_str(), "www.", 4) == 0 ? "http://" + f : f; + return wxLaunchDefaultBrowser(wxString::FromUTF8(AnsiToUtf8(target.c_str()).c_str())) ? result(42) : result(31); + } + bool absolute = f[0] == '\\' || f[0] == '/' || (f.size() > 1 && f[1] == ':'); + bool hasSeparator = f.find_first_of("\\/") != std::string::npos; + std::string native; + struct stat st; + if (!absolute && dir && *dir) { + std::string inDir = FsPath((std::string(dir) + "\\" + f).c_str()); + if (stat(inDir.c_str(), &st) == 0) + native = inDir; + } + if (native.empty()) { + std::string direct = FsPath(f.c_str()); + if (stat(direct.c_str(), &st) == 0) + native = direct; + } + if (native.empty() && f.size() > 4 && strcasecmp(f.c_str() + f.size() - 4, ".exe") == 0) { + std::string stripped = FsPath(f.substr(0, f.size() - 4).c_str()); + if (stat(stripped.c_str(), &st) == 0) + native = stripped; + } + bool runProgram = false; + if (native.empty()) { + if (hasSeparator) + return result(2); + runProgram = true; + } else if (S_ISREG(st.st_mode) && access(native.c_str(), X_OK) == 0) { + size_t slash = native.rfind('/'); + size_t dot = native.rfind('.'); + std::string ext = dot != std::string::npos && (slash == std::string::npos || dot > slash) ? native.substr(dot) : ""; + std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { return static_cast(tolower(c)); }); + runProgram = ext.empty() || ext == ".sh" || ext == ".bin" || ext == ".run" || ext == ".command" || + ext == ".py" || ext == ".pl"; + } + if (runProgram) { + std::string cmd = "\"" + (native.empty() ? f : AppPath(native.c_str())) + "\""; + if (params && *params) + cmd += std::string(" ") + params; + STARTUPINFO si; + memset(&si, 0, sizeof si); + si.cb = sizeof si; + PROCESS_INFORMATION pi; + if (!CreateProcessA(nullptr, &cmd[0], nullptr, nullptr, FALSE, 0, nullptr, dir, &si, &pi)) + return result(GetLastError() == ERROR_PATH_NOT_FOUND ? 3 : 2); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return result(42); + } + return wxLaunchDefaultApplication(wxString::FromUTF8(native.c_str())) ? result(42) : result(31); +} + +int lstrlenA(LPCSTR s) { return s ? static_cast(strlen(s)) : 0; } + +LPSTR lstrcpyA(LPSTR d, LPCSTR s) { + if (!d) + return nullptr; + return strcpy(d, s ? s : ""); +} + +LPSTR lstrcpynA(LPSTR d, LPCSTR s, int n) { + if (!d || n <= 0) + return d; + int i = 0; + for (; s && i < n - 1 && s[i]; ++i) + d[i] = s[i]; + d[i] = 0; + return d; +} + +LPSTR lstrcatA(LPSTR d, LPCSTR s) { + if (!d) + return nullptr; + return strcat(d, s ? s : ""); +} + +static int CompareAnsi(LPCSTR a, LPCSTR b, bool caseSensitive) { + a = a ? a : ""; + b = b ? b : ""; + int tie = 0; + for (;; ++a, ++b) { + unsigned char la = static_cast(AnsiToLower(*a)); + unsigned char lb = static_cast(AnsiToLower(*b)); + wchar_t ua = AnsiToUnicode(la); + wchar_t ub = AnsiToUnicode(lb); + if (ua != ub) + return ua < ub ? -1 : 1; + if (!*a) + break; + if (caseSensitive && !tie && *a != *b) + tie = AnsiIsLower(*a) ? -1 : 1; + } + return tie; +} + +int lstrcmpA(LPCSTR a, LPCSTR b) { return CompareAnsi(a, b, true); } + +int lstrcmpiA(LPCSTR a, LPCSTR b) { return CompareAnsi(a, b, false); } + +int wvsprintfA(LPSTR buf, LPCSTR fmt, va_list args) { + char translated[1024]; + fmt = AfxTranslateFormat(fmt, translated, sizeof translated); + int n = vsnprintf(buf, 1025, fmt ? fmt : "", args); + return n > 1024 ? 1024 : n; +} + +int wsprintfA(LPSTR buf, LPCSTR fmt, ...) { + va_list args; + va_start(args, fmt); + int n = wvsprintfA(buf, fmt, args); + va_end(args); + return n; +} + +LPSTR CharUpperA(LPSTR s) { + if (IS_INTRESOURCE(s)) + return reinterpret_cast(static_cast(static_cast( + AnsiToUpper(static_cast(reinterpret_cast(s)))))); + for (char* p = s; *p; ++p) + *p = AnsiToUpper(*p); + return s; +} + +LPSTR CharLowerA(LPSTR s) { + if (IS_INTRESOURCE(s)) + return reinterpret_cast(static_cast(static_cast( + AnsiToLower(static_cast(reinterpret_cast(s)))))); + for (char* p = s; *p; ++p) + *p = AnsiToLower(*p); + return s; +} + +DWORD CharUpperBuffA(LPSTR s, DWORD len) { + for (DWORD i = 0; s && i < len; ++i) + s[i] = AnsiToUpper(s[i]); + return len; +} + +DWORD CharLowerBuffA(LPSTR s, DWORD len) { + for (DWORD i = 0; s && i < len; ++i) + s[i] = AnsiToLower(s[i]); + return len; +} + +LPSTR CharNextA(LPCSTR s) { return const_cast(s && *s ? s + 1 : s); } + +LPSTR CharPrevA(LPCSTR start, LPCSTR s) { return const_cast(s > start ? s - 1 : start); } + +BOOL IsCharAlphaA(CHAR c) { return AnsiIsAlpha(c) ? TRUE : FALSE; } + +BOOL IsCharAlphaNumericA(CHAR c) { return (AnsiIsAlpha(c) || (c >= '0' && c <= '9')) ? TRUE : FALSE; } + +BOOL IsCharUpperA(CHAR c) { return AnsiIsUpper(c) ? TRUE : FALSE; } + +BOOL IsCharLowerA(CHAR c) { return AnsiIsLower(c) ? TRUE : FALSE; } + +BOOL IsDBCSLeadByte(BYTE) { return FALSE; } + +BOOL OemToCharA(LPCSTR src, LPSTR dst) { + if (!src || !dst) + return FALSE; + if (src != dst) + memmove(dst, src, strlen(src) + 1); + return TRUE; +} + +BOOL CharToOemA(LPCSTR src, LPSTR dst) { return OemToCharA(src, dst); } diff --git a/port/mfcwx/src/winapi.cpp b/port/mfcwx/src/winapi.cpp new file mode 100644 index 000000000..adf0d727a --- /dev/null +++ b/port/mfcwx/src/winapi.cpp @@ -0,0 +1,1748 @@ +#include "globalmem.h" +#include "windows_impl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace mfcwx { + +wxWindow* LogicalParent(wxWindow* w) { + if (!w) + return nullptr; + WindowState* st = GetState(w); + if (st && st->owner) + return ToWx(st->owner); + for (wxWindow* p = w->GetParent(); p; p = p->GetParent()) + if (IsManagedWindow(p)) + return p; + return nullptr; +} + +void DestroyWxWindow(wxWindow* w) { + WindowState* st = GetState(w); + if (st) { + st->destroyNotified = true; + CWnd* p = st->permanent; + st->permanent = nullptr; + if (p) { + p->m_hWnd = nullptr; + p->PostNcDestroy(); + } + } + if (w->IsTopLevel()) + w->Hide(); + w->Destroy(); +} + +namespace { + +const wxCursor* g_requestedCursor = nullptr; +bool g_cursorRequested = false; +const wxCursor* g_currentCursor = nullptr; + +wxWindow* ManagedAncestor(wxWindow* w) { + while (w && !IsManagedWindow(w)) + w = w->GetParent(); + return w; +} + +std::vector ManagedChildren(wxWindow* parent) { + std::vector out; + if (!parent) + return out; + for (wxWindow* c : parent->GetChildren()) + if (IsManagedWindow(c)) + out.push_back(c); + return out; +} + +wxWindow* FindChildById(wxWindow* parent, int id) { + if (!parent) + return nullptr; + for (wxWindow* c : parent->GetChildren()) { + WindowState* st = GetState(c); + if (st && st->winId == id) + return c; + } + for (wxWindow* c : parent->GetChildren()) { + if (IsManagedWindow(c) && !c->IsTopLevel()) + continue; + if (c->IsTopLevel()) + continue; + if (wxWindow* r = FindChildById(c, id)) + return r; + } + return nullptr; +} + +void MarkDefault(HWND hWnd, UINT msg) { + CurrentMessage* cm = GetCurrentMessageSlot(); + if (cm && cm->event && cm->msg.hwnd == hWnd && cm->msg.message == msg) + cm->defaultCalled = true; +} + +bool IsDialogWindow(wxWindow* w) { + WindowState* st = GetState(w); + return st && st->kind == ControlKind::Dialog; +} + +} // namespace + +void ResetCursorRequest() { + g_requestedCursor = nullptr; + g_cursorRequested = true; +} + +const wxCursor* RequestedCursor() { + g_cursorRequested = false; + return g_requestedCursor; +} + +LRESULT DefaultWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + wxWindow* w = ToWx(hWnd); + WindowState* st = GetState(w); + if (!st) + return 0; + bool handled = false; + LRESULT r = ControlWindowProc(w, *st, msg, wParam, lParam, handled); + if (handled) + return r; + switch (msg) { + case WM_SETTEXT: + SetControlText(w, ToWx(reinterpret_cast(lParam))); + return TRUE; + case WM_GETTEXT: { + if (!wParam || !lParam) + return 0; + std::string a = FromWx(GetControlText(w)); + size_t n = std::min(a.size(), static_cast(wParam) - 1); + memcpy(reinterpret_cast(lParam), a.data(), n); + reinterpret_cast(lParam)[n] = 0; + return static_cast(n); + } + case WM_GETTEXTLENGTH: + return static_cast(FromWx(GetControlText(w)).size()); + case WM_SETFONT: { + st->font = reinterpret_cast(wParam); + wxFont f = st->font ? FontFromHandle(st->font) : wxFont(); + if (f.IsOk()) { + w->SetFont(f); + if (st->kind == ControlKind::Static) + SetControlText(w, st->text); + } + if (lParam) + w->Refresh(); + return 0; + } + case WM_GETFONT: + return reinterpret_cast(st->font ? st->font : FontHandleFor(w->GetFont())); + case WM_SETREDRAW: + if (wParam) { + if (w->IsFrozen()) + w->Thaw(); + } else if (!w->IsFrozen()) { + w->Freeze(); + } + st->redraw = wParam != 0; + return 0; + case WM_CLOSE: + if (IsDialogWindow(w)) { + wxWindow* cancel = FindChildById(w, IDCANCEL); + DispatchMessageTo(hWnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED), reinterpret_cast(ToHwnd(cancel))); + } else if (st->permanent) { + st->permanent->DestroyWindow(); + } else { + DestroyWxWindow(w); + } + return 0; + case WM_SETICON: + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) { + auto* icon = reinterpret_cast(lParam); + if (icon && icon->IsOk()) + tlw->SetIcon(*icon); + } + return 0; + case WM_GETICON: + return 0; + case WM_HELP: { + wxWindow* parent = LogicalParent(w); + if (parent && !w->IsTopLevel()) + return DispatchMessageTo(ToHwnd(parent), WM_HELP, wParam, lParam); + return TRUE; + } + case WM_SYSCOMMAND: + switch (wParam & 0xFFF0) { + case SC_CLOSE: + DispatchMessageTo(hWnd, WM_CLOSE, 0, 0); + break; + case SC_MINIMIZE: + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) + tlw->Iconize(); + break; + case SC_MAXIMIZE: + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) + tlw->Maximize(); + break; + case SC_RESTORE: + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) + tlw->Restore(); + break; + default: + break; + } + return 0; + case WM_ERASEBKGND: + MarkDefault(hWnd, msg); + return 1; + case DM_GETDEFID: + return st->defaultButtonId ? MAKELRESULT(st->defaultButtonId, DC_HASDEFID) : 0; + case DM_SETDEFID: { + st->defaultButtonId = static_cast(wParam); + if (auto* b = wxDynamicCast(FindChildById(w, st->defaultButtonId), wxButton)) + b->SetDefault(); + return TRUE; + } + case WM_NEXTDLGCTL: + if (lParam) + ::SetFocus(reinterpret_cast(wParam)); + else + w->Navigate(wParam ? wxNavigationKeyEvent::IsBackward : wxNavigationKeyEvent::IsForward); + return 0; + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOR: + return 0; + case WM_ACTIVATE: + case WM_SETCURSOR: + case WM_MOUSEWHEEL: + default: + MarkDefault(hWnd, msg); + return 0; + } +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// Messages + +LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + if (!hWnd) + return 0; + return OnMain([&]() -> LRESULT { return DispatchMessageTo(hWnd, Msg, wParam, lParam); }); +} + +LRESULT SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return SendMessage(hWnd, Msg, wParam, lParam); } + +BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + if (!hWnd) + return Msg == WM_QUIT ? (PostToMainThread([] { if (wxTheApp) wxTheApp->ExitMainLoop(); }), TRUE) : FALSE; + PostToMainThread([=] { + if (IsManagedWindow(ToWx(hWnd))) + DispatchMessageTo(hWnd, Msg, wParam, lParam); + }); + return TRUE; +} + +BOOL PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return PostMessage(hWnd, Msg, wParam, lParam); } + +BOOL SendNotifyMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + if (IsMainThread()) { + SendMessage(hWnd, Msg, wParam, lParam); + return TRUE; + } + return PostMessage(hWnd, Msg, wParam, lParam); +} + +BOOL PostThreadMessage(DWORD, UINT Msg, WPARAM, LPARAM) { + if (Msg == WM_QUIT) + PostToMainThread([] { if (wxTheApp) wxTheApp->ExitMainLoop(); }); + return TRUE; +} + +void PostQuitMessage(int) { + PostToMainThread([] { + if (wxTheApp) + wxTheApp->ExitMainLoop(); + }); +} + +UINT RegisterWindowMessage(const char* lpString) { + static std::mutex m; + static std::map ids; + std::lock_guard lock(m); + std::string key = lpString ? lpString : ""; + auto it = ids.find(key); + if (it != ids.end()) + return it->second; + UINT id = 0xC000 + static_cast(ids.size()); + ids[key] = id; + return id; +} + +UINT RegisterWindowMessageA(const char* lpString) { return RegisterWindowMessage(lpString); } + +BOOL PeekMessage(LPMSG lpMsg, HWND, UINT, UINT, UINT) { + if (lpMsg) + memset(lpMsg, 0, sizeof *lpMsg); + if (IsMainThread()) { + wxEventLoopBase* loop = wxEventLoopBase::GetActive(); + if (loop && !loop->IsYielding()) + loop->YieldFor(wxEVT_CATEGORY_ALL); + } + return FALSE; +} + +BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT a, UINT b) { + PeekMessage(lpMsg, hWnd, a, b, PM_REMOVE); + wxMilliSleep(10); + return TRUE; +} + +BOOL TranslateMessage(const MSG*) { return FALSE; } + +LRESULT DispatchMessage(const MSG* lpMsg) { + if (!lpMsg || !lpMsg->hwnd) + return 0; + return SendMessage(lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam); +} + +BOOL WaitMessage() { + PeekMessage(nullptr, nullptr, 0, 0, PM_NOREMOVE); + return TRUE; +} + +DWORD MsgWaitForMultipleObjects(DWORD nCount, const HANDLE* pHandles, BOOL fWaitAll, DWORD dwMilliseconds, DWORD) { + DWORD start = GetTickCount(); + for (;;) { + DWORD r = WaitForMultipleObjects(nCount, pHandles, fWaitAll, 0); + if (r != WAIT_TIMEOUT) + return r; + if (IsMainThread()) + return WAIT_OBJECT_0 + nCount; + if (dwMilliseconds != INFINITE && GetTickCount() - start >= dwMilliseconds) + return WAIT_TIMEOUT; + wxMilliSleep(5); + } +} + +LRESULT DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + return OnMain([&]() -> LRESULT { return DefaultWindowProc(hWnd, Msg, wParam, lParam); }); +} + +LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + return lpPrevWndFunc ? lpPrevWndFunc(hWnd, Msg, wParam, lParam) : DefWindowProc(hWnd, Msg, wParam, lParam); +} + +// --------------------------------------------------------------------------------------------- +// Window state + +BOOL IsWindow(HWND hWnd) { + return hWnd && OnMain([&]() -> BOOL { return IsManagedWindow(ToWx(hWnd)); }); +} + +BOOL IsWindowVisible(HWND hWnd) { + return IsWindow(hWnd) && OnMain([&]() -> BOOL { return ToWx(hWnd)->IsShown(); }); +} + +BOOL IsWindowEnabled(HWND hWnd) { + return IsWindow(hWnd) && OnMain([&]() -> BOOL { return ToWx(hWnd)->IsThisEnabled(); }); +} + +BOOL EnableWindow(HWND hWnd, BOOL bEnable) { + if (!IsWindow(hWnd)) + return FALSE; + return OnMain([&]() -> BOOL { + wxWindow* w = ToWx(hWnd); + BOOL wasDisabled = !w->IsThisEnabled(); + w->Enable(bEnable != FALSE); + WindowState* st = GetState(w); + if (st) { + st->style = bEnable ? (st->style & ~WS_DISABLED) : (st->style | WS_DISABLED); + if (st->kind == ControlKind::OwnerDrawButton || st->kind == ControlKind::Generic) + w->Refresh(); + } + return wasDisabled; + }); +} + +BOOL ShowWindow(HWND hWnd, int nCmdShow) { + if (!IsWindow(hWnd)) + return FALSE; + return OnMain([&]() -> BOOL { + wxWindow* w = ToWx(hWnd); + BOOL wasVisible = w->IsShown(); + auto* tlw = wxDynamicCast(w, wxTopLevelWindow); + switch (nCmdShow) { + case SW_HIDE: + w->Hide(); + break; + case SW_MINIMIZE: + case SW_SHOWMINIMIZED: + case SW_SHOWMINNOACTIVE: + case SW_FORCEMINIMIZE: + if (tlw) + tlw->Iconize(); + break; + case SW_MAXIMIZE: + if (tlw) + tlw->Maximize(); + w->Show(); + break; + case SW_RESTORE: + if (tlw) + tlw->Restore(); + w->Show(); + break; + default: + w->Show(); + if (tlw && (nCmdShow == SW_SHOW || nCmdShow == SW_SHOWNORMAL)) + tlw->Raise(); + break; + } + WindowState* st = GetState(w); + if (st) + st->style = w->IsShown() ? (st->style | WS_VISIBLE) : (st->style & ~WS_VISIBLE); + return wasVisible; + }); +} + +BOOL IsIconic(HWND hWnd) { + return IsWindow(hWnd) && OnMain([&]() -> BOOL { + auto* tlw = wxDynamicCast(ToWx(hWnd), wxTopLevelWindow); + return tlw && tlw->IsIconized(); + }); +} + +BOOL IsZoomed(HWND hWnd) { + return IsWindow(hWnd) && OnMain([&]() -> BOOL { + auto* tlw = wxDynamicCast(ToWx(hWnd), wxTopLevelWindow); + return tlw && tlw->IsMaximized(); + }); +} + +BOOL IsChild(HWND hWndParent, HWND hWnd) { + if (!hWndParent || !hWnd) + return FALSE; + return OnMain([&]() -> BOOL { + for (wxWindow* w = ToWx(hWnd); w && !w->IsTopLevel(); w = w->GetParent()) + if (w->GetParent() == ToWx(hWndParent)) + return TRUE; + return FALSE; + }); +} + +HWND GetParent(HWND hWnd) { + if (!IsWindow(hWnd)) + return nullptr; + return OnMain([&]() -> HWND { return ToHwnd(LogicalParent(ToWx(hWnd))); }); +} + +HWND SetParent(HWND hWndChild, HWND hWndNewParent) { + HWND old = GetParent(hWndChild); + if (IsWindow(hWndChild) && IsWindow(hWndNewParent)) + OnMain([&] { ToWx(hWndChild)->Reparent(ToWx(hWndNewParent)); }); + return old; +} + +HWND GetWindow(HWND hWnd, UINT uCmd) { + if (!IsWindow(hWnd)) + return nullptr; + return OnMain([&]() -> HWND { + wxWindow* w = ToWx(hWnd); + if (uCmd == GW_CHILD) { + auto children = ManagedChildren(w); + return children.empty() ? nullptr : ToHwnd(children.front()); + } + if (uCmd == GW_OWNER) + return w->IsTopLevel() ? ToHwnd(ManagedAncestor(w->GetParent())) : nullptr; + auto siblings = ManagedChildren(w->GetParent()); + auto it = std::find(siblings.begin(), siblings.end(), w); + if (it == siblings.end()) + return nullptr; + switch (uCmd) { + case GW_HWNDFIRST: + return ToHwnd(siblings.front()); + case GW_HWNDLAST: + return ToHwnd(siblings.back()); + case GW_HWNDNEXT: + return ++it == siblings.end() ? nullptr : ToHwnd(*it); + case GW_HWNDPREV: + return it == siblings.begin() ? nullptr : ToHwnd(*--it); + default: + return nullptr; + } + }); +} + +HWND GetNextWindow(HWND hWnd, UINT wCmd) { return GetWindow(hWnd, wCmd); } +HWND GetTopWindow(HWND hWnd) { return GetWindow(hWnd, GW_CHILD); } +namespace { + +HWND DesktopHwnd() { return reinterpret_cast(static_cast(-16)); } + +} // namespace + +HWND GetDesktopWindow() { return DesktopHwnd(); } + +HWND GetActiveWindow() { + return OnMain([]() -> HWND { return ToHwnd(ManagedAncestor(wxGetActiveWindow())); }); +} + +HWND SetActiveWindow(HWND hWnd) { + HWND old = GetActiveWindow(); + if (IsWindow(hWnd)) + OnMain([&] { wxGetTopLevelParent(ToWx(hWnd))->Raise(); }); + return old; +} + +HWND GetForegroundWindow() { return GetActiveWindow(); } + +BOOL SetForegroundWindow(HWND hWnd) { + SetActiveWindow(hWnd); + return TRUE; +} + +HWND GetFocus() { + return OnMain([]() -> HWND { return ToHwnd(ManagedAncestor(wxWindow::FindFocus())); }); +} + +HWND SetFocus(HWND hWnd) { + HWND old = GetFocus(); + if (IsWindow(hWnd)) + OnMain([&] { ToWx(hWnd)->SetFocus(); }); + return old; +} + +HWND GetCapture() { + return OnMain([]() -> HWND { return ToHwnd(ManagedAncestor(wxWindow::GetCapture())); }); +} + +HWND SetCapture(HWND hWnd) { + HWND old = GetCapture(); + if (IsWindow(hWnd)) + OnMain([&] { + if (!ToWx(hWnd)->HasCapture()) + ToWx(hWnd)->CaptureMouse(); + }); + return old; +} + +BOOL ReleaseCapture() { + OnMain([] { + if (wxWindow* w = wxWindow::GetCapture()) + w->ReleaseMouse(); + }); + return TRUE; +} + +HWND FindWindow(const char*, const char* lpWindowName) { + if (!lpWindowName) + return nullptr; + return OnMain([&]() -> HWND { + wxString name = ToWx(lpWindowName); + for (wxWindow* w : wxTopLevelWindows) + if (IsManagedWindow(w) && w->GetLabel() == name) + return ToHwnd(w); + return nullptr; + }); +} + +HWND FindWindowA(const char* lpClassName, const char* lpWindowName) { return FindWindow(lpClassName, lpWindowName); } + +HWND WindowFromPoint(POINT Point) { + return OnMain([&]() -> HWND { return ToHwnd(ManagedAncestor(wxFindWindowAtPoint(wxPoint(Point.x, Point.y)))); }); +} + +HWND ChildWindowFromPoint(HWND hWndParent, POINT Point) { + if (!IsWindow(hWndParent)) + return nullptr; + return OnMain([&]() -> HWND { + wxWindow* parent = ToWx(hWndParent); + for (wxWindow* c : ManagedChildren(parent)) + if (c->GetRect().Contains(Point.x, Point.y)) + return ToHwnd(c); + return wxRect(parent->GetClientSize()).Contains(Point.x, Point.y) ? hWndParent : nullptr; + }); +} + +BOOL DestroyWindow(HWND hWnd) { + if (!IsWindow(hWnd)) + return FALSE; + return OnMain([&]() -> BOOL { + CWnd* p = PermanentWnd(ToWx(hWnd)); + if (p) + return p->DestroyWindow(); + DestroyWxWindow(ToWx(hWnd)); + return TRUE; + }); +} + +BOOL CloseWindow(HWND hWnd) { return ShowWindow(hWnd, SW_MINIMIZE); } + +BOOL BringWindowToTop(HWND hWnd) { + if (!IsWindow(hWnd)) + return FALSE; + OnMain([&] { ToWx(hWnd)->Raise(); }); + return TRUE; +} + +BOOL SetWindowText(HWND hWnd, const char* lpString) { + return IsWindow(hWnd) && SendMessage(hWnd, WM_SETTEXT, 0, reinterpret_cast(lpString ? lpString : "")); +} + +BOOL SetWindowTextA(HWND hWnd, const char* lpString) { return SetWindowText(hWnd, lpString); } + +int GetWindowText(HWND hWnd, char* lpString, int nMaxCount) { + if (!lpString || nMaxCount <= 0) + return 0; + lpString[0] = 0; + if (!IsWindow(hWnd)) + return 0; + return static_cast(SendMessage(hWnd, WM_GETTEXT, static_cast(nMaxCount), reinterpret_cast(lpString))); +} + +int GetWindowTextA(HWND hWnd, char* lpString, int nMaxCount) { return GetWindowText(hWnd, lpString, nMaxCount); } + +int GetWindowTextLength(HWND hWnd) { + return IsWindow(hWnd) ? static_cast(SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0)) : 0; +} + +int GetClassName(HWND hWnd, char* lpClassName, int nMaxCount) { + if (!lpClassName || nMaxCount <= 0) + return 0; + const char* name = ""; + if (IsWindow(hWnd)) { + switch (GetState(ToWx(hWnd))->kind) { + case ControlKind::PushButton: case ControlKind::CheckBox: case ControlKind::RadioButton: + case ControlKind::OwnerDrawButton: case ControlKind::GroupBox: name = "Button"; break; + case ControlKind::Edit: name = "Edit"; break; + case ControlKind::RichEdit: name = "RichEdit20A"; break; + case ControlKind::Static: case ControlKind::StaticBitmap: case ControlKind::StaticFrame: name = "Static"; break; + case ControlKind::ComboBox: case ControlKind::ComboList: name = "ComboBox"; break; + case ControlKind::ListBox: name = "ListBox"; break; + case ControlKind::ScrollBar: name = "ScrollBar"; break; + case ControlKind::Progress: name = "msctls_progress32"; break; + case ControlKind::Slider: name = "msctls_trackbar32"; break; + case ControlKind::Spin: name = "msctls_updown32"; break; + case ControlKind::ListView: name = "SysListView32"; break; + case ControlKind::TreeView: name = "SysTreeView32"; break; + case ControlKind::Tab: name = "SysTabControl32"; break; + case ControlKind::Scintilla: name = "Scintilla"; break; + case ControlKind::Dialog: name = "#32770"; break; + default: name = "AfxWnd"; break; + } + } + strncpy(lpClassName, name, static_cast(nMaxCount) - 1); + lpClassName[nMaxCount - 1] = 0; + return static_cast(strlen(lpClassName)); +} + +LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex) { + if (!IsWindow(hWnd)) + return 0; + return OnMain([&]() -> LONG_PTR { + wxWindow* w = ToWx(hWnd); + WindowState* st = GetState(w); + switch (nIndex) { + case GWL_STYLE: + return static_cast(CurrentStyle(w)); + case GWL_EXSTYLE: + return static_cast(st->exStyle); + case GWL_ID: + return st->winId; + case GWL_USERDATA: + return st->userData; + case GWL_HWNDPARENT: + return reinterpret_cast(ToHwnd(LogicalParent(w))); + default: + return 0; + } + }); +} + +LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong) { + if (!IsWindow(hWnd)) + return 0; + return OnMain([&]() -> LONG_PTR { + wxWindow* w = ToWx(hWnd); + WindowState* st = GetState(w); + LONG_PTR old = GetWindowLongPtr(hWnd, nIndex); + switch (nIndex) { + case GWL_STYLE: + ApplyStyle(w, CurrentStyle(w), static_cast(dwNewLong)); + break; + case GWL_EXSTYLE: + st->exStyle = static_cast(dwNewLong); + break; + case GWL_ID: + st->winId = static_cast(dwNewLong); + w->SetId(ToWxId(st->winId)); + break; + case GWL_USERDATA: + st->userData = dwNewLong; + break; + default: + break; + } + return old; + }); +} + +LONG GetWindowLong(HWND hWnd, int nIndex) { return static_cast(GetWindowLongPtr(hWnd, nIndex)); } +LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong) { return static_cast(SetWindowLongPtr(hWnd, nIndex, dwNewLong)); } + +// --------------------------------------------------------------------------------------------- +// Geometry and painting + +namespace { + +void ToRect(const wxRect& r, LPRECT out) { + out->left = r.x; + out->top = r.y; + out->right = r.x + r.width; + out->bottom = r.y + r.height; +} + +} // namespace + +BOOL GetWindowRect(HWND hWnd, LPRECT lpRect) { + if (hWnd == DesktopHwnd() && lpRect) { + OnMain([&] { ToRect(wxRect(wxGetDisplaySize()), lpRect); }); + return TRUE; + } + if (!IsWindow(hWnd) || !lpRect) + return FALSE; + OnMain([&] { ToRect(ToWx(hWnd)->GetScreenRect(), lpRect); }); + return TRUE; +} + +BOOL GetClientRect(HWND hWnd, LPRECT lpRect) { + if (hWnd == DesktopHwnd() && lpRect) { + OnMain([&] { ToRect(wxRect(wxGetDisplaySize()), lpRect); }); + return TRUE; + } + if (!IsWindow(hWnd) || !lpRect) + return FALSE; + OnMain([&] { ToRect(wxRect(ToWx(hWnd)->GetClientSize()), lpRect); }); + return TRUE; +} + +BOOL ClientToScreen(HWND hWnd, LPPOINT lpPoint) { + if (!IsWindow(hWnd) || !lpPoint) + return FALSE; + OnMain([&] { + wxPoint p = ToWx(hWnd)->ClientToScreen(wxPoint(lpPoint->x, lpPoint->y)); + lpPoint->x = p.x; + lpPoint->y = p.y; + }); + return TRUE; +} + +BOOL ScreenToClient(HWND hWnd, LPPOINT lpPoint) { + if (!IsWindow(hWnd) || !lpPoint) + return FALSE; + OnMain([&] { + wxPoint p = ToWx(hWnd)->ScreenToClient(wxPoint(lpPoint->x, lpPoint->y)); + lpPoint->x = p.x; + lpPoint->y = p.y; + }); + return TRUE; +} + +int MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints) { + int dx = 0, dy = 0; + POINT origin = {0, 0}; + if (hWndFrom) { + ClientToScreen(hWndFrom, &origin); + dx += origin.x; + dy += origin.y; + } + if (hWndTo) { + POINT o = {0, 0}; + ClientToScreen(hWndTo, &o); + dx -= o.x; + dy -= o.y; + } + for (UINT i = 0; i < cPoints; ++i) { + lpPoints[i].x += dx; + lpPoints[i].y += dy; + } + return MAKELONG(static_cast(dx), static_cast(dy)); +} + +BOOL MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint) { + if (!IsWindow(hWnd)) + return FALSE; + OnMain([&] { + wxWindow* w = ToWx(hWnd); + w->SetSize(X, Y, nWidth, nHeight, wxSIZE_ALLOW_MINUS_ONE); + if (bRepaint) + w->Refresh(); + }); + return TRUE; +} + +BOOL SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags) { + if (!IsWindow(hWnd)) + return FALSE; + OnMain([&] { + wxWindow* w = ToWx(hWnd); + wxRect r = w->GetRect(); + if (!(uFlags & SWP_NOMOVE)) + r.SetPosition(wxPoint(X, Y)); + if (!(uFlags & SWP_NOSIZE)) + r.SetSize(wxSize(cx, cy)); + if (!(uFlags & (SWP_NOMOVE | SWP_NOSIZE)) || (uFlags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)) + w->SetSize(r, wxSIZE_ALLOW_MINUS_ONE); + if (!(uFlags & SWP_NOZORDER)) { + if (hWndInsertAfter == HWND_TOPMOST || hWndInsertAfter == HWND_NOTOPMOST) { + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) { + long style = tlw->GetWindowStyleFlag(); + tlw->SetWindowStyleFlag(hWndInsertAfter == HWND_TOPMOST ? (style | wxSTAY_ON_TOP) : (style & ~wxSTAY_ON_TOP)); + } + } else if (hWndInsertAfter == HWND_BOTTOM) { + w->Lower(); + } else if (hWndInsertAfter == HWND_TOP) { + w->Raise(); + } + } + if (uFlags & SWP_SHOWWINDOW) + w->Show(); + if (uFlags & SWP_HIDEWINDOW) + w->Hide(); + if (uFlags & SWP_FRAMECHANGED) + w->Refresh(); + }); + return TRUE; +} + +BOOL InvalidateRect(HWND hWnd, const RECT* lpRect, BOOL bErase) { + if (!IsWindow(hWnd)) + return FALSE; + OnMain([&] { + wxWindow* w = ToWx(hWnd); + if (lpRect) { + wxRect r(lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top); + ClearClientDCOverlay(w, &r); + w->RefreshRect(r, bErase != FALSE); + } else { + ClearClientDCOverlay(w); + w->Refresh(bErase != FALSE); + } + if (!w->IsTopLevel()) + ApplyCtlColor(w); + }); + return TRUE; +} + +BOOL ValidateRect(HWND, const RECT*) { return TRUE; } + +BOOL UpdateWindow(HWND hWnd) { + if (!IsWindow(hWnd)) + return FALSE; + OnMain([&] { ToWx(hWnd)->Update(); }); + return TRUE; +} + +BOOL RedrawWindow(HWND hWnd, const RECT* lprcUpdate, HRGN, UINT) { + if (!IsWindow(hWnd)) + return FALSE; + InvalidateRect(hWnd, lprcUpdate, TRUE); + return UpdateWindow(hWnd); +} + +UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc) { + if (!IsWindow(hWnd)) + return 0; + return OnMain([&]() -> UINT_PTR { return StartTimer(ToWx(hWnd), nIDEvent, uElapse, lpTimerFunc); }); +} + +BOOL KillTimer(HWND hWnd, UINT_PTR uIDEvent) { + if (!hWnd) + return FALSE; + return OnMain([&]() -> BOOL { return IsManagedWindow(ToWx(hWnd)) && StopTimer(ToWx(hWnd), uIDEvent); }); +} + +// --------------------------------------------------------------------------------------------- +// Dialog items + +HWND GetDlgItem(HWND hDlg, int nIDDlgItem) { + if (!IsWindow(hDlg)) + return nullptr; + return OnMain([&]() -> HWND { return ToHwnd(FindChildById(ToWx(hDlg), nIDDlgItem)); }); +} + +int GetDlgCtrlID(HWND hWnd) { return static_cast(GetWindowLongPtr(hWnd, GWL_ID)); } + +UINT GetDlgItemInt(HWND hDlg, int nIDDlgItem, BOOL* lpTranslated, BOOL bSigned) { + char buf[64]; + if (lpTranslated) + *lpTranslated = FALSE; + if (!GetDlgItem(hDlg, nIDDlgItem)) + return 0; + GetDlgItemText(hDlg, nIDDlgItem, buf, sizeof buf); + char* end = nullptr; + const char* p = buf; + while (*p == ' ') + ++p; + long long v = bSigned ? strtoll(p, &end, 10) : static_cast(strtoull(p, &end, 10)); + if (end == p || (!bSigned && *p == '-')) + return 0; + while (end && *end == ' ') + ++end; + if (end && *end) + return 0; + if (lpTranslated) + *lpTranslated = TRUE; + return static_cast(v); +} + +BOOL SetDlgItemInt(HWND hDlg, int nIDDlgItem, UINT uValue, BOOL bSigned) { + char buf[32]; + if (bSigned) + snprintf(buf, sizeof buf, "%d", static_cast(uValue)); + else + snprintf(buf, sizeof buf, "%u", uValue); + return SetDlgItemText(hDlg, nIDDlgItem, buf); +} + +UINT GetDlgItemText(HWND hDlg, int nIDDlgItem, char* lpString, int cchMax) { + if (lpString && cchMax > 0) + lpString[0] = 0; + HWND h = GetDlgItem(hDlg, nIDDlgItem); + return h ? static_cast(GetWindowText(h, lpString, cchMax)) : 0; +} + +UINT GetDlgItemTextA(HWND hDlg, int nIDDlgItem, char* lpString, int cchMax) { + return GetDlgItemText(hDlg, nIDDlgItem, lpString, cchMax); +} + +BOOL SetDlgItemText(HWND hDlg, int nIDDlgItem, const char* lpString) { + HWND h = GetDlgItem(hDlg, nIDDlgItem); + return h ? SetWindowText(h, lpString) : FALSE; +} + +BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, const char* lpString) { return SetDlgItemText(hDlg, nIDDlgItem, lpString); } + +BOOL CheckDlgButton(HWND hDlg, int nIDButton, UINT uCheck) { + HWND h = GetDlgItem(hDlg, nIDButton); + if (!h) + return FALSE; + SendMessage(h, BM_SETCHECK, uCheck, 0); + return TRUE; +} + +UINT IsDlgButtonChecked(HWND hDlg, int nIDButton) { + HWND h = GetDlgItem(hDlg, nIDButton); + return h ? static_cast(SendMessage(h, BM_GETCHECK, 0, 0)) : 0; +} + +BOOL CheckRadioButton(HWND hDlg, int nIDFirstButton, int nIDLastButton, int nIDCheckButton) { + for (int id = nIDFirstButton; id <= nIDLastButton; ++id) { + HWND h = GetDlgItem(hDlg, id); + if (h) + SendMessage(h, BM_SETCHECK, id == nIDCheckButton ? BST_CHECKED : BST_UNCHECKED, 0); + } + return TRUE; +} + +LRESULT SendDlgItemMessage(HWND hDlg, int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam) { + HWND h = GetDlgItem(hDlg, nIDDlgItem); + return h ? SendMessage(h, Msg, wParam, lParam) : 0; +} + +BOOL EndDialog(HWND hDlg, INT_PTR nResult) { + CWnd* p = CWnd::FromHandlePermanent(hDlg); + if (p && p->IsKindOf(RUNTIME_CLASS(CDialog))) { + static_cast(p)->EndDialog(static_cast(nResult)); + return TRUE; + } + return FALSE; +} + +namespace { + +HWND NextTabItem(HWND hDlg, HWND hCtl, BOOL bPrevious, bool groupOnly) { + if (!IsWindow(hDlg)) + return nullptr; + return OnMain([&]() -> HWND { + auto children = ManagedChildren(ToWx(hDlg)); + if (children.empty()) + return nullptr; + auto eligible = [&](wxWindow* c) { + WindowState* st = GetState(c); + return c->IsShown() && c->IsEnabled() && st && (groupOnly || (st->style & WS_TABSTOP)); + }; + size_t n = children.size(); + size_t start = 0; + for (size_t i = 0; i < n; ++i) + if (ToHwnd(children[i]) == hCtl) + start = i; + for (size_t k = 1; k <= n; ++k) { + size_t i = bPrevious ? (start + n - k) % n : (start + k) % n; + if (groupOnly) { + WindowState* st = GetState(children[i]); + if (!bPrevious && st && (st->style & WS_GROUP)) + break; + } + if (eligible(children[i])) + return ToHwnd(children[i]); + } + return hCtl; + }); +} + +} // namespace + +HWND GetNextDlgTabItem(HWND hDlg, HWND hCtl, BOOL bPrevious) { return NextTabItem(hDlg, hCtl, bPrevious, false); } +HWND GetNextDlgGroupItem(HWND hDlg, HWND hCtl, BOOL bPrevious) { return NextTabItem(hDlg, hCtl, bPrevious, true); } + +BOOL MapDialogRect(HWND hDlg, LPRECT lpRect) { + if (!IsWindow(hDlg) || !lpRect) + return FALSE; + OnMain([&] { + wxRect r = DialogUnitsToPixels(ToWx(hDlg), lpRect->left, lpRect->top, lpRect->right - lpRect->left, + lpRect->bottom - lpRect->top); + ToRect(r, lpRect); + }); + return TRUE; +} + +LONG GetDialogBaseUnits() { + return OnMain([]() -> LONG { + wxRect r = DialogUnitsToPixels(nullptr, 0, 0, 4, 8); + return MAKELONG(r.width, r.height); + }); +} + +int MessageBox(HWND hWnd, const char* lpText, const char* lpCaption, UINT uType) { + return OnMain([&]() -> int { return ShowMessageBox(hWnd ? ToWx(hWnd) : nullptr, lpText, lpCaption, uType); }); +} + +int MessageBoxA(HWND hWnd, const char* lpText, const char* lpCaption, UINT uType) { + return MessageBox(hWnd, lpText, lpCaption, uType); +} + +BOOL WinHelp(HWND, const char*, UINT uCommand, ULONG_PTR dwData) { + if (CWinApp* app = AfxGetApp()) + app->WinHelp(dwData, uCommand); + return TRUE; +} + +BOOL WinHelpA(HWND hWndMain, const char* lpszHelp, UINT uCommand, ULONG_PTR dwData) { + return WinHelp(hWndMain, lpszHelp, uCommand, dwData); +} + +// --------------------------------------------------------------------------------------------- +// System information, keyboard, cursors, icons + +int GetSystemMetrics(int nIndex) { + return OnMain([&]() -> int { + wxDisplay display(static_cast(0)); + wxRect screen = display.GetGeometry(); + wxRect work = display.GetClientArea(); + switch (nIndex) { + case SM_CXSCREEN: case SM_CXVIRTUALSCREEN: return screen.width; + case SM_CYSCREEN: case SM_CYVIRTUALSCREEN: return screen.height; + case SM_CXFULLSCREEN: case SM_CXMAXIMIZED: return work.width; + case SM_CYFULLSCREEN: case SM_CYMAXIMIZED: return work.height; + case SM_CXVSCROLL: return wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + case SM_CYHSCROLL: return wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y); + case SM_CYVSCROLL: case SM_CXHSCROLL: return 16; + case SM_CYCAPTION: return std::max(20, wxSystemSettings::GetMetric(wxSYS_CAPTION_Y)); + case SM_CYMENU: return std::max(20, wxSystemSettings::GetMetric(wxSYS_MENU_Y)); + case SM_CXBORDER: case SM_CYBORDER: return 1; + case SM_CXEDGE: case SM_CYEDGE: return 2; + case SM_CXDLGFRAME: case SM_CYDLGFRAME: case SM_CXFRAME: case SM_CYFRAME: return 4; + case SM_CXICON: case SM_CYICON: case SM_CXCURSOR: case SM_CYCURSOR: return 32; + case SM_CXSMICON: case SM_CYSMICON: return 16; + case SM_CXDRAG: case SM_CYDRAG: return 4; + case SM_CXMIN: return 112; + case SM_CYMIN: return 27; + default: return 0; + } + }); +} + +BOOL SystemParametersInfo(UINT uiAction, UINT, PVOID pvParam, UINT) { + if (uiAction == SPI_GETWORKAREA && pvParam) { + OnMain([&] { ToRect(wxDisplay(static_cast(0)).GetClientArea(), static_cast(pvParam)); }); + return TRUE; + } + return FALSE; +} + +BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni) { + return SystemParametersInfo(uiAction, uiParam, pvParam, fWinIni); +} + +SHORT GetKeyState(int nVirtKey) { + return OnMain([&]() -> SHORT { + wxMouseState ms = wxGetMouseState(); + bool down = false; + switch (nVirtKey) { + case VK_LBUTTON: down = ms.LeftIsDown(); break; + case VK_RBUTTON: down = ms.RightIsDown(); break; + case VK_MBUTTON: down = ms.MiddleIsDown(); break; + case VK_SHIFT: case VK_LSHIFT: case VK_RSHIFT: down = ms.ShiftDown(); break; + case VK_CONTROL: case VK_LCONTROL: case VK_RCONTROL: down = ms.ControlDown(); break; + case VK_MENU: case VK_LMENU: case VK_RMENU: down = ms.AltDown(); break; + default: { + int key = WxKeyFromVirtual(static_cast(nVirtKey)); + if (key == WXK_CAPITAL || key == WXK_NUMLOCK || key == WXK_SCROLL) + return wxGetKeyState(static_cast(key)) ? 1 : 0; + down = key && wxGetKeyState(static_cast(key)); + break; + } + } + return down ? static_cast(0x8000) : 0; + }); +} + +SHORT GetAsyncKeyState(int vKey) { return GetKeyState(vKey); } + +BOOL GetKeyboardState(BYTE* lpKeyState) { + if (!lpKeyState) + return FALSE; + for (int i = 0; i < 256; ++i) + lpKeyState[i] = (i == VK_SHIFT || i == VK_CONTROL || i == VK_MENU || i == VK_LBUTTON || i == VK_RBUTTON) + ? static_cast((GetKeyState(i) & 0x8000) ? 0x80 : 0) + : 0; + return TRUE; +} + +BOOL GetCursorPos(LPPOINT lpPoint) { + if (!lpPoint) + return FALSE; + OnMain([&] { + wxPoint p = wxGetMousePosition(); + lpPoint->x = p.x; + lpPoint->y = p.y; + }); + return TRUE; +} + +BOOL SetCursorPos(int, int) { return FALSE; } + +namespace { + +wxCursor* StockCursor(int id) { + static std::map cache; + auto it = cache.find(id); + if (it != cache.end()) + return it->second; + wxStockCursor stock = wxCURSOR_ARROW; + switch (id) { + case 32513: stock = wxCURSOR_IBEAM; break; + case 32514: stock = wxCURSOR_WAIT; break; + case 32515: stock = wxCURSOR_CROSS; break; + case 32516: stock = wxCURSOR_POINT_RIGHT; break; + case 32640: case 32646: stock = wxCURSOR_SIZING; break; + case 32642: stock = wxCURSOR_SIZENWSE; break; + case 32643: stock = wxCURSOR_SIZENESW; break; + case 32644: stock = wxCURSOR_SIZEWE; break; + case 32645: stock = wxCURSOR_SIZENS; break; + case 32648: stock = wxCURSOR_NO_ENTRY; break; + case 32649: stock = wxCURSOR_HAND; break; + case 32650: stock = wxCURSOR_ARROWWAIT; break; + case 32651: stock = wxCURSOR_QUESTION_ARROW; break; + default: break; + } + auto* c = new wxCursor(stock); + cache[id] = c; + return c; +} + +wxCursor* ResourceCursor(const ResRef& ref) { + static std::map cache; + std::string key = ref.name.empty() ? std::to_string(ref.id) : ref.name; + auto it = cache.find(key); + if (it != cache.end()) + return it->second; + wxCursor c = LoadCursorResource(ref); + wxCursor* p = c.IsOk() ? new wxCursor(c) : nullptr; + cache[key] = p; + return p; +} + +wxIcon* ResourceIcon(const ResRef& ref) { + static std::map cache; + std::string key = ref.name.empty() ? std::to_string(ref.id) : ref.name; + auto it = cache.find(key); + if (it != cache.end()) + return it->second; + wxIcon icon; + if (ref.name.empty() && ref.id >= 32512 && ref.id <= 32517) { + wxArtID art = wxART_INFORMATION; + if (ref.id == 32513) + art = wxART_ERROR; + else if (ref.id == 32514) + art = wxART_QUESTION; + else if (ref.id == 32515) + art = wxART_WARNING; + icon = wxArtProvider::GetIcon(art, wxART_MESSAGE_BOX); + } else { + icon = LoadIconResource(ref); + } + wxIcon* p = icon.IsOk() ? new wxIcon(icon) : nullptr; + cache[key] = p; + return p; +} + +} // namespace + +HCURSOR SetCursor(HCURSOR hCursor) { + HCURSOR old = reinterpret_cast(const_cast(g_currentCursor)); + auto* c = reinterpret_cast(hCursor); + g_currentCursor = c; + if (g_cursorRequested) { + g_requestedCursor = c; + return old; + } + OnMain([&] { wxSetCursor(c ? *c : wxNullCursor); }); + return old; +} + +HCURSOR GetCursor() { return reinterpret_cast(const_cast(g_currentCursor)); } +int ShowCursor(BOOL bShow) { return bShow ? 0 : -1; } + +HCURSOR LoadCursor(HINSTANCE hInstance, const char* lpCursorName) { + ResRef ref = ResRef::From(lpCursorName); + return OnMain([&]() -> HCURSOR { + if (!hInstance && ref.name.empty()) + return reinterpret_cast(StockCursor(ref.id)); + if (wxCursor* c = ResourceCursor(ref)) + return reinterpret_cast(c); + return ref.name.empty() && ref.id >= 32512 ? reinterpret_cast(StockCursor(ref.id)) : nullptr; + }); +} + +HCURSOR LoadCursorA(HINSTANCE hInstance, const char* lpCursorName) { return LoadCursor(hInstance, lpCursorName); } + +HCURSOR LoadCursorFromFile(const char* lpFileName) { + return OnMain([&]() -> HCURSOR { + wxImage image; + wxLogNull noLog; + if (!image.LoadFile(NativePathWx(lpFileName))) + return nullptr; + return reinterpret_cast(new wxCursor(image)); + }); +} + +HICON LoadIcon(HINSTANCE, const char* lpIconName) { + ResRef ref = ResRef::From(lpIconName); + return OnMain([&]() -> HICON { return reinterpret_cast(ResourceIcon(ref)); }); +} + +HICON LoadIconA(HINSTANCE hInstance, const char* lpIconName) { return LoadIcon(hInstance, lpIconName); } +BOOL DestroyIcon(HICON) { return TRUE; } +BOOL DestroyCursor(HCURSOR) { return TRUE; } + +HANDLE LoadImage(HINSTANCE hInst, const char* name, UINT type, int cx, int cy, UINT fuLoad) { + return OnMain([&]() -> HANDLE { + if (fuLoad & LR_LOADFROMFILE) { + wxImage image; + wxLogNull noLog; + if (!image.LoadFile(NativePathWx(name))) + return nullptr; + if (cx > 0 && cy > 0) + image.Rescale(cx, cy, wxIMAGE_QUALITY_HIGH); + if (type == IMAGE_BITMAP) + return CreateBitmapHandle(wxBitmap(image)); + if (type == IMAGE_CURSOR) + return new wxCursor(image); + wxIcon icon; + icon.CopyFromBitmap(wxBitmap(image)); + return new wxIcon(icon); + } + ResRef ref = ResRef::From(name); + if (type == IMAGE_BITMAP) { + wxBitmap bmp = LoadBitmapResource(ref); + if (!bmp.IsOk()) + return nullptr; + if (cx > 0 && cy > 0 && (bmp.GetWidth() != cx || bmp.GetHeight() != cy)) + bmp = wxBitmap(bmp.ConvertToImage().Rescale(cx, cy, wxIMAGE_QUALITY_HIGH)); + return CreateBitmapHandle(bmp); + } + if (type == IMAGE_CURSOR) + return LoadCursor(hInst, name); + return LoadIcon(hInst, name); + }); +} + +HANDLE LoadImageA(HINSTANCE hInst, const char* name, UINT type, int cx, int cy, UINT fuLoad) { + return LoadImage(hInst, name, type, cx, cy, fuLoad); +} + +HBITMAP LoadBitmap(HINSTANCE, const char* lpBitmapName) { + ResRef ref = ResRef::From(lpBitmapName); + return OnMain([&]() -> HBITMAP { + wxBitmap bmp = LoadBitmapResource(ref); + return bmp.IsOk() ? CreateBitmapHandle(bmp) : nullptr; + }); +} + +HBITMAP LoadBitmapA(HINSTANCE hInstance, const char* lpBitmapName) { return LoadBitmap(hInstance, lpBitmapName); } + +HACCEL LoadAccelerators(HINSTANCE, const char* lpTableName) { + const rc::AccelTable* t = FindAccelTable(ResRef::From(lpTableName)); + return reinterpret_cast(const_cast(t)); +} + +int TranslateAccelerator(HWND, HACCEL, LPMSG) { return 0; } + +// --------------------------------------------------------------------------------------------- +// Clipboard + +namespace { + +struct ClipboardState { + bool open = false; + bool emptied = false; + std::vector owned; + std::map formats; + std::string remembered; + size_t rememberedMin = 0; + bool hasRemembered = false; +}; + +ClipboardState& Clip() { + static ClipboardState s; + return s; +} + +std::string FormatName(UINT format) { + for (auto& f : Clip().formats) + if (f.second == format) + return f.first; + return "CrypTool.Format." + std::to_string(format); +} + +void ForgetClipboardText() { + Clip().remembered.clear(); + Clip().rememberedMin = 0; + Clip().hasRemembered = false; +} + +// What wxStyledTextCtrl puts on the clipboard: NUL becomes a space and every line ending becomes LF. +wxString NormalizeCopiedText(const wxString& s) { + wxString out; + bool afterCr = false; + for (wxString::const_iterator it = s.begin(); it != s.end(); ++it) { + wxUniChar c = *it; + if (c == '\n' && afterCr) { + afterCr = false; + continue; + } + afterCr = c == '\r'; + out += c == '\r' ? wxUniChar('\n') : (c == wxUniChar(0) ? wxUniChar(' ') : c); + } + return out; +} + +bool RememberedMatches(const wxString& clipboardText) { + const ClipboardState& c = Clip(); + return c.hasRemembered && + NormalizeCopiedText(ToWx(c.remembered.data(), static_cast(c.remembered.size()))) == + NormalizeCopiedText(clipboardText); +} + +} // namespace + +void mfcwx::RememberClipboardText(std::string ansiBytes, size_t minSize) { + OnMain([&]() { + Clip().remembered = std::move(ansiBytes); + Clip().rememberedMin = minSize; + Clip().hasRemembered = true; + }); +} + +BOOL OpenClipboard(HWND) { + return OnMain([]() -> BOOL { + if (Clip().open) + return FALSE; + if (!wxTheClipboard->Open()) + return FALSE; + Clip().open = true; + Clip().emptied = false; + return TRUE; + }); +} + +BOOL CloseClipboard() { + return OnMain([]() -> BOOL { + if (!Clip().open) + return FALSE; + wxTheClipboard->Flush(); + wxTheClipboard->Close(); + Clip().open = false; + for (HGLOBAL h : Clip().owned) + GlobalFree(h); + Clip().owned.clear(); + return TRUE; + }); +} + +BOOL EmptyClipboard() { + return OnMain([]() -> BOOL { + if (!Clip().open) + return FALSE; + wxTheClipboard->Clear(); + ForgetClipboardText(); + Clip().emptied = true; + return TRUE; + }); +} + +HANDLE SetClipboardData(UINT uFormat, HANDLE hMem) { + return OnMain([&]() -> HANDLE { + if (!Clip().open || !hMem) + return nullptr; + const char* data = static_cast(GlobalData(hMem)); + size_t size = GlobalDataSize(hMem); + if (!data) + return nullptr; + if (uFormat == CF_TEXT || uFormat == CF_OEMTEXT) { + ForgetClipboardText(); + size_t len = strnlen(data, size); + wxString text = ToWx(data, static_cast(len)); + text.Replace("\r\n", "\n"); + wxTheClipboard->AddData(new wxTextDataObject(text)); + } else { + auto* obj = new wxCustomDataObject(wxDataFormat(wxString::FromUTF8(FormatName(uFormat)))); + obj->SetData(size, data); + wxTheClipboard->AddData(obj); + } + Clip().owned.push_back(hMem); + return hMem; + }); +} + +HANDLE GetClipboardData(UINT uFormat) { + return OnMain([&]() -> HANDLE { + if (!Clip().open) + return nullptr; + if (uFormat == CF_TEXT || uFormat == CF_OEMTEXT || uFormat == CF_UNICODETEXT) { + if (!wxTheClipboard->IsSupported(wxDF_UNICODETEXT) && !wxTheClipboard->IsSupported(wxDF_TEXT)) + return nullptr; + wxTextDataObject obj; + if (!wxTheClipboard->GetData(obj)) + return nullptr; + wxString text = obj.GetText(); + if (uFormat != CF_UNICODETEXT && RememberedMatches(text)) { + std::string a = Clip().remembered; + a.resize(std::max(a.size(), Clip().rememberedMin) + 1, '\0'); + HGLOBAL h = GlobalFromData(a.data(), a.size()); + Clip().owned.push_back(h); + return h; + } + text.Replace("\r\n", "\n"); + text.Replace("\n", "\r\n"); + std::string a = FromWx(text); + HGLOBAL h = GlobalFromData(a.c_str(), a.size() + 1); + Clip().owned.push_back(h); + return h; + } + wxDataFormat fmt(wxString::FromUTF8(FormatName(uFormat))); + if (!wxTheClipboard->IsSupported(fmt)) + return nullptr; + wxCustomDataObject obj(fmt); + if (!wxTheClipboard->GetData(obj)) + return nullptr; + HGLOBAL h = GlobalFromData(obj.GetData(), obj.GetSize()); + Clip().owned.push_back(h); + return h; + }); +} + +BOOL IsClipboardFormatAvailable(UINT format) { + return OnMain([&]() -> BOOL { + bool opened = false; + if (!Clip().open) { + if (!wxTheClipboard->Open()) + return FALSE; + opened = true; + } + bool r; + if (format == CF_TEXT || format == CF_OEMTEXT || format == CF_UNICODETEXT) + r = wxTheClipboard->IsSupported(wxDF_UNICODETEXT) || wxTheClipboard->IsSupported(wxDF_TEXT); + else + r = wxTheClipboard->IsSupported(wxDataFormat(wxString::FromUTF8(FormatName(format)))); + if (opened) + wxTheClipboard->Close(); + return r; + }); +} + +UINT RegisterClipboardFormat(const char* lpszFormat) { + std::string name = lpszFormat ? lpszFormat : ""; + auto it = Clip().formats.find(name); + if (it != Clip().formats.end()) + return it->second; + UINT id = 0xC100 + static_cast(Clip().formats.size()); + Clip().formats[name] = id; + return id; +} + +UINT RegisterClipboardFormatA(const char* lpszFormat) { return RegisterClipboardFormat(lpszFormat); } + +// --------------------------------------------------------------------------------------------- +// Drag and drop of files + +namespace { + +struct DropList { + std::vector files; +}; + +} // namespace + +UINT DragQueryFile(HDROP hDrop, UINT iFile, char* lpszFile, UINT cch) { + auto* list = reinterpret_cast(hDrop); + if (!list) + return 0; + if (iFile == 0xFFFFFFFF) + return static_cast(list->files.size()); + if (iFile >= list->files.size()) + return 0; + const std::string& f = list->files[iFile]; + if (!lpszFile) + return static_cast(f.size()); + size_t n = std::min(f.size(), cch ? cch - 1 : 0); + memcpy(lpszFile, f.data(), n); + if (cch) + lpszFile[n] = 0; + return static_cast(n); +} + +UINT DragQueryFileA(HDROP hDrop, UINT iFile, char* lpszFile, UINT cch) { return DragQueryFile(hDrop, iFile, lpszFile, cch); } + +void DragFinish(HDROP hDrop) { delete reinterpret_cast(hDrop); } + +void DragAcceptFiles(HWND hWnd, BOOL fAccept) { + if (!IsWindow(hWnd)) + return; + OnMain([&] { + wxWindow* w = ToWx(hWnd); + w->DragAcceptFiles(fAccept != FALSE); + WindowState* st = GetState(w); + if (!fAccept || !st || st->dropBound) + return; + st->dropBound = true; + w->Bind(wxEVT_DROP_FILES, [w](wxDropFilesEvent& e) { + auto* list = new DropList; + for (int i = 0; i < e.GetNumberOfFiles(); ++i) + list->files.push_back(AppPath(e.GetFiles()[i].utf8_str())); + DispatchMessageTo(ToHwnd(w), WM_DROPFILES, reinterpret_cast(list), 0); + }); + }); +} + +// --------------------------------------------------------------------------------------------- +// Window classes, carets, locale, common dialogs + +namespace { + +std::map& Classes() { + static std::map classes; + return classes; +} + +} // namespace + +LONG GetClassLong(HWND, int) { return 0; } + +LONG SetClassLong(HWND hWnd, int nIndex, LONG dwNewLong) { + return static_cast(SetClassLongPtr(hWnd, nIndex, dwNewLong)); +} + +ULONG_PTR SetClassLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong) { + if (nIndex == GCL_HCURSOR && IsWindow(hWnd)) { + auto* c = reinterpret_cast(dwNewLong); + OnMain([&] { ToWx(hWnd)->SetCursor(c ? *c : wxNullCursor); }); + } + return 0; +} + +BOOL GetClassInfo(HINSTANCE, const char* lpClassName, WNDCLASS* lpWndClass) { + if (!lpWndClass) + return FALSE; + auto it = Classes().find(lpClassName && !IS_INTRESOURCE(lpClassName) ? lpClassName : ""); + if (it == Classes().end()) + return FALSE; + *lpWndClass = it->second; + return TRUE; +} + +ATOM RegisterClass(const WNDCLASS* lpWndClass) { + if (!lpWndClass || !lpWndClass->lpszClassName) + return 0; + Classes()[lpWndClass->lpszClassName] = *lpWndClass; + return static_cast(Classes().size()); +} + +BOOL UnregisterClass(const char* lpClassName, HINSTANCE) { + return lpClassName && Classes().erase(lpClassName) ? TRUE : FALSE; +} + +HWND CreateWindowEx(DWORD dwExStyle, const char* lpClassName, const char* lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE, LPVOID lpParam) { + return OnMain([&]() -> HWND { + CREATESTRUCT cs; + memset(&cs, 0, sizeof cs); + cs.dwExStyle = dwExStyle; + cs.lpszClass = lpClassName; + cs.lpszName = lpWindowName; + cs.style = static_cast(dwStyle); + cs.x = X; + cs.y = Y; + cs.cx = nWidth; + cs.cy = nHeight; + cs.hwndParent = hWndParent; + cs.hMenu = hMenu; + cs.lpCreateParams = lpParam; + wxWindow* w = CreateWindowForClass(nullptr, cs); + if (w && (dwStyle & WS_VISIBLE)) + w->Show(); + return ToHwnd(w); + }); +} + +HWND CreateWindow(const char* lpClassName, const char* lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, + int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) { + return CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, + lpParam); +} + +BOOL DestroyCaret() { return TRUE; } +BOOL CreateCaret(HWND, HBITMAP, int, int) { return TRUE; } +BOOL ShowCaret(HWND) { return TRUE; } +BOOL HideCaret(HWND) { return TRUE; } +BOOL SetCaretPos(int, int) { return TRUE; } + +int GetLocaleInfo(LCID, DWORD LCType, char* lpLCData, int cchData) { + std::string value; + switch (LCType) { + case LOCALE_IMEASURE: value = "0"; break; + case LOCALE_SDECIMAL: value = "."; break; + case LOCALE_STHOUSAND: value = ","; break; + case LOCALE_IDEFAULTANSICODEPAGE: value = std::to_string(GetAnsiCodePage()); break; + case LOCALE_SABBREVLANGNAME: value = GetResourceLanguage(); break; + default: value = ""; break; + } + if (!lpLCData || cchData == 0) + return static_cast(value.size() + 1); + strncpy(lpLCData, value.c_str(), static_cast(cchData) - 1); + lpLCData[cchData - 1] = 0; + return static_cast(strlen(lpLCData) + 1); +} + +int GetLocaleInfoA(LCID Locale, DWORD LCType, char* lpLCData, int cchData) { + return GetLocaleInfo(Locale, LCType, lpLCData, cchData); +} + +namespace { + +// "Text (*.txt)\0*.txt\0All\0*.*\0\0" -> "Text (*.txt)|*.txt|All|*.*" +wxString FilterFromDoubleNul(const char* f) { + wxString out; + if (!f) + return wxString("*"); + while (*f) { + if (!out.empty()) + out += '|'; + out += ToWx(f); + f += strlen(f) + 1; + } + return out; +} + +BOOL FileDialog(OPENFILENAME* ofn, bool open) { + if (!ofn) + return FALSE; + return OnMain([&]() -> BOOL { + long style = open ? wxFD_OPEN : wxFD_SAVE; + if (open && (ofn->Flags & OFN_FILEMUSTEXIST)) + style |= wxFD_FILE_MUST_EXIST; + if (!open && (ofn->Flags & OFN_OVERWRITEPROMPT)) + style |= wxFD_OVERWRITE_PROMPT; + if (ofn->Flags & OFN_ALLOWMULTISELECT) + style |= wxFD_MULTIPLE; + wxString initial = ofn->lpstrFile ? ToWx(ofn->lpstrFile) : wxString(); + wxString dir = ofn->lpstrInitialDir ? NativePathWx(ofn->lpstrInitialDir) : wxString(); + wxWindow* parent = ofn->hwndOwner ? ToWx(ofn->hwndOwner) : MainWxWindow(); + wxFileDialog dlg(parent, ofn->lpstrTitle ? ToWx(ofn->lpstrTitle) : wxString(), dir, + wxFileName(NativePathWx(ofn->lpstrFile ? ofn->lpstrFile : "")).GetFullName(), + FilterFromDoubleNul(ofn->lpstrFilter), style); + if (ofn->nFilterIndex > 0) + dlg.SetFilterIndex(static_cast(ofn->nFilterIndex) - 1); + if (dlg.ShowModal() != wxID_OK) + return FALSE; + std::string path = AppPath(dlg.GetPath().utf8_str()); + if (!open && ofn->lpstrDefExt && *ofn->lpstrDefExt && path.find('.', path.rfind('\\') + 1) == std::string::npos) + path += std::string(".") + ofn->lpstrDefExt; + if (ofn->lpstrFile && ofn->nMaxFile) { + strncpy(ofn->lpstrFile, path.c_str(), ofn->nMaxFile - 1); + ofn->lpstrFile[ofn->nMaxFile - 1] = 0; + } + size_t slash = path.rfind('\\'); + ofn->nFileOffset = static_cast(slash == std::string::npos ? 0 : slash + 1); + size_t dot = path.rfind('.'); + ofn->nFileExtension = static_cast(dot == std::string::npos || dot < ofn->nFileOffset ? path.size() : dot + 1); + if (ofn->lpstrFileTitle && ofn->nMaxFileTitle) { + strncpy(ofn->lpstrFileTitle, path.c_str() + ofn->nFileOffset, ofn->nMaxFileTitle - 1); + ofn->lpstrFileTitle[ofn->nMaxFileTitle - 1] = 0; + } + ofn->nFilterIndex = static_cast(dlg.GetFilterIndex() + 1); + (void)initial; + return TRUE; + }); +} + +} // namespace + +BOOL GetOpenFileName(OPENFILENAME* lpofn) { return FileDialog(lpofn, true); } +BOOL GetSaveFileName(OPENFILENAME* lpofn) { return FileDialog(lpofn, false); } +BOOL GetOpenFileNameA(OPENFILENAME* lpofn) { return FileDialog(lpofn, true); } +BOOL GetSaveFileNameA(OPENFILENAME* lpofn) { return FileDialog(lpofn, false); } + +BOOL ChooseColor(CHOOSECOLOR* lpcc) { + if (!lpcc) + return FALSE; + return OnMain([&]() -> BOOL { + wxColourData data; + data.SetColour(ToWxColour(lpcc->rgbResult)); + wxColourDialog dlg(lpcc->hwndOwner ? ToWx(lpcc->hwndOwner) : MainWxWindow(), &data); + if (dlg.ShowModal() != wxID_OK) + return FALSE; + lpcc->rgbResult = FromWxColour(dlg.GetColourData().GetColour()); + return TRUE; + }); +} + +BOOL FlashWindow(HWND hWnd, BOOL) { + if (IsWindow(hWnd)) + OnMain([&] { + if (auto* tlw = wxDynamicCast(wxGetTopLevelParent(ToWx(hWnd)), wxTopLevelWindow)) + tlw->RequestUserAttention(); + }); + return TRUE; +} diff --git a/port/mfcwx/src/windows_impl.h b/port/mfcwx/src/windows_impl.h new file mode 100644 index 000000000..ddac5754b --- /dev/null +++ b/port/mfcwx/src/windows_impl.h @@ -0,0 +1,112 @@ +#pragma once + +// Internal helpers shared by wnd.cpp, controls.cpp, dialog.cpp, winapi.cpp, frames and doc/view. + +#include "internal.h" + +#include + +namespace mfcwx { + +template +R OnMainImpl(F&& f, std::false_type) { + R result{}; + RunOnMainThread([&] { result = f(); }); + return result; +} + +template +void OnMainImpl(F&& f, std::true_type) { + RunOnMainThread([&] { f(); }); +} + +// Runs f on the main thread (synchronously) and returns its result. +template +auto OnMain(F&& f) -> decltype(f()) { + using R = decltype(f()); + if (IsMainThread()) + return f(); + return OnMainImpl(std::forward(f), std::is_void()); +} + + +class MessageScope { +public: + MessageScope(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, wxEvent* event); + ~MessageScope(); + bool DefaultCalled() const; + MessageScope(const MessageScope&) = delete; + MessageScope& operator=(const MessageScope&) = delete; +}; + +bool IsManagedWindow(wxWindow* window); +void OnWindowGone(wxWindow* window); +CWnd* PermanentWnd(wxWindow* window); +CWnd* WrapperFor(wxWindow* window); +bool HasMessageHandler(CWnd* pWnd, UINT message); +LRESULT SendFromEvent(wxWindow* window, UINT msg, WPARAM wParam, LPARAM lParam, wxEvent& event, bool* defaultCalled); + +UINT VirtualKeyFromWx(int code); +int WxKeyFromVirtual(UINT vk); +LPARAM KeyLParam(const wxKeyEvent& e, bool up); +WPARAM MouseFlags(const wxMouseEvent& e); +bool TranslateCharToAnsi(const wxKeyEvent& e, UINT& ch); + +UINT_PTR StartTimer(wxWindow* window, UINT_PTR id, UINT elapse, TIMERPROC proc); +bool StopTimer(wxWindow* window, UINT_PTR id); + +// controls.cpp +void BindControlEvents(wxWindow* window, WindowState& state); +// Applies ES_NUMBER / ES_UPPERCASE / ES_LOWERCASE and read-only rules; true if the key was consumed. +bool FilterEditChar(wxWindow* window, WindowState& state, UINT& ch, wxKeyEvent& event); +void NotifyFocusChange(wxWindow* window, WindowState& state, bool gained); +// Replaces a native control by a custom-drawn window if pWnd paints it itself; returns the window to attach. +wxWindow* PrepareForSubclass(wxWindow* window, CWnd* pWnd); +wxWindow* CreateWindowForClass(CWnd* pWnd, CREATESTRUCT& cs); +DWORD CurrentStyle(wxWindow* window); +void ApplyStyle(wxWindow* window, DWORD oldStyle, DWORD newStyle); +LRESULT ControlWindowProc(wxWindow* window, WindowState& state, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled); +// Sends WM_CTLCOLOR* for a control and applies the resulting colours. +void ApplyCtlColor(wxWindow* control); +wxString GetControlText(wxWindow* window); +void SetControlText(wxWindow* window, const wxString& text); + +// scintilla.cpp: wxStyledTextCtrl behind the Scintilla message API (ANSI text, ANSI positions) +void BindScintillaEvents(wxWindow* window); +LRESULT ScintillaWindowProc(wxWindow* window, UINT msg, WPARAM wParam, LPARAM lParam, bool& handled); + +// winapi.cpp: exact ANSI bytes copied by a Scintilla window; GetClipboardData(CF_TEXT) returns them (zero-padded to minSize). +void RememberClipboardText(std::string ansiBytes, size_t minSize); + +// gdi.cpp: an HBITMAP owning a copy of bmp +HBITMAP CreateBitmapHandle(const wxBitmap& bmp); + +// wnd.cpp / winapi.cpp +void DestroyWxWindow(wxWindow* window); +// The parent in the Win32 sense (skips internal wx containers). +wxWindow* LogicalParent(wxWindow* window); +void ResetCursorRequest(); +const wxCursor* RequestedCursor(); +// Sends a WM_COMMAND notification for a control to its parent. +void NotifyParent(wxWindow* control, UINT code); +// Sends WM_NOTIFY with the given header (hwndFrom/idFrom are filled in). +LRESULT NotifyParentNM(wxWindow* control, NMHDR* hdr); + +// menu.cpp: command ids of menu items (ID_APP_ABOUT/ID_APP_EXIT map to the wx stock ids) +int MenuWxId(int winId); +int MenuWinId(int wxId); +// Accelerator table whose keys are shown in menus built afterwards. +void SetMenuAccelerators(const rc::AccelTable* table); + +// dialog.cpp +wxWindow* CreateDialogWindow(CDialog* dlg, const rc::Dialog& tmpl, wxWindow* parent); +BOOL ApplyDlgInit(CWnd* pWnd, int dialogId); +// Handles Enter/Escape/F1 like the Windows dialog manager; true if consumed. +bool DialogKeyHook(wxWindow* dialog, wxKeyEvent& event); + +// app.cpp +BOOL ShowContextHelp(CWnd* pWnd, HELPINFO* pHelpInfo); +// Runs the application's PreTranslateMessage chain for a key event; true if consumed. +bool PreTranslateKey(wxWindow* topLevel, wxKeyEvent& event, UINT message); + +} // namespace mfcwx diff --git a/port/mfcwx/src/wnd.cpp b/port/mfcwx/src/wnd.cpp new file mode 100644 index 000000000..cbaf3156e --- /dev/null +++ b/port/mfcwx/src/wnd.cpp @@ -0,0 +1,1858 @@ +#include "internal.h" +#include "windows_impl.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace mfcwx { + +// --------------------------------------------------------------------------------------------- +// Threads + +namespace { + +const std::thread::id g_mainThread = std::this_thread::get_id(); + +} // namespace + +bool IsMainThread() { return std::this_thread::get_id() == g_mainThread; } + +void RunOnMainThread(const std::function& fn) { + if (IsMainThread() || !wxTheApp) { + fn(); + return; + } + std::mutex m; + std::condition_variable cv; + bool done = false; + std::exception_ptr error; + wxTheApp->CallAfter([&] { + try { + fn(); + } catch (...) { + error = std::current_exception(); + } + std::lock_guard lock(m); + done = true; + cv.notify_one(); + }); + std::unique_lock lock(m); + cv.wait(lock, [&] { return done; }); + if (error) + std::rethrow_exception(error); +} + +void PostToMainThread(std::function fn) { + if (wxTheApp) + wxTheApp->CallAfter(std::move(fn)); +} + +// --------------------------------------------------------------------------------------------- +// Window registry + +namespace { + +std::unordered_map>& States() { + static auto* states = new std::unordered_map>(); + return *states; +} + +std::unordered_map& TempWrappers() { + static auto* temps = new std::unordered_map(); + return *temps; +} + +// Deleted together with the wx window; performs the final MFC-side cleanup. +class WindowTracker : public wxClientData { +public: + explicit WindowTracker(wxWindow* window) : m_window(window) {} + ~WindowTracker() override { OnWindowGone(m_window); } + +private: + wxWindow* m_window; +}; + +std::vector& MessageStack() { + static std::vector stack; + return stack; +} + +} // namespace + +WindowState* GetState(wxWindow* window) { + if (!window) + return nullptr; + auto it = States().find(window); + return it == States().end() ? nullptr : it->second.get(); +} + +WindowState& EnsureState(wxWindow* window) { + auto& slot = States()[window]; + if (!slot) { + slot.reset(new WindowState); + slot->window = window; + window->SetClientObject(new WindowTracker(window)); + } + return *slot; +} + +bool IsManagedWindow(wxWindow* window) { return window && States().count(window) != 0; } + +void OnWindowGone(wxWindow* window) { + auto it = States().find(window); + if (it == States().end()) + return; + std::unique_ptr state = std::move(it->second); + States().erase(it); + for (auto& t : state->timers) + t.second->Stop(); + auto tmp = TempWrappers().find(window); + if (tmp != TempWrappers().end()) { + CWnd* wrapper = tmp->second; + TempWrappers().erase(tmp); + wrapper->m_hWnd = nullptr; + delete wrapper; + } + CWnd* pWnd = state->permanent; + if (pWnd && pWnd->m_hWnd == ToHwnd(window)) { + if (!state->destroyNotified) { + state->destroyNotified = true; + pWnd->SendMessage(WM_DESTROY); + } + pWnd->m_hWnd = nullptr; + pWnd->PostNcDestroy(); + } +} + +CurrentMessage* GetCurrentMessageSlot() { + auto& stack = MessageStack(); + return stack.empty() ? nullptr : &stack.back(); +} + +MessageScope::MessageScope(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, wxEvent* event) { + CurrentMessage cm; + cm.msg.hwnd = hWnd; + cm.msg.message = message; + cm.msg.wParam = wParam; + cm.msg.lParam = lParam; + cm.msg.time = static_cast(wxGetLocalTimeMillis().GetLo()); + wxPoint p = wxGetMousePosition(); + cm.msg.pt.x = p.x; + cm.msg.pt.y = p.y; + cm.event = event; + cm.defaultCalled = false; + MessageStack().push_back(cm); +} + +MessageScope::~MessageScope() { MessageStack().pop_back(); } + +bool MessageScope::DefaultCalled() const { return MessageStack().back().defaultCalled; } + +CWnd* PermanentWnd(wxWindow* window) { + WindowState* s = GetState(window); + return s ? s->permanent : nullptr; +} + +CWnd* WrapperFor(wxWindow* window) { + if (!window) + return nullptr; + if (CWnd* p = PermanentWnd(window)) + return p; + auto it = TempWrappers().find(window); + if (it != TempWrappers().end()) + return it->second; + EnsureState(window); + CWnd* wrapper = new CWnd; + wrapper->m_hWnd = ToHwnd(window); + TempWrappers()[window] = wrapper; + return wrapper; +} + +bool HasMessageHandler(CWnd* pWnd, UINT message) { + return pWnd && pWnd->FindMessageEntry(message, 0, 0) != nullptr; +} + +// --------------------------------------------------------------------------------------------- +// Message dispatch + +LRESULT DispatchMessageTo(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + wxWindow* window = ToWx(hWnd); + if (!window || !IsManagedWindow(window)) + return 0; + CWnd* pWnd = PermanentWnd(window); + MessageScope scope(hWnd, msg, wParam, lParam, nullptr); + if (pWnd) + return pWnd->WindowProc(msg, wParam, lParam); + return DefaultWindowProc(hWnd, msg, wParam, lParam); +} + +LRESULT SendFromEvent(wxWindow* window, UINT msg, WPARAM wParam, LPARAM lParam, wxEvent& event, bool* defaultCalled) { + CWnd* pWnd = PermanentWnd(window); + MessageScope scope(ToHwnd(window), msg, wParam, lParam, &event); + LRESULT r = pWnd ? pWnd->WindowProc(msg, wParam, lParam) : DefaultWindowProc(ToHwnd(window), msg, wParam, lParam); + if (defaultCalled) + *defaultCalled = scope.DefaultCalled(); + return r; +} + +// --------------------------------------------------------------------------------------------- +// Keyboard translation + +UINT VirtualKeyFromWx(int code) { + if (code >= 'a' && code <= 'z') + return static_cast(code - 'a' + 'A'); + if ((code >= 'A' && code <= 'Z') || (code >= '0' && code <= '9')) + return static_cast(code); + switch (code) { + case WXK_BACK: return VK_BACK; + case WXK_TAB: return VK_TAB; + case WXK_RETURN: case WXK_NUMPAD_ENTER: return VK_RETURN; + case WXK_ESCAPE: return VK_ESCAPE; + case WXK_SPACE: return VK_SPACE; + case WXK_DELETE: case WXK_NUMPAD_DELETE: return VK_DELETE; + case WXK_SHIFT: return VK_SHIFT; + case WXK_ALT: return VK_MENU; + case WXK_CONTROL: return VK_CONTROL; + case WXK_PAUSE: return VK_PAUSE; + case WXK_CAPITAL: return VK_CAPITAL; + case WXK_END: case WXK_NUMPAD_END: return VK_END; + case WXK_HOME: case WXK_NUMPAD_HOME: return VK_HOME; + case WXK_LEFT: case WXK_NUMPAD_LEFT: return VK_LEFT; + case WXK_UP: case WXK_NUMPAD_UP: return VK_UP; + case WXK_RIGHT: case WXK_NUMPAD_RIGHT: return VK_RIGHT; + case WXK_DOWN: case WXK_NUMPAD_DOWN: return VK_DOWN; + case WXK_PAGEUP: case WXK_NUMPAD_PAGEUP: return VK_PRIOR; + case WXK_PAGEDOWN: case WXK_NUMPAD_PAGEDOWN: return VK_NEXT; + case WXK_INSERT: case WXK_NUMPAD_INSERT: return VK_INSERT; + case WXK_HELP: return VK_HELP; + case WXK_NUMPAD0: case WXK_NUMPAD1: case WXK_NUMPAD2: case WXK_NUMPAD3: case WXK_NUMPAD4: + case WXK_NUMPAD5: case WXK_NUMPAD6: case WXK_NUMPAD7: case WXK_NUMPAD8: case WXK_NUMPAD9: + return static_cast(VK_NUMPAD0 + (code - WXK_NUMPAD0)); + case WXK_MULTIPLY: case WXK_NUMPAD_MULTIPLY: return VK_MULTIPLY; + case WXK_ADD: case WXK_NUMPAD_ADD: return VK_ADD; + case WXK_SUBTRACT: case WXK_NUMPAD_SUBTRACT: return VK_SUBTRACT; + case WXK_DECIMAL: case WXK_NUMPAD_DECIMAL: return VK_DECIMAL; + case WXK_DIVIDE: case WXK_NUMPAD_DIVIDE: return VK_DIVIDE; + case WXK_NUMLOCK: return VK_NUMLOCK; + case WXK_SCROLL: return VK_SCROLL; + case ',': return VK_OEM_COMMA; + case '.': return VK_OEM_PERIOD; + case '-': return VK_OEM_MINUS; + case '+': case '=': return VK_OEM_PLUS; + default: break; + } + if (code >= WXK_F1 && code <= WXK_F24) + return static_cast(VK_F1 + (code - WXK_F1)); + return 0; +} + +int WxKeyFromVirtual(UINT vk) { + if ((vk >= 'A' && vk <= 'Z') || (vk >= '0' && vk <= '9')) + return static_cast(vk); + switch (vk) { + case VK_BACK: return WXK_BACK; + case VK_TAB: return WXK_TAB; + case VK_RETURN: return WXK_RETURN; + case VK_ESCAPE: return WXK_ESCAPE; + case VK_SPACE: return WXK_SPACE; + case VK_DELETE: return WXK_DELETE; + case VK_SHIFT: case VK_LSHIFT: case VK_RSHIFT: return WXK_SHIFT; + case VK_CONTROL: case VK_LCONTROL: case VK_RCONTROL: return WXK_CONTROL; + case VK_MENU: case VK_LMENU: case VK_RMENU: return WXK_ALT; + case VK_CAPITAL: return WXK_CAPITAL; + case VK_END: return WXK_END; + case VK_HOME: return WXK_HOME; + case VK_LEFT: return WXK_LEFT; + case VK_UP: return WXK_UP; + case VK_RIGHT: return WXK_RIGHT; + case VK_DOWN: return WXK_DOWN; + case VK_PRIOR: return WXK_PAGEUP; + case VK_NEXT: return WXK_PAGEDOWN; + case VK_INSERT: return WXK_INSERT; + case VK_NUMLOCK: return WXK_NUMLOCK; + case VK_SCROLL: return WXK_SCROLL; + case VK_LBUTTON: return WXK_LBUTTON; + case VK_RBUTTON: return WXK_RBUTTON; + case VK_MBUTTON: return WXK_MBUTTON; + default: break; + } + if (vk >= VK_F1 && vk <= VK_F1 + 23) + return WXK_F1 + static_cast(vk - VK_F1); + if (vk >= VK_NUMPAD0 && vk <= VK_NUMPAD9) + return WXK_NUMPAD0 + static_cast(vk - VK_NUMPAD0); + return 0; +} + +LPARAM KeyLParam(const wxKeyEvent& e, bool up) { + LPARAM lp = 1; + if (e.AltDown()) + lp |= 1L << 29; + if (up) + lp |= (1L << 30) | (1L << 31); + return lp; +} + +WPARAM MouseFlags(const wxMouseEvent& e) { + WPARAM f = 0; + if (e.LeftIsDown()) + f |= MK_LBUTTON; + if (e.RightIsDown()) + f |= MK_RBUTTON; + if (e.MiddleIsDown()) + f |= MK_MBUTTON; + if (e.ShiftDown()) + f |= MK_SHIFT; + if (e.ControlDown()) + f |= MK_CONTROL; + return f; +} + +bool TranslateCharToAnsi(const wxKeyEvent& e, UINT& ch) { + wxChar uc = e.GetUnicodeKey(); + int code = e.GetKeyCode(); + if (uc == WXK_NONE) { + if (code > 0 && code < 32) { + ch = static_cast(code); + return true; + } + return false; + } + if (uc == 127) + return false; + if (uc < 32) { + ch = static_cast(uc); + return true; + } + char a; + UnicodeToAnsi(static_cast(uc), a); + ch = static_cast(a); + return true; +} + +// --------------------------------------------------------------------------------------------- +// Event bridge: generic window events + +namespace { + +void OnKeyDown(wxKeyEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + UINT msg = e.AltDown() && !e.ControlDown() ? WM_SYSKEYDOWN : WM_KEYDOWN; + UINT vk = VirtualKeyFromWx(e.GetKeyCode()); + if (!vk || !HasMessageHandler(pWnd, msg)) { + e.Skip(); + return; + } + bool def = false; + SendFromEvent(w, msg, vk, KeyLParam(e, false), e, &def); + if (def) + e.Skip(); +} + +void OnKeyUp(wxKeyEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + UINT msg = e.AltDown() && !e.ControlDown() ? WM_SYSKEYUP : WM_KEYUP; + UINT vk = VirtualKeyFromWx(e.GetKeyCode()); + if (!vk || !HasMessageHandler(pWnd, msg)) { + e.Skip(); + return; + } + bool def = false; + SendFromEvent(w, msg, vk, KeyLParam(e, true), e, &def); + if (def) + e.Skip(); +} + +void OnChar(wxKeyEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + WindowState* st = GetState(w); + CWnd* pWnd = st ? st->permanent : nullptr; + UINT ch = 0; + if (!TranslateCharToAnsi(e, ch)) { + e.Skip(); + return; + } + if (st && FilterEditChar(w, *st, ch, e)) + return; + if (!HasMessageHandler(pWnd, WM_CHAR)) { + e.Skip(); + return; + } + bool def = false; + SendFromEvent(w, WM_CHAR, ch, KeyLParam(e, false), e, &def); +} + +void SendMouse(wxMouseEvent& e, UINT msg) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + if (!HasMessageHandler(pWnd, msg)) { + e.Skip(); + return; + } + bool def = false; + SendFromEvent(w, msg, MouseFlags(e), MAKELPARAM(e.GetX(), e.GetY()), e, &def); + // Native controls need the default handling to keep working (focus, selection, ...). + e.Skip(); +} + +void OnMouseWheel(wxMouseEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + if (!HasMessageHandler(pWnd, WM_MOUSEWHEEL) || e.GetWheelAxis() != wxMOUSE_WHEEL_VERTICAL) { + e.Skip(); + return; + } + int delta = e.GetWheelRotation() * WHEEL_DELTA / std::max(1, e.GetWheelDelta()); + wxPoint screen = w->ClientToScreen(e.GetPosition()); + bool def = false; + SendFromEvent(w, WM_MOUSEWHEEL, MAKEWPARAM(MouseFlags(e), static_cast(static_cast(delta))), + MAKELPARAM(screen.x, screen.y), e, &def); + if (def) + e.Skip(); +} + +void OnPaint(wxPaintEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + WindowState* st = GetState(w); + if (st && st->customPaint) { + st->customPaint(e); + return; + } + if (!HasMessageHandler(pWnd, WM_PAINT)) { + if (HasClientDCOverlay(w)) { + wxPaintDC dc(w); + PaintClientDCOverlay(w, dc); + } + e.Skip(); + return; + } + bool def = false; + wxPaintDC dc(w); + CDC* c = WrapDC(&dc, w); + SendFromEvent(w, WM_PAINT, 0, 0, e, &def); + PaintClientDCOverlay(w, dc); + UnwrapDC(c); + if (def) + e.Skip(); +} + +void OnEraseBackground(wxEraseEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + if (!HasMessageHandler(pWnd, WM_ERASEBKGND) || !e.GetDC()) { + e.Skip(); + return; + } + CDC* dc = WrapDC(e.GetDC(), w); + bool def = false; + LRESULT r = SendFromEvent(w, WM_ERASEBKGND, reinterpret_cast(dc->m_hDC), 0, e, &def); + UnwrapDC(dc); + if (def || !r) + e.Skip(); +} + +void OnSize(wxSizeEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + e.Skip(); + ClearClientDCOverlay(w); + CWnd* pWnd = PermanentWnd(w); + if (!HasMessageHandler(pWnd, WM_SIZE)) + return; + wxSize sz = w->GetClientSize(); + WPARAM type = SIZE_RESTORED; + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) { + if (tlw->IsIconized()) + type = SIZE_MINIMIZED; + else if (tlw->IsMaximized()) + type = SIZE_MAXIMIZED; + } + SendFromEvent(w, WM_SIZE, type, MAKELPARAM(sz.x, sz.y), e, nullptr); +} + +void OnMove(wxMoveEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + e.Skip(); + CWnd* pWnd = PermanentWnd(w); + if (!HasMessageHandler(pWnd, WM_MOVE)) + return; + wxPoint p = w->GetPosition(); + SendFromEvent(w, WM_MOVE, 0, MAKELPARAM(p.x, p.y), e, nullptr); +} + +void OnFocus(wxFocusEvent& e, bool set) { + wxWindow* w = static_cast(e.GetEventObject()); + e.Skip(); + WindowState* st = GetState(w); + if (!st) + return; + HWND other = ToHwnd(e.GetWindow()); + CWnd* pWnd = st->permanent; + if (HasMessageHandler(pWnd, set ? WM_SETFOCUS : WM_KILLFOCUS)) + SendFromEvent(w, set ? WM_SETFOCUS : WM_KILLFOCUS, reinterpret_cast(other), 0, e, nullptr); + NotifyFocusChange(w, *st, set); +} + +void OnContextMenu(wxContextMenuEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + for (wxWindow* t = w; t; t = t->GetParent()) { + CWnd* pWnd = PermanentWnd(t); + if (HasMessageHandler(pWnd, WM_CONTEXTMENU)) { + wxPoint p = e.GetPosition(); + LPARAM lp = p == wxDefaultPosition ? static_cast(-1) : MAKELPARAM(p.x, p.y); + bool def = false; + SendFromEvent(t, WM_CONTEXTMENU, reinterpret_cast(ToHwnd(w)), lp, e, &def); + if (def) + e.Skip(); + return; + } + if (t->IsTopLevel()) + break; + } + e.Skip(); +} + +void OnSetCursor(wxSetCursorEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + if (!HasMessageHandler(pWnd, WM_SETCURSOR)) { + e.Skip(); + return; + } + ResetCursorRequest(); + bool def = false; + LRESULT r = SendFromEvent(w, WM_SETCURSOR, reinterpret_cast(ToHwnd(w)), + MAKELPARAM(HTCLIENT, WM_MOUSEMOVE), e, &def); + const wxCursor* c = RequestedCursor(); + if (r && c) + e.SetCursor(*c); + else + e.Skip(); +} + +void OnShow(wxShowEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + e.Skip(); + CWnd* pWnd = PermanentWnd(w); + if (HasMessageHandler(pWnd, WM_SHOWWINDOW)) + SendFromEvent(w, WM_SHOWWINDOW, e.IsShown() ? TRUE : FALSE, 0, e, nullptr); +} + +void OnScrollWin(wxScrollWinEvent& e) { + wxWindow* w = static_cast(e.GetEventObject()); + CWnd* pWnd = PermanentWnd(w); + UINT msg = e.GetOrientation() == wxVERTICAL ? WM_VSCROLL : WM_HSCROLL; + if (!HasMessageHandler(pWnd, msg)) { + e.Skip(); + return; + } + wxEventType t = e.GetEventType(); + UINT code = SB_ENDSCROLL; + if (t == wxEVT_SCROLLWIN_TOP) + code = SB_TOP; + else if (t == wxEVT_SCROLLWIN_BOTTOM) + code = SB_BOTTOM; + else if (t == wxEVT_SCROLLWIN_LINEUP) + code = SB_LINEUP; + else if (t == wxEVT_SCROLLWIN_LINEDOWN) + code = SB_LINEDOWN; + else if (t == wxEVT_SCROLLWIN_PAGEUP) + code = SB_PAGEUP; + else if (t == wxEVT_SCROLLWIN_PAGEDOWN) + code = SB_PAGEDOWN; + else if (t == wxEVT_SCROLLWIN_THUMBTRACK) + code = SB_THUMBTRACK; + else if (t == wxEVT_SCROLLWIN_THUMBRELEASE) + code = SB_THUMBPOSITION; + WPARAM wp = MAKEWPARAM(code, static_cast(e.GetPosition())); + SendFromEvent(w, msg, wp, 0, e, nullptr); + if (code == SB_THUMBPOSITION) + SendFromEvent(w, msg, MAKEWPARAM(SB_ENDSCROLL, 0), 0, e, nullptr); +} + +void OnDestroyEvent(wxWindowDestroyEvent& e) { + e.Skip(); + wxWindow* w = static_cast(e.GetEventObject()); + if (w != e.GetWindow()) + return; + WindowState* st = GetState(w); + if (!st || st->destroyNotified || !st->permanent) + return; + st->destroyNotified = true; + st->permanent->SendMessage(WM_DESTROY); +} + +} // namespace + +void HookWindow(wxWindow* window, ControlKind kind, int winId, DWORD style, DWORD exStyle) { + WindowState& st = EnsureState(window); + st.kind = kind; + st.winId = winId; + st.style = style; + st.exStyle = exStyle; + if (st.hooked) + return; + st.hooked = true; + window->Bind(wxEVT_KEY_DOWN, &OnKeyDown); + window->Bind(wxEVT_KEY_UP, &OnKeyUp); + window->Bind(wxEVT_CHAR, &OnChar); + window->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& e) { SendMouse(e, WM_LBUTTONDOWN); }); + window->Bind(wxEVT_LEFT_UP, [](wxMouseEvent& e) { SendMouse(e, WM_LBUTTONUP); }); + window->Bind(wxEVT_LEFT_DCLICK, [](wxMouseEvent& e) { SendMouse(e, WM_LBUTTONDBLCLK); }); + window->Bind(wxEVT_RIGHT_DOWN, [](wxMouseEvent& e) { SendMouse(e, WM_RBUTTONDOWN); }); + window->Bind(wxEVT_RIGHT_UP, [](wxMouseEvent& e) { SendMouse(e, WM_RBUTTONUP); }); + window->Bind(wxEVT_RIGHT_DCLICK, [](wxMouseEvent& e) { SendMouse(e, WM_RBUTTONDBLCLK); }); + window->Bind(wxEVT_MIDDLE_DOWN, [](wxMouseEvent& e) { SendMouse(e, WM_MBUTTONDOWN); }); + window->Bind(wxEVT_MIDDLE_UP, [](wxMouseEvent& e) { SendMouse(e, WM_MBUTTONUP); }); + window->Bind(wxEVT_MOTION, [](wxMouseEvent& e) { SendMouse(e, WM_MOUSEMOVE); }); + window->Bind(wxEVT_MOUSEWHEEL, &OnMouseWheel); + window->Bind(wxEVT_PAINT, &OnPaint); + window->Bind(wxEVT_ERASE_BACKGROUND, &OnEraseBackground); + window->Bind(wxEVT_SIZE, &OnSize); + window->Bind(wxEVT_MOVE, &OnMove); + window->Bind(wxEVT_SET_FOCUS, [](wxFocusEvent& e) { OnFocus(e, true); }); + window->Bind(wxEVT_KILL_FOCUS, [](wxFocusEvent& e) { OnFocus(e, false); }); + window->Bind(wxEVT_CONTEXT_MENU, &OnContextMenu); + window->Bind(wxEVT_SET_CURSOR, &OnSetCursor); + window->Bind(wxEVT_SHOW, &OnShow); + window->Bind(wxEVT_DESTROY, &OnDestroyEvent); + for (const wxEventTypeTag& t : {wxEVT_SCROLLWIN_TOP, wxEVT_SCROLLWIN_BOTTOM, wxEVT_SCROLLWIN_LINEUP, wxEVT_SCROLLWIN_LINEDOWN, + wxEVT_SCROLLWIN_PAGEUP, wxEVT_SCROLLWIN_PAGEDOWN, wxEVT_SCROLLWIN_THUMBTRACK, + wxEVT_SCROLLWIN_THUMBRELEASE}) + window->Bind(t, &OnScrollWin); + BindControlEvents(window, st); +} + +// --------------------------------------------------------------------------------------------- +// Timers + +namespace { + +class TimerOwner : public wxTimer { +public: + TimerOwner(wxWindow* window, UINT_PTR id) : m_window(window), m_id(id) {} + void Notify() override { + wxWindow* w = m_window; + UINT_PTR id = m_id; + WindowState* st = GetState(w); + if (!st) + return; + auto proc = st->timerProcs.find(id); + if (proc != st->timerProcs.end() && proc->second) { + proc->second(ToHwnd(w), WM_TIMER, id, GetTickCount()); + return; + } + DispatchMessageTo(ToHwnd(w), WM_TIMER, id, 0); + } + +private: + wxWindow* m_window; + UINT_PTR m_id; +}; + +} // namespace + +UINT_PTR StartTimer(wxWindow* window, UINT_PTR id, UINT elapse, TIMERPROC proc) { + WindowState& st = EnsureState(window); + auto it = st.timers.find(id); + if (it != st.timers.end()) + it->second->Stop(); + std::unique_ptr timer(new TimerOwner(window, id)); + timer->Start(static_cast(std::max(elapse, USER_TIMER_MINIMUM))); + st.timers[id] = std::move(timer); + st.timerProcs[id] = proc; + return id ? id : 1; +} + +bool StopTimer(wxWindow* window, UINT_PTR id) { + WindowState* st = GetState(window); + if (!st) + return false; + auto it = st->timers.find(id); + if (it == st->timers.end()) + return false; + it->second->Stop(); + // The timer may be the one currently notifying; delete it later. + wxTimer* timer = it->second.release(); + st->timers.erase(it); + st->timerProcs.erase(id); + if (wxTheApp) + wxTheApp->CallAfter([timer] { delete timer; }); + return true; +} + +} // namespace mfcwx + +using namespace mfcwx; + +// --------------------------------------------------------------------------------------------- +// CWnd + +CRuntimeClass CWnd::classCWnd = {"CWnd", sizeof(CWnd), 0xFFFF, &CWnd::CreateObject, &CCmdTarget::GetThisClass, nullptr}; +static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd); +CRuntimeClass* CWnd::GetThisClass() { return &CWnd::classCWnd; } +CRuntimeClass* CWnd::GetRuntimeClass() const { return &CWnd::classCWnd; } +CObject* CWnd::CreateObject() { return new CWnd; } + +const AFX_MSGMAP* CWnd::GetMessageMap() const { return GetThisMessageMap(); } +const AFX_MSGMAP* CWnd::GetThisMessageMap() { + static const AFX_MSGMAP_ENTRY entries[] = {{0, 0, 0, 0, AfxSig_end, nullptr}}; + static const AFX_MSGMAP map = {&CCmdTarget::GetThisMessageMap, &entries[0]}; + return ↦ +} + +const CWnd wndTop; +const CWnd wndBottom; +const CWnd wndTopMost; +const CWnd wndNoTopMost; + +CWnd::CWnd() : m_hWnd(nullptr) {} + +CWnd::~CWnd() { + if (m_hWnd && IsMainThread()) { + wxWindow* w = GetWx(); + WindowState* st = GetState(w); + if (st && st->permanent == this) { + st->permanent = nullptr; + if (!st->destroyNotified && !w->IsBeingDeleted()) { + st->destroyNotified = true; + m_hWnd = nullptr; + w->Destroy(); + } + } + m_hWnd = nullptr; + } +} + +CWnd* CWnd::FromWx(wxWindow* window) { return WrapperFor(window); } + +CWnd* CWnd::FromHandle(HWND hWnd) { + if (!hWnd) + return nullptr; + return OnMain([&] { return WrapperFor(ToWx(hWnd)); }); +} + +CWnd* CWnd::FromHandlePermanent(HWND hWnd) { + if (!hWnd) + return nullptr; + return PermanentWnd(ToWx(hWnd)); +} + +void CWnd::DeleteTempMap() {} + +void CWnd::AttachWx(wxWindow* window) { + WindowState& st = EnsureState(window); + auto tmp = TempWrappers().find(window); + if (tmp != TempWrappers().end()) { + tmp->second->m_hWnd = nullptr; + delete tmp->second; + TempWrappers().erase(tmp); + } + st.permanent = this; + m_hWnd = ToHwnd(window); +} + +BOOL CWnd::Attach(HWND hWndNew) { + if (!hWndNew) + return FALSE; + OnMain([&] { AttachWx(ToWx(hWndNew)); }); + return TRUE; +} + +HWND CWnd::Detach() { + HWND h = m_hWnd; + if (h) { + WindowState* st = GetState(GetWx()); + if (st && st->permanent == this) + st->permanent = nullptr; + } + m_hWnd = nullptr; + return h; +} + +BOOL CWnd::SubclassWindow(HWND hWnd) { + if (!hWnd) + return FALSE; + return OnMain([&] { + wxWindow* w = ToWx(hWnd); + w = PrepareForSubclass(w, this); + AttachWx(w); + PreSubclassWindow(); + return TRUE; + }); +} + +BOOL CWnd::SubclassDlgItem(UINT nID, CWnd* pParent) { + if (!pParent) + return FALSE; + HWND h = nullptr; + pParent->GetDlgItem(static_cast(nID), &h); + return h ? SubclassWindow(h) : FALSE; +} + +HWND CWnd::UnsubclassWindow() { return Detach(); } + +BOOL CWnd::PreCreateWindow(CREATESTRUCT&) { return TRUE; } + +BOOL CWnd::Create(const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { + return CreateEx(0, lpszClassName, lpszWindowName, dwStyle | WS_CHILD, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, pParentWnd ? pParentWnd->m_hWnd : nullptr, + reinterpret_cast(static_cast(nID)), pContext); +} + +BOOL CWnd::CreateEx(DWORD dwExStyle, const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam) { + return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, pParentWnd ? pParentWnd->m_hWnd : nullptr, + reinterpret_cast(static_cast(nID)), lpParam); +} + +BOOL CWnd::CreateEx(DWORD dwExStyle, const char* lpszClassName, const char* lpszWindowName, DWORD dwStyle, int x, + int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) { + return OnMain([&]() -> BOOL { + CREATESTRUCT cs; + memset(&cs, 0, sizeof cs); + cs.dwExStyle = dwExStyle; + cs.lpszClass = lpszClassName; + cs.lpszName = lpszWindowName; + cs.style = static_cast(dwStyle); + cs.x = x; + cs.y = y; + cs.cx = nWidth; + cs.cy = nHeight; + cs.hwndParent = hWndParent; + cs.hMenu = nIDorHMenu; + cs.lpCreateParams = lpParam; + if (!PreCreateWindow(cs)) + return FALSE; + wxWindow* window = CreateWindowForClass(this, cs); + if (!window) + return FALSE; + AttachWx(window); + PreSubclassWindow(); + if (SendMessage(WM_CREATE, 0, reinterpret_cast(&cs)) == -1) { + DestroyWindow(); + return FALSE; + } + if (m_hWnd) { + wxSize sz = window->GetClientSize(); + SendMessage(WM_SIZE, SIZE_RESTORED, MAKELPARAM(sz.x, sz.y)); + if (cs.style & WS_VISIBLE) + window->Show(); + } + return m_hWnd != nullptr; + }); +} + +BOOL CWnd::DestroyWindow() { + if (!m_hWnd) + return FALSE; + return OnMain([&]() -> BOOL { + wxWindow* w = GetWx(); + WindowState* st = GetState(w); + if (st && !st->destroyNotified) { + st->destroyNotified = true; + SendMessage(WM_DESTROY); + } + if (!m_hWnd) + return TRUE; + DestroyWxWindow(w); + return TRUE; + }); +} + +LRESULT CWnd::SendMessage(UINT message, WPARAM wParam, LPARAM lParam) { + return ::SendMessage(m_hWnd, message, wParam, lParam); +} + +BOOL CWnd::PostMessage(UINT message, WPARAM wParam, LPARAM lParam) { + return ::PostMessage(m_hWnd, message, wParam, lParam); +} + +BOOL CWnd::SendNotifyMessage(UINT message, WPARAM wParam, LPARAM lParam) { + return ::SendNotifyMessage(m_hWnd, message, wParam, lParam); +} + +void CWnd::SendMessageToDescendants(UINT message, WPARAM wParam, LPARAM lParam, BOOL bDeep, BOOL bOnlyPerm) { + OnMain([&] { + std::function walk = [&](wxWindow* parent) { + for (wxWindow* child : parent->GetChildren()) { + if (!IsManagedWindow(child)) + continue; + if (!bOnlyPerm || PermanentWnd(child)) + DispatchMessageTo(ToHwnd(child), message, wParam, lParam); + if (bDeep && IsManagedWindow(child)) + walk(child); + } + }; + if (m_hWnd) + walk(GetWx()); + }); +} + +LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { + LRESULT result = 0; + if (!OnWndMsg(message, wParam, lParam, &result)) + result = DefWindowProc(message, wParam, lParam); + return result; +} + +LRESULT CWnd::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { + return DefaultWindowProc(m_hWnd, message, wParam, lParam); +} + +LRESULT CWnd::Default() { + CurrentMessage* cm = GetCurrentMessageSlot(); + if (!cm) + return 0; + return DefWindowProc(cm->msg.message, cm->msg.wParam, cm->msg.lParam); +} + +const MSG* CWnd::GetCurrentMessage() { + CurrentMessage* cm = GetCurrentMessageSlot(); + static MSG empty; + return cm ? &cm->msg : ∅ +} + +struct AFX_NOTIFY { + LRESULT* pResult; + NMHDR* pNMHDR; +}; + +BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam) { + UINT nID = LOWORD(wParam); + int nCode = HIWORD(wParam); + HWND hWndCtrl = reinterpret_cast(lParam); + if (hWndCtrl) { + if (ReflectChildNotify(WM_COMMAND, wParam, lParam, nullptr)) + return TRUE; + } + if (nID == 0) + return FALSE; + return OnCmdMsg(nID, nCode, nullptr, nullptr); +} + +BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult) { + NMHDR* pNMHDR = reinterpret_cast(lParam); + HWND hWndCtrl = pNMHDR->hwndFrom; + UINT nID = static_cast(pNMHDR->idFrom); + int nCode = static_cast(pNMHDR->code); + if (hWndCtrl && ReflectChildNotify(WM_NOTIFY, 0, lParam, pResult)) + return TRUE; + AFX_NOTIFY notify; + notify.pResult = pResult; + notify.pNMHDR = pNMHDR; + return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, nullptr); +} + +BOOL CWnd::ReflectChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { + HWND hChild = nullptr; + switch (message) { + case WM_COMMAND: + hChild = reinterpret_cast(lParam); + break; + case WM_NOTIFY: + hChild = reinterpret_cast(lParam)->hwndFrom; + break; + case WM_DRAWITEM: + hChild = reinterpret_cast(lParam)->hwndItem; + break; + case WM_HSCROLL: + case WM_VSCROLL: + case WM_CTLCOLOR: + hChild = reinterpret_cast(lParam); + break; + default: + break; + } + CWnd* child = hChild ? FromHandlePermanent(hChild) : nullptr; + if (!child || child == this) + return FALSE; + return child->OnChildNotify(message, wParam, lParam, pResult); +} + +BOOL CWnd::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { + UINT reflected = message + WM_REFLECT_BASE; + UINT code = 0; + if (message == WM_COMMAND) + code = HIWORD(wParam); + else if (message == WM_NOTIFY) + code = reinterpret_cast(lParam)->code; + const AFX_MSGMAP_ENTRY* e = nullptr; + for (const AFX_MSGMAP* map = GetMessageMap(); map && !e; map = map->pfnGetBaseMap ? map->pfnGetBaseMap() : nullptr) { + for (const AFX_MSGMAP_ENTRY* it = map->lpEntries; it->nSig != AfxSig_end; ++it) + if (it->nMessage == reflected && (message != WM_COMMAND && message != WM_NOTIFY ? true : it->nCode == code)) { + e = it; + break; + } + if (!map->pfnGetBaseMap) + break; + } + if (!e) + return FALSE; + switch (e->nSig) { + case AfxSig_vv_reflect: + (this->*e->pfn)(); + return TRUE; + case AfxSig_bv_reflect: + return (this->*reinterpret_cast(e->pfn))(); + case AfxSig_vNMHDRpl: + (this->*reinterpret_cast(e->pfn))( + reinterpret_cast(lParam), pResult); + return TRUE; + case AfxSig_bNMHDRpl: + return (this->*reinterpret_cast(e->pfn))( + reinterpret_cast(lParam), pResult); + case AfxSig_hDw: { + HBRUSH h = (static_cast(this)->*reinterpret_cast(e->pfn))( + CDC::FromHandle(reinterpret_cast(wParam)), static_cast(pResult ? *pResult : 0)); + if (pResult) + *pResult = reinterpret_cast(h); + return h != nullptr; + } + case AfxSig_vOWNER: + (static_cast(this)->*reinterpret_cast(e->pfn))( + reinterpret_cast(lParam)); + return TRUE; + case AfxSig_vwwW: + (static_cast(this)->*reinterpret_cast(e->pfn))(LOWORD(wParam), + HIWORD(wParam)); + return TRUE; + default: + return FALSE; + } +} + +BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { + LRESULT lResult = 0; + if (message == WM_COMMAND) { + if (OnCommand(wParam, lParam)) { + if (pResult) + *pResult = 1; + return TRUE; + } + return FALSE; + } + if (message == WM_NOTIFY) { + if (OnNotify(wParam, lParam, &lResult)) { + if (pResult) + *pResult = lResult; + return TRUE; + } + return FALSE; + } + UINT lookup = message; + if (message >= WM_CTLCOLORMSGBOX && message <= WM_CTLCOLORSTATIC) + lookup = WM_CTLCOLOR; + if (message == WM_DRAWITEM || message == WM_HSCROLL || message == WM_VSCROLL || + (message >= WM_CTLCOLORMSGBOX && message <= WM_CTLCOLORSTATIC)) { + LRESULT reflectResult = message >= WM_CTLCOLORMSGBOX ? static_cast(message - WM_CTLCOLORMSGBOX) : 0; + if (ReflectChildNotify(lookup, wParam, lParam, &reflectResult)) { + if (pResult) + *pResult = reflectResult; + return TRUE; + } + } + const AFX_MSGMAP_ENTRY* e = FindMessageEntry(lookup, 0, 0); + if (!e) + return FALSE; + union { + AFX_PMSG pfn; + void (CWnd::*vv)(); + BOOL (CWnd::*bv)(); + LRESULT (CWnd::*lwl)(WPARAM, LPARAM); + int (CWnd::*is)(LPCREATESTRUCT); + BOOL (CWnd::*bD)(CDC*); + void (CWnd::*vwii)(UINT, int, int); + void (CWnd::*vwwx)(UINT, UINT, UINT); + void (CWnd::*vwp)(UINT, CPoint); + BOOL (CWnd::*bwsp)(UINT, short, CPoint); + void (CWnd::*vwwW)(UINT, UINT, CScrollBar*); + HBRUSH (CWnd::*hDWw)(CDC*, CWnd*, UINT); + void (CWnd::*vOWNER)(int, LPDRAWITEMSTRUCT); + void (CWnd::*vMEASURE)(int, LPMEASUREITEMSTRUCT); + void (CWnd::*vW)(CWnd*); + void (CWnd::*vWp)(CWnd*, CPoint); + BOOL (CWnd::*bWww)(CWnd*, UINT, UINT); + void (CWnd::*vbw)(BOOL, UINT); + void (CWnd::*vwl)(UINT, LPARAM); + void (CWnd::*vw_ptr)(UINT_PTR); + void (CWnd::*vw_uint)(UINT); + HCURSOR (CWnd::*hv)(); + BOOL (CWnd::*bHELPINFO)(HELPINFO*); + void (CWnd::*vPOS)(MINMAXINFO*); + void (CWnd::*vwWb)(UINT, CWnd*, BOOL); + UINT (CWnd::*wv)(); + void (CWnd::*vHDROP)(HDROP); + void (CWnd::*vMwb)(CMenu*, UINT, BOOL); + void (CWnd::*vii)(int, int); + void (CWnd::*vbWW)(BOOL, CWnd*, CWnd*); + BOOL (CWnd::*bb)(BOOL); + void (CWnd::*vb)(BOOL); + void (CWnd::*vwwh)(UINT, UINT, HMENU); + void (CWnd::*vRECT)(UINT, LPRECT); + } mmf; + mmf.pfn = e->pfn; + UINT_PTR sig = e->nMessage == 0xC000 ? AfxSig_lwl : e->nSig; + switch (sig) { + case AfxSig_vv: + (this->*mmf.vv)(); + break; + case AfxSig_bv: + lResult = (this->*mmf.bv)(); + break; + case AfxSig_lwl: + lResult = (this->*mmf.lwl)(wParam, lParam); + break; + case AfxSig_is: + lResult = (this->*mmf.is)(reinterpret_cast(lParam)); + break; + case AfxSig_bD: + lResult = (this->*mmf.bD)(CDC::FromHandle(reinterpret_cast(wParam))); + break; + case AfxSig_vwii: + (this->*mmf.vwii)(static_cast(wParam), LOWORD(lParam), HIWORD(lParam)); + break; + case AfxSig_vwwx: + (this->*mmf.vwwx)(static_cast(wParam), LOWORD(lParam), HIWORD(lParam)); + break; + case AfxSig_vwp: + (this->*mmf.vwp)(static_cast(wParam), CPoint(static_cast(LOWORD(lParam)), + static_cast(HIWORD(lParam)))); + break; + case AfxSig_bwsp: { + CPoint pt(static_cast(LOWORD(lParam)), static_cast(HIWORD(lParam))); + lResult = (this->*mmf.bwsp)(LOWORD(wParam), static_cast(HIWORD(wParam)), pt); + break; + } + case AfxSig_vwwW: + (this->*mmf.vwwW)(LOWORD(wParam), HIWORD(wParam), + reinterpret_cast(CWnd::FromHandle(reinterpret_cast(lParam)))); + break; + case AfxSig_hDWw: { + UINT ctlType = message == WM_CTLCOLOR ? static_cast(HIWORD(lParam)) : message - WM_CTLCOLORMSGBOX; + lResult = reinterpret_cast((this->*mmf.hDWw)(CDC::FromHandle(reinterpret_cast(wParam)), + CWnd::FromHandle(reinterpret_cast(lParam)), + ctlType)); + break; + } + case AfxSig_vOWNER: + (this->*mmf.vOWNER)(static_cast(wParam), reinterpret_cast(lParam)); + lResult = TRUE; + break; + case AfxSig_vMEASURE: + (this->*mmf.vMEASURE)(static_cast(wParam), reinterpret_cast(lParam)); + lResult = TRUE; + break; + case AfxSig_vW: + (this->*mmf.vW)(CWnd::FromHandle(reinterpret_cast(wParam))); + break; + case AfxSig_vWp: + (this->*mmf.vWp)(CWnd::FromHandle(reinterpret_cast(wParam)), + CPoint(static_cast(LOWORD(lParam)), static_cast(HIWORD(lParam)))); + break; + case AfxSig_bWww: + lResult = (this->*mmf.bWww)(CWnd::FromHandle(reinterpret_cast(wParam)), LOWORD(lParam), HIWORD(lParam)); + break; + case AfxSig_vbw: + (this->*mmf.vbw)(static_cast(wParam), static_cast(lParam)); + break; + case AfxSig_vwl: + (this->*mmf.vwl)(static_cast(wParam), lParam); + break; + case AfxSig_vw_ptr: + (this->*mmf.vw_ptr)(static_cast(wParam)); + break; + case AfxSig_vw_uint: + (this->*mmf.vw_uint)(static_cast(wParam)); + break; + case AfxSig_hv: + lResult = reinterpret_cast((this->*mmf.hv)()); + break; + case AfxSig_bHELPINFO: + lResult = (this->*mmf.bHELPINFO)(reinterpret_cast(lParam)); + break; + case AfxSig_vPOS: + (this->*mmf.vPOS)(reinterpret_cast(lParam)); + break; + case AfxSig_vwWb: + (this->*mmf.vwWb)(LOWORD(wParam), CWnd::FromHandle(reinterpret_cast(lParam)), HIWORD(wParam)); + break; + case AfxSig_wv: + lResult = (this->*mmf.wv)(); + break; + case AfxSig_vHDROP: + (this->*mmf.vHDROP)(reinterpret_cast(wParam)); + break; + case AfxSig_vMwb: + (this->*mmf.vMwb)(CMenu::FromHandle(reinterpret_cast(wParam)), LOWORD(lParam), HIWORD(lParam)); + break; + case AfxSig_vii: + (this->*mmf.vii)(static_cast(LOWORD(lParam)), static_cast(HIWORD(lParam))); + break; + case AfxSig_vbWW: + (this->*mmf.vbWW)(reinterpret_cast(lParam) == m_hWnd, CWnd::FromHandle(reinterpret_cast(lParam)), + CWnd::FromHandle(reinterpret_cast(wParam))); + break; + case AfxSig_bb: + lResult = (this->*mmf.bb)(static_cast(wParam)); + break; + case AfxSig_vb: + (this->*mmf.vb)(static_cast(wParam)); + break; + case AfxSig_vwwh: + (this->*mmf.vwwh)(LOWORD(wParam), HIWORD(wParam), reinterpret_cast(lParam)); + break; + case AfxSig_vRECT: + (this->*mmf.vRECT)(static_cast(wParam), reinterpret_cast(lParam)); + lResult = TRUE; + break; + default: + return FALSE; + } + if (pResult) + *pResult = lResult; + return TRUE; +} + +BOOL CWnd::PreTranslateMessage(MSG*) { return FALSE; } + +// Default handlers: forward to the window's default processing like MFC's CWnd::Default(). +int CWnd::OnCreate(LPCREATESTRUCT) { return static_cast(Default()); } +void CWnd::OnDestroy() { Default(); } +void CWnd::OnNcDestroy() { Default(); } +void CWnd::OnClose() { Default(); } +void CWnd::OnPaint() { Default(); } +BOOL CWnd::OnEraseBkgnd(CDC*) { return static_cast(Default()); } +void CWnd::OnSize(UINT, int, int) { Default(); } +void CWnd::OnMove(int, int) { Default(); } +void CWnd::OnTimer(UINT_PTR) { Default(); } +void CWnd::OnKeyDown(UINT, UINT, UINT) { Default(); } +void CWnd::OnKeyUp(UINT, UINT, UINT) { Default(); } +void CWnd::OnChar(UINT, UINT, UINT) { Default(); } +void CWnd::OnSysKeyDown(UINT, UINT, UINT) { Default(); } +void CWnd::OnSysKeyUp(UINT, UINT, UINT) { Default(); } +void CWnd::OnSysChar(UINT, UINT, UINT) { Default(); } +void CWnd::OnMouseMove(UINT, CPoint) { Default(); } +void CWnd::OnLButtonDown(UINT, CPoint) { Default(); } +void CWnd::OnLButtonUp(UINT, CPoint) { Default(); } +void CWnd::OnLButtonDblClk(UINT, CPoint) { Default(); } +void CWnd::OnRButtonDown(UINT, CPoint) { Default(); } +void CWnd::OnRButtonUp(UINT, CPoint) { Default(); } +void CWnd::OnRButtonDblClk(UINT, CPoint) { Default(); } +void CWnd::OnMButtonDown(UINT, CPoint) { Default(); } +void CWnd::OnMButtonUp(UINT, CPoint) { Default(); } +void CWnd::OnNcLButtonDown(UINT, CPoint) { Default(); } +BOOL CWnd::OnMouseWheel(UINT, short, CPoint) { return static_cast(Default()); } +void CWnd::OnHScroll(UINT, UINT, CScrollBar*) { Default(); } +void CWnd::OnVScroll(UINT, UINT, CScrollBar*) { Default(); } +HBRUSH CWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { + LRESULT r = 0; + if (pWnd && pWnd != this && pWnd->m_hWnd) { + CWnd* child = FromHandlePermanent(pWnd->m_hWnd); + r = nCtlColor; + if (child && child->OnChildNotify(WM_CTLCOLOR, reinterpret_cast(pDC->m_hDC), + reinterpret_cast(pWnd->m_hWnd), &r)) + return reinterpret_cast(r); + } + return nullptr; +} +void CWnd::OnDrawItem(int, LPDRAWITEMSTRUCT lpDrawItemStruct) { + LRESULT r = 0; + if (lpDrawItemStruct && lpDrawItemStruct->CtlType != ODT_MENU) + ReflectChildNotify(WM_DRAWITEM, 0, reinterpret_cast(lpDrawItemStruct), &r); +} +void CWnd::OnMeasureItem(int, LPMEASUREITEMSTRUCT) {} +void CWnd::OnSetFocus(CWnd*) { Default(); } +void CWnd::OnKillFocus(CWnd*) { Default(); } +void CWnd::OnContextMenu(CWnd*, CPoint) { Default(); } +BOOL CWnd::OnSetCursor(CWnd*, UINT, UINT) { return static_cast(Default()); } +void CWnd::OnShowWindow(BOOL, UINT) { Default(); } +void CWnd::OnSysCommand(UINT, LPARAM) { Default(); } +HCURSOR CWnd::OnQueryDragIcon() { return nullptr; } +BOOL CWnd::OnHelpInfo(HELPINFO* pHelpInfo) { return static_cast(ShowContextHelp(this, pHelpInfo)); } +void CWnd::OnGetMinMaxInfo(MINMAXINFO*) {} +void CWnd::OnActivate(UINT, CWnd*, BOOL) { Default(); } +UINT CWnd::OnGetDlgCode() { return static_cast(Default()); } +void CWnd::OnDropFiles(HDROP) {} +void CWnd::OnInitMenuPopup(CMenu*, UINT, BOOL) {} +void CWnd::OnMDIActivate(BOOL, CWnd*, CWnd*) {} +void CWnd::OnEnable(BOOL) {} +BOOL CWnd::OnNcActivate(BOOL) { return TRUE; } +void CWnd::OnMenuSelect(UINT, UINT, HMENU) {} +void CWnd::OnSizing(UINT, LPRECT) {} + +// --------------------------------------------------------------------------------------------- +// CWnd state and geometry + +DWORD CWnd::GetStyle() const { + return OnMain([&]() -> DWORD { return m_hWnd ? CurrentStyle(GetWx()) : 0; }); +} + +DWORD CWnd::GetExStyle() const { + return OnMain([&]() -> DWORD { + WindowState* st = m_hWnd ? GetState(GetWx()) : nullptr; + return st ? st->exStyle : 0; + }); +} + +BOOL CWnd::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT) { + return OnMain([&]() -> BOOL { + if (!m_hWnd) + return FALSE; + DWORD old = CurrentStyle(GetWx()); + DWORD now = (old & ~dwRemove) | dwAdd; + if (now == old) + return FALSE; + ApplyStyle(GetWx(), old, now); + return TRUE; + }); +} + +BOOL CWnd::ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT) { + return OnMain([&]() -> BOOL { + WindowState* st = m_hWnd ? GetState(GetWx()) : nullptr; + if (!st) + return FALSE; + st->exStyle = (st->exStyle & ~dwRemove) | dwAdd; + return TRUE; + }); +} + +int CWnd::GetDlgCtrlID() const { + return OnMain([&]() -> int { + WindowState* st = m_hWnd ? GetState(GetWx()) : nullptr; + return st ? st->winId : 0; + }); +} + +int CWnd::SetDlgCtrlID(int nID) { + return OnMain([&]() -> int { + WindowState* st = m_hWnd ? GetState(GetWx()) : nullptr; + if (!st) + return 0; + int old = st->winId; + st->winId = nID; + GetWx()->SetId(ToWxId(nID)); + return old; + }); +} + +CWnd* CWnd::GetParent() const { + return OnMain([&]() -> CWnd* { + if (!m_hWnd) + return nullptr; + wxWindow* w = GetWx(); + WindowState* st = GetState(w); + if (st && st->owner) + return FromHandle(st->owner); + wxWindow* p = LogicalParent(w); + return p ? WrapperFor(p) : nullptr; + }); +} + +CWnd* CWnd::SetParent(CWnd* pWndNewParent) { + return OnMain([&]() -> CWnd* { + CWnd* old = GetParent(); + if (m_hWnd && pWndNewParent && pWndNewParent->m_hWnd) + GetWx()->Reparent(pWndNewParent->GetWx()); + return old; + }); +} + +CWnd* CWnd::GetOwner() const { return GetParent(); } + +void CWnd::SetOwner(CWnd* pOwnerWnd) { + OnMain([&] { + if (m_hWnd) + EnsureState(GetWx()).owner = pOwnerWnd ? pOwnerWnd->m_hWnd : nullptr; + }); +} + +CWnd* CWnd::GetParentOwner() const { return GetParent(); } + +CFrameWnd* CWnd::GetParentFrame() const { + return OnMain([&]() -> CFrameWnd* { + if (!m_hWnd) + return nullptr; + for (wxWindow* w = LogicalParent(GetWx()); w; w = LogicalParent(w)) { + CWnd* p = PermanentWnd(w); + if (p && p->IsKindOf(RUNTIME_CLASS(CFrameWnd))) + return static_cast(p); + } + return nullptr; + }); +} + +CFrameWnd* CWnd::GetTopLevelFrame() const { + return OnMain([&]() -> CFrameWnd* { + CFrameWnd* frame = IsKindOf(RUNTIME_CLASS(CFrameWnd)) ? static_cast(const_cast(this)) + : GetParentFrame(); + while (frame) { + CFrameWnd* parent = frame->GetParentFrame(); + if (!parent) + break; + frame = parent; + } + return frame; + }); +} + +CWnd* CWnd::GetTopLevelParent() const { + return OnMain([&]() -> CWnd* { + if (!m_hWnd) + return nullptr; + wxWindow* w = GetWx(); + while (w && !w->IsTopLevel() && w->GetParent()) + w = w->GetParent(); + return WrapperFor(w); + }); +} + +CWnd* CWnd::GetTopLevelOwner() const { return GetTopLevelParent(); } + +CWnd* CWnd::GetTopWindow() const { return GetWindow(GW_CHILD); } + +CWnd* CWnd::GetWindow(UINT nCmd) const { return FromHandle(::GetWindow(m_hWnd, nCmd)); } + +CWnd* CWnd::GetNextWindow(UINT nFlag) const { return FromHandle(::GetWindow(m_hWnd, nFlag)); } + +CWnd* CWnd::GetLastActivePopup() const { return const_cast(this); } + +CWnd* CWnd::GetDescendantWindow(int nID, BOOL) const { + return OnMain([&]() -> CWnd* { + if (!m_hWnd) + return nullptr; + std::function find = [&](wxWindow* parent) -> wxWindow* { + for (wxWindow* child : parent->GetChildren()) { + WindowState* st = GetState(child); + if (st && st->winId == nID) + return child; + if (wxWindow* r = find(child)) + return r; + } + return nullptr; + }; + wxWindow* w = find(GetWx()); + return w ? WrapperFor(w) : nullptr; + }); +} + +CWnd* CWnd::ChildWindowFromPoint(POINT point) const { return FromHandle(::ChildWindowFromPoint(m_hWnd, point)); } +CWnd* CWnd::WindowFromPoint(POINT point) { return FromHandle(::WindowFromPoint(point)); } +CWnd* CWnd::GetActiveWindow() { return FromHandle(::GetActiveWindow()); } +CWnd* CWnd::SetActiveWindow() { return FromHandle(::SetActiveWindow(m_hWnd)); } +CWnd* CWnd::GetForegroundWindow() { return FromHandle(::GetForegroundWindow()); } +BOOL CWnd::SetForegroundWindow() { return ::SetForegroundWindow(m_hWnd); } +CWnd* CWnd::GetFocus() { return FromHandle(::GetFocus()); } +CWnd* CWnd::SetFocus() { return FromHandle(::SetFocus(m_hWnd)); } +CWnd* CWnd::GetDesktopWindow() { return nullptr; } +CWnd* CWnd::GetCapture() { return FromHandle(::GetCapture()); } +CWnd* CWnd::SetCapture() { return FromHandle(::SetCapture(m_hWnd)); } +CWnd* CWnd::FindWindow(const char* lpszClassName, const char* lpszWindowName) { + return FromHandle(::FindWindow(lpszClassName, lpszWindowName)); +} +BOOL CWnd::IsChild(const CWnd* pWnd) const { return pWnd && ::IsChild(m_hWnd, pWnd->m_hWnd); } +BOOL CWnd::IsWindowEnabled() const { return ::IsWindowEnabled(m_hWnd); } +BOOL CWnd::EnableWindow(BOOL bEnable) { return ::EnableWindow(m_hWnd, bEnable); } +BOOL CWnd::IsWindowVisible() const { return ::IsWindowVisible(m_hWnd); } +BOOL CWnd::ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); } +BOOL CWnd::IsIconic() const { return ::IsIconic(m_hWnd); } +BOOL CWnd::IsZoomed() const { return ::IsZoomed(m_hWnd); } +void CWnd::DragAcceptFiles(BOOL bAccept) { ::DragAcceptFiles(m_hWnd, bAccept); } + +void CWnd::SetWindowText(const char* lpszString) { ::SetWindowText(m_hWnd, lpszString); } + +int CWnd::GetWindowText(char* lpszStringBuf, int nMaxCount) const { + return ::GetWindowText(m_hWnd, lpszStringBuf, nMaxCount); +} + +void CWnd::GetWindowText(CString& rString) const { + int n = GetWindowTextLength(); + char* buf = rString.GetBuffer(n + 1); + ::GetWindowText(m_hWnd, buf, n + 1); + rString.ReleaseBuffer(); +} + +int CWnd::GetWindowTextLength() const { return ::GetWindowTextLength(m_hWnd); } + +void CWnd::SetFont(CFont* pFont, BOOL bRedraw) { + SendMessage(WM_SETFONT, reinterpret_cast(pFont ? pFont->m_hObject : nullptr), bRedraw); +} + +CFont* CWnd::GetFont() const { + return CFont::FromHandle(reinterpret_cast(const_cast(this)->SendMessage(WM_GETFONT))); +} + +void CWnd::GetWindowRect(LPRECT lpRect) const { ::GetWindowRect(m_hWnd, lpRect); } +void CWnd::GetClientRect(LPRECT lpRect) const { ::GetClientRect(m_hWnd, lpRect); } +void CWnd::ClientToScreen(LPPOINT lpPoint) const { ::ClientToScreen(m_hWnd, lpPoint); } +void CWnd::ClientToScreen(LPRECT lpRect) const { + ::ClientToScreen(m_hWnd, reinterpret_cast(lpRect)); + ::ClientToScreen(m_hWnd, reinterpret_cast(lpRect) + 1); +} +void CWnd::ScreenToClient(LPPOINT lpPoint) const { ::ScreenToClient(m_hWnd, lpPoint); } +void CWnd::ScreenToClient(LPRECT lpRect) const { + ::ScreenToClient(m_hWnd, reinterpret_cast(lpRect)); + ::ScreenToClient(m_hWnd, reinterpret_cast(lpRect) + 1); +} +void CWnd::MapWindowPoints(CWnd* pwndTo, LPPOINT lpPoint, UINT nCount) const { + ::MapWindowPoints(m_hWnd, pwndTo ? pwndTo->m_hWnd : nullptr, lpPoint, nCount); +} +void CWnd::MapWindowPoints(CWnd* pwndTo, LPRECT lpRect) const { + ::MapWindowPoints(m_hWnd, pwndTo ? pwndTo->m_hWnd : nullptr, reinterpret_cast(lpRect), 2); +} +void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint) { + ::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint); +} +void CWnd::MoveWindow(LPCRECT lpRect, BOOL bRepaint) { + ::MoveWindow(m_hWnd, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, + bRepaint); +} +BOOL CWnd::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags) { + HWND after = nullptr; + if (pWndInsertAfter == &wndTopMost) + after = HWND_TOPMOST; + else if (pWndInsertAfter == &wndNoTopMost) + after = HWND_NOTOPMOST; + else if (pWndInsertAfter == &wndBottom) + after = HWND_BOTTOM; + else if (pWndInsertAfter && pWndInsertAfter != &wndTop) + after = pWndInsertAfter->m_hWnd; + return ::SetWindowPos(m_hWnd, after, x, y, cx, cy, nFlags); +} + +BOOL CWnd::GetWindowPlacement(WINDOWPLACEMENT* lpwndpl) const { + return OnMain([&]() -> BOOL { + if (!m_hWnd || !lpwndpl) + return FALSE; + wxWindow* w = GetWx(); + wxRect r = w->GetRect(); + lpwndpl->flags = 0; + lpwndpl->showCmd = SW_SHOWNORMAL; + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) { + if (tlw->IsMaximized()) + lpwndpl->showCmd = SW_SHOWMAXIMIZED; + else if (tlw->IsIconized()) + lpwndpl->showCmd = SW_SHOWMINIMIZED; + } + lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1; + lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1; + lpwndpl->rcNormalPosition.left = r.x; + lpwndpl->rcNormalPosition.top = r.y; + lpwndpl->rcNormalPosition.right = r.x + r.width; + lpwndpl->rcNormalPosition.bottom = r.y + r.height; + return TRUE; + }); +} + +BOOL CWnd::SetWindowPlacement(const WINDOWPLACEMENT* lpwndpl) { + return OnMain([&]() -> BOOL { + if (!m_hWnd || !lpwndpl) + return FALSE; + wxWindow* w = GetWx(); + const RECT& r = lpwndpl->rcNormalPosition; + wxRect rect(r.left, r.top, r.right - r.left, r.bottom - r.top); + if (w->IsTopLevel()) { + int display = wxDisplay::GetFromPoint(rect.GetTopLeft()); + if (display == wxNOT_FOUND) + rect.SetPosition(wxPoint(50, 50)); + } + w->SetSize(rect); + if (auto* tlw = wxDynamicCast(w, wxTopLevelWindow)) { + if (lpwndpl->showCmd == SW_SHOWMAXIMIZED || lpwndpl->showCmd == SW_MAXIMIZE) + tlw->Maximize(); + } + return TRUE; + }); +} + +void CWnd::CenterWindow(CWnd* pAlternateOwner) { + OnMain([&] { + if (!m_hWnd) + return; + wxWindow* w = GetWx(); + if (pAlternateOwner && pAlternateOwner->m_hWnd && w->IsTopLevel()) { + wxRect owner = pAlternateOwner->GetWx()->GetScreenRect(); + wxSize sz = w->GetSize(); + w->Move(owner.x + (owner.width - sz.x) / 2, owner.y + (owner.height - sz.y) / 2); + } else { + w->CentreOnParent(); + } + }); +} + +void CWnd::BringWindowToTop() { ::BringWindowToTop(m_hWnd); } + +void CWnd::CalcWindowRect(LPRECT lpClientRect, UINT) { + OnMain([&] { + if (!m_hWnd || !lpClientRect) + return; + wxWindow* w = GetWx(); + wxSize outer = w->GetSize(); + wxSize inner = w->GetClientSize(); + lpClientRect->right += outer.x - inner.x; + lpClientRect->bottom += outer.y - inner.y; + }); +} + +void CWnd::Invalidate(BOOL bErase) { ::InvalidateRect(m_hWnd, nullptr, bErase); } +void CWnd::InvalidateRect(LPCRECT lpRect, BOOL bErase) { ::InvalidateRect(m_hWnd, lpRect, bErase); } +void CWnd::InvalidateRgn(CRgn*, BOOL bErase) { ::InvalidateRect(m_hWnd, nullptr, bErase); } +void CWnd::UpdateWindow() { ::UpdateWindow(m_hWnd); } +BOOL CWnd::RedrawWindow(LPCRECT lpRectUpdate, CRgn*, UINT flags) { + return ::RedrawWindow(m_hWnd, lpRectUpdate, nullptr, flags); +} +void CWnd::SetRedraw(BOOL bRedraw) { SendMessage(WM_SETREDRAW, bRedraw, 0); } +BOOL CWnd::GetUpdateRect(LPRECT lpRect, BOOL) { + return OnMain([&]() -> BOOL { + if (!m_hWnd) + return FALSE; + wxRect r = GetWx()->GetUpdateRegion().GetBox(); + if (lpRect) { + lpRect->left = r.x; + lpRect->top = r.y; + lpRect->right = r.x + r.width; + lpRect->bottom = r.y + r.height; + } + return !r.IsEmpty(); + }); +} +void CWnd::ScrollWindow(int, int, LPCRECT, LPCRECT) { Invalidate(); } +CPoint CWnd::GetCaretPos() { return CPoint(0, 0); } + +// scroll bars of generic windows +int CWnd::GetScrollPos(int nBar) const { + return OnMain([&]() -> int { + if (!m_hWnd) + return 0; + if (nBar == SB_CTL) + return static_cast(const_cast(this)->SendMessage(SBM_GETPOS)); + return GetWx()->GetScrollPos(nBar == SB_VERT ? wxVERTICAL : wxHORIZONTAL); + }); +} + +int CWnd::SetScrollPos(int nBar, int nPos, BOOL bRedraw) { + return OnMain([&]() -> int { + if (!m_hWnd) + return 0; + if (nBar == SB_CTL) + return static_cast(SendMessage(SBM_SETPOS, static_cast(nPos), bRedraw)); + int orient = nBar == SB_VERT ? wxVERTICAL : wxHORIZONTAL; + int old = GetWx()->GetScrollPos(orient); + GetWx()->SetScrollPos(orient, nPos, bRedraw != FALSE); + return old; + }); +} + +void CWnd::GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const { + OnMain([&] { + if (!m_hWnd) + return; + int orient = nBar == SB_VERT ? wxVERTICAL : wxHORIZONTAL; + if (lpMinPos) + *lpMinPos = 0; + if (lpMaxPos) + *lpMaxPos = std::max(0, GetWx()->GetScrollRange(orient) - 1); + }); +} + +void CWnd::SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw) { + OnMain([&] { + if (!m_hWnd || nBar == SB_CTL) + return; + int orient = nBar == SB_VERT ? wxVERTICAL : wxHORIZONTAL; + int range = std::max(0, nMaxPos - nMinPos + 1); + GetWx()->SetScrollbar(orient, std::min(GetWx()->GetScrollPos(orient), range), 1, + nMaxPos > nMinPos ? range : 0, bRedraw != FALSE); + }); +} + +BOOL CWnd::SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw) { + return OnMain([&]() -> BOOL { + if (!m_hWnd || !lpScrollInfo) + return FALSE; + int orient = nBar == SB_VERT ? wxVERTICAL : wxHORIZONTAL; + wxWindow* w = GetWx(); + int pos = w->GetScrollPos(orient); + int thumb = w->GetScrollThumb(orient); + int range = w->GetScrollRange(orient); + if (lpScrollInfo->fMask & SIF_RANGE) + range = lpScrollInfo->nMax - lpScrollInfo->nMin + 1; + if (lpScrollInfo->fMask & SIF_PAGE) + thumb = static_cast(lpScrollInfo->nPage); + if (lpScrollInfo->fMask & SIF_POS) + pos = lpScrollInfo->nPos - ((lpScrollInfo->fMask & SIF_RANGE) ? lpScrollInfo->nMin : 0); + if (thumb >= range && !(lpScrollInfo->fMask & SIF_DISABLENOSCROLL)) + range = 0; + w->SetScrollbar(orient, std::max(0, pos), std::max(1, thumb), std::max(0, range), bRedraw != FALSE); + return TRUE; + }); +} + +BOOL CWnd::GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, UINT nMask) { + return OnMain([&]() -> BOOL { + if (!m_hWnd || !lpScrollInfo) + return FALSE; + int orient = nBar == SB_VERT ? wxVERTICAL : wxHORIZONTAL; + wxWindow* w = GetWx(); + lpScrollInfo->fMask = nMask; + lpScrollInfo->nMin = 0; + lpScrollInfo->nMax = std::max(0, w->GetScrollRange(orient) - 1); + lpScrollInfo->nPage = static_cast(w->GetScrollThumb(orient)); + lpScrollInfo->nPos = w->GetScrollPos(orient); + lpScrollInfo->nTrackPos = lpScrollInfo->nPos; + return TRUE; + }); +} + +int CWnd::GetScrollLimit(int nBar) { + SCROLLINFO si; + GetScrollInfo(nBar, &si, SIF_ALL); + return std::max(0, si.nMax - static_cast(si.nPage) + 1); +} + +void CWnd::ShowScrollBar(UINT nBar, BOOL bShow) { + OnMain([&] { + if (!m_hWnd || bShow) + return; + if (nBar == SB_HORZ || nBar == SB_BOTH) + GetWx()->SetScrollbar(wxHORIZONTAL, 0, 0, 0); + if (nBar == SB_VERT || nBar == SB_BOTH) + GetWx()->SetScrollbar(wxVERTICAL, 0, 0, 0); + }); +} + +BOOL CWnd::EnableScrollBar(int, UINT) { return TRUE; } +CScrollBar* CWnd::GetScrollBarCtrl(int) const { return nullptr; } + +UINT_PTR CWnd::SetTimer(UINT_PTR nIDEvent, UINT nElapse, void (*lpfnTimer)(HWND, UINT, UINT_PTR, DWORD)) { + return ::SetTimer(m_hWnd, nIDEvent, nElapse, lpfnTimer); +} + +BOOL CWnd::KillTimer(UINT_PTR nIDEvent) { return ::KillTimer(m_hWnd, nIDEvent); } + +CWnd* CWnd::GetDlgItem(int nID) const { return FromHandle(::GetDlgItem(m_hWnd, nID)); } +void CWnd::GetDlgItem(int nID, HWND* phWnd) const { + if (phWnd) + *phWnd = ::GetDlgItem(m_hWnd, nID); +} +UINT CWnd::GetDlgItemInt(int nID, BOOL* lpTrans, BOOL bSigned) const { + return ::GetDlgItemInt(m_hWnd, nID, lpTrans, bSigned); +} +void CWnd::SetDlgItemInt(int nID, UINT nValue, BOOL bSigned) { ::SetDlgItemInt(m_hWnd, nID, nValue, bSigned); } +int CWnd::GetDlgItemText(int nID, char* lpStr, int nMaxCount) const { + return static_cast(::GetDlgItemText(m_hWnd, nID, lpStr, nMaxCount)); +} +int CWnd::GetDlgItemText(int nID, CString& rString) const { + CWnd* item = GetDlgItem(nID); + if (!item) { + rString.Empty(); + return 0; + } + item->GetWindowText(rString); + return rString.GetLength(); +} +void CWnd::SetDlgItemText(int nID, const char* lpszString) { ::SetDlgItemText(m_hWnd, nID, lpszString); } +UINT CWnd::IsDlgButtonChecked(int nIDButton) const { return ::IsDlgButtonChecked(m_hWnd, nIDButton); } +void CWnd::CheckDlgButton(int nIDButton, UINT nCheck) { ::CheckDlgButton(m_hWnd, nIDButton, nCheck); } +void CWnd::CheckRadioButton(int nIDFirstButton, int nIDLastButton, int nIDCheckButton) { + ::CheckRadioButton(m_hWnd, nIDFirstButton, nIDLastButton, nIDCheckButton); +} +int CWnd::GetCheckedRadioButton(int nIDFirstButton, int nIDLastButton) { + for (int id = nIDFirstButton; id <= nIDLastButton; ++id) + if (IsDlgButtonChecked(id)) + return id; + return 0; +} +LRESULT CWnd::SendDlgItemMessage(int nID, UINT message, WPARAM wParam, LPARAM lParam) { + return ::SendDlgItemMessage(m_hWnd, nID, message, wParam, lParam); +} +CWnd* CWnd::GetNextDlgGroupItem(CWnd* pWndCtl, BOOL bPrevious) const { + return FromHandle(::GetNextDlgGroupItem(m_hWnd, pWndCtl ? pWndCtl->m_hWnd : nullptr, bPrevious)); +} +CWnd* CWnd::GetNextDlgTabItem(CWnd* pWndCtl, BOOL bPrevious) const { + return FromHandle(::GetNextDlgTabItem(m_hWnd, pWndCtl ? pWndCtl->m_hWnd : nullptr, bPrevious)); +} + +BOOL CWnd::UpdateData(BOOL bSaveAndValidate) { + return OnMain([&]() -> BOOL { + CDataExchange dx(this, bSaveAndValidate); + try { + DoDataExchange(&dx); + } catch (CUserException* e) { + e->Delete(); + return FALSE; + } + return TRUE; + }); +} + +void CWnd::DoDataExchange(CDataExchange*) {} + +BOOL CWnd::ExecuteDlgInit(UINT nIDTemplate) { return ApplyDlgInit(this, static_cast(nIDTemplate)); } +BOOL CWnd::ExecuteDlgInit(const char* lpszResourceName) { + ResRef ref = ResRef::From(lpszResourceName); + return ApplyDlgInit(this, ref.id); +} + +CMenu* CWnd::GetMenu() const { return CMenu::FromHandle(::GetMenu(m_hWnd)); } +BOOL CWnd::SetMenu(CMenu* pMenu) { return ::SetMenu(m_hWnd, pMenu ? pMenu->m_hMenu : nullptr); } +void CWnd::DrawMenuBar() { ::DrawMenuBar(m_hWnd); } +CMenu* CWnd::GetSystemMenu(BOOL bRevert) const { return CMenu::FromHandle(::GetSystemMenu(m_hWnd, bRevert)); } + +void CWnd::WinHelp(DWORD_PTR dwData, UINT nCmd) { + CWinApp* app = AfxGetApp(); + if (app) + app->WinHelp(dwData, nCmd); +} + +void CWnd::HtmlHelp(DWORD_PTR dwData, UINT nCmd) { + CWinApp* app = AfxGetApp(); + if (app) + app->HtmlHelp(dwData, nCmd); +} + +HICON CWnd::SetIcon(HICON hIcon, BOOL bBigIcon) { + return reinterpret_cast(SendMessage(WM_SETICON, bBigIcon, reinterpret_cast(hIcon))); +} + +HICON CWnd::GetIcon(BOOL bBigIcon) const { + return reinterpret_cast(const_cast(this)->SendMessage(WM_GETICON, bBigIcon, 0)); +} + +BOOL CWnd::EnableToolTips(BOOL) { return TRUE; } + +int CWnd::MessageBox(const char* lpszText, const char* lpszCaption, UINT nType) { + return ::MessageBox(m_hWnd, lpszText, lpszCaption, nType); +} + +BOOL CWnd::OpenClipboard() { return ::OpenClipboard(m_hWnd); } + +BOOL CWnd::LockWindowUpdate() { + return OnMain([&]() -> BOOL { + if (m_hWnd) + GetWx()->Freeze(); + return TRUE; + }); +} + +void CWnd::UnlockWindowUpdate() { + OnMain([&] { + if (m_hWnd && GetWx()->IsFrozen()) + GetWx()->Thaw(); + }); +} + +LONG_PTR CWnd::GetWindowLongPtr(int nIndex) const { return ::GetWindowLongPtr(m_hWnd, nIndex); } +LONG_PTR CWnd::SetWindowLongPtr(int nIndex, LONG_PTR dwNewLong) { return ::SetWindowLongPtr(m_hWnd, nIndex, dwNewLong); } diff --git a/port/mfcwx/tests/gdi_test_stubs.cpp b/port/mfcwx/tests/gdi_test_stubs.cpp new file mode 100644 index 000000000..7387415bd --- /dev/null +++ b/port/mfcwx/tests/gdi_test_stubs.cpp @@ -0,0 +1,53 @@ +// Stand-ins for symbols of other mfcwx parts so the GDI tests link with the GDI sources only. + +#include "internal.h" + +#include + +AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass*) {} + +CRuntimeClass CObject::classCObject = {"CObject", sizeof(CObject), 0xFFFF, nullptr, nullptr, nullptr}; +CRuntimeClass* CObject::GetThisClass() { return &classCObject; } +CRuntimeClass* CObject::GetRuntimeClass() const { return &classCObject; } +void CObject::Serialize(CArchive&) {} + +BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const { + for (const CRuntimeClass* c = this; c; c = c->GetBaseClass()) + if (c == pBaseClass) + return TRUE; + return FALSE; +} + +BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const { return GetRuntimeClass()->IsDerivedFrom(pClass); } + +void AfxAssertFailedLine(const char* file, int line, const char* expr) { + fprintf(stderr, "ASSERT failed: %s:%d %s\n", file, line, expr ? expr : ""); +} + +void AfxDebugBreak() {} + +CWnd* CWnd::FromHandle(HWND) { return nullptr; } + +namespace mfcwx { + +bool LoadResourceString(UINT, std::string&) { return false; } + +ResRef ResRef::From(const char* lpszName) { + ResRef r; + if (IS_INTRESOURCE(lpszName)) + r.id = static_cast(reinterpret_cast(lpszName)); + else if (lpszName) + r.name = lpszName; + return r; +} + +wxBitmap LoadBitmapResource(const ResRef& ref) { + if (ref.id != 1 && ref.name != "TEST") + return wxNullBitmap; + wxImage img(4, 2, true); + img.SetRGB(0, 0, 255, 0, 0); + img.SetRGB(3, 1, 0, 0, 255); + return wxBitmap(img); +} + +} // namespace mfcwx diff --git a/port/mfcwx/tests/gdi_tests.cpp b/port/mfcwx/tests/gdi_tests.cpp new file mode 100644 index 000000000..7754b096e --- /dev/null +++ b/port/mfcwx/tests/gdi_tests.cpp @@ -0,0 +1,913 @@ +// Visual and pixel tests of the GDI emulation. Renders through CDC into bitmaps, checks key +// pixels and writes PNGs (argv[1] or ./gdi_test_output) for inspection. +// Pass --no-window to skip the tests that create a frame (e.g. on a headless CI machine). + +#include "gdi_internal.h" + +#include + +#include +#include +#include + +using namespace mfcwx; + +namespace { + +int g_checks = 0; +int g_failures = 0; +wxString g_out = "gdi_test_output"; +bool g_windowTests = true; + +#define CHECK(cond, ...) \ + do { \ + ++g_checks; \ + if (!(cond)) { \ + ++g_failures; \ + printf("FAIL %s:%d: %s -- ", __FILE__, __LINE__, #cond); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } \ + } while (0) + +const COLORREF kWhite = RGB(255, 255, 255); +const COLORREF kBlack = RGB(0, 0, 0); +const COLORREF kRed = RGB(255, 0, 0); +const COLORREF kGreen = RGB(0, 255, 0); +const COLORREF kBlue = RGB(0, 0, 255); +const COLORREF kYellow = RGB(255, 255, 0); + +bool Near(COLORREF a, COLORREF b, int tol = 10) { + return std::abs(GetRValue(a) - GetRValue(b)) <= tol && std::abs(GetGValue(a) - GetGValue(b)) <= tol && + std::abs(GetBValue(a) - GetBValue(b)) <= tol; +} + +bool Dark(COLORREF c) { return GetRValue(c) + GetGValue(c) + GetBValue(c) < 384; } + +struct Box { + int left = 1 << 30, top = 1 << 30, right = -1, bottom = -1; + bool Empty() const { return right < 0; } +}; + +struct Canvas { + CDC dc; + CBitmap bmp; + CBitmap* old = nullptr; + int w, h; + Canvas(int width, int height, CDC* compat = nullptr) : w(width), h(height) { + dc.CreateCompatibleDC(compat); + bmp.CreateCompatibleBitmap(compat ? compat : &dc, w, h); + old = dc.SelectObject(&bmp); + dc.FillSolidRect(0, 0, w, h, kWhite); + } + ~Canvas() { + if (old) + dc.SelectObject(old); + } + COLORREF Px(int x, int y) { return dc.GetPixel(x, y); } + Box DarkBox(int l, int t, int r, int b) { + Box box; + for (int y = t; y < b; ++y) + for (int x = l; x < r; ++x) + if (Dark(Px(x, y))) { + box.left = std::min(box.left, x); + box.top = std::min(box.top, y); + box.right = std::max(box.right, x); + box.bottom = std::max(box.bottom, y); + } + return box; + } + void Save(const char* name) { + wxBitmap* b = BitmapFromHandle(bmp); + if (b) + b->SaveFile(g_out + "/" + name + ".png", wxBITMAP_TYPE_PNG); + } +}; + +void TestShapes() { + Canvas c(240, 160); + CPen pen(PS_SOLID, 1, kBlack); + CBrush red(kRed); + CPen* oldPen = c.dc.SelectObject(&pen); + CBrush* oldBrush = c.dc.SelectObject(&red); + CHECK(oldPen && oldBrush, "SelectObject returns the default objects"); + + c.dc.Rectangle(10, 10, 20, 20); + CHECK(Near(c.Px(10, 10), kBlack, 2) && c.Px(15, 10) == kBlack && Near(c.Px(19, 19), kBlack, 2) && + c.Px(10, 15) == kBlack && c.Px(19, 15) == kBlack && c.Px(15, 19) == kBlack, + "rectangle outline covers [left,right-1] (%06x %06x)", c.Px(10, 10), c.Px(19, 19)); + CHECK(c.Px(20, 15) == kWhite && c.Px(15, 20) == kWhite, "rectangle excludes right/bottom (%06x %06x)", + c.Px(20, 15), c.Px(15, 20)); + CHECK(c.Px(15, 15) == kRed && c.Px(11, 11) == kRed, "rectangle fill (%06x)", c.Px(15, 15)); + + CBrush blue(kBlue); + RECT fr{30, 10, 40, 20}; + c.dc.FillRect(&fr, &blue); + CHECK(c.Px(30, 10) == kBlue && c.Px(39, 19) == kBlue, "FillRect covers [left,right) (%06x)", c.Px(39, 19)); + CHECK(c.Px(40, 15) == kWhite && c.Px(35, 20) == kWhite && c.Px(29, 15) == kWhite, "FillRect excludes right/bottom"); + + CBrush green(kGreen); + c.dc.SelectStockObject(NULL_PEN); + c.dc.SelectObject(&green); + c.dc.Rectangle(50, 10, 60, 20); + CHECK(c.Px(50, 10) == kGreen && c.Px(58, 18) == kGreen, "null-pen rectangle fill (%06x)", c.Px(58, 18)); + CHECK(c.Px(59, 15) == kWhite && c.Px(55, 19) == kWhite, "null-pen rectangle is one pixel smaller (%06x)", + c.Px(59, 15)); + c.dc.SelectObject(&pen); + + c.dc.MoveTo(10, 30); + c.dc.LineTo(20, 30); + CHECK(c.Px(10, 30) == kBlack && c.Px(19, 30) == kBlack, "LineTo draws the start (%06x %06x)", c.Px(10, 30), + c.Px(19, 30)); + CHECK(c.Px(20, 30) == kWhite && c.Px(15, 29) == kWhite && c.Px(15, 31) == kWhite, "LineTo excludes the end (%06x)", + c.Px(20, 30)); + CHECK(c.dc.GetCurrentPosition() == CPoint(20, 30), "LineTo updates the position"); + c.dc.MoveTo(25, 25); + c.dc.LineTo(25, 35); + CHECK(c.Px(25, 25) == kBlack && c.Px(25, 34) == kBlack && c.Px(25, 35) == kWhite, "vertical LineTo"); + + POINT frame[] = {{30, 25}, {30, 40}, {45, 40}, {45, 25}, {30, 25}}; + c.dc.Polyline(frame, 5); + CHECK(c.Px(30, 25) == kBlack && c.Px(30, 40) == kBlack && c.Px(45, 40) == kBlack && c.Px(45, 25) == kBlack, + "polyline corners are covered"); + + CBrush yellow(kYellow); + c.dc.SelectObject(&yellow); + c.dc.Ellipse(70, 10, 90, 30); + CHECK(c.Px(80, 20) == kYellow, "ellipse fill (%06x)", c.Px(80, 20)); + CHECK(Dark(c.Px(70, 20)) && Dark(c.Px(89, 20)) && Dark(c.Px(80, 10)) && Dark(c.Px(80, 29)), + "ellipse touches [left,right-1] (%06x %06x)", c.Px(70, 20), c.Px(89, 20)); + CHECK(c.Px(90, 20) == kWhite && c.Px(69, 20) == kWhite && c.Px(80, 30) == kWhite, "ellipse stays in its box (%06x)", + c.Px(90, 20)); + + CPen dash(PS_DASH, 1, kBlack); + c.dc.SelectObject(&dash); + c.dc.MoveTo(10, 50); + c.dc.LineTo(110, 50); + int on = 0, off = 0; + for (int x = 10; x < 110; ++x) + (Dark(c.Px(x, 50)) ? on : off)++; + CHECK(on > 40 && off > 10, "dashed line has dashes and gaps (%d/%d)", on, off); + CPen dot(PS_DOT, 1, kBlack); + c.dc.SelectObject(&dot); + c.dc.MoveTo(10, 55); + c.dc.LineTo(110, 55); + on = off = 0; + for (int x = 10; x < 110; ++x) + (Dark(c.Px(x, 55)) ? on : off)++; + CHECK(on > 20 && off > 20, "dotted line (%d/%d)", on, off); + + CPen wide(PS_SOLID, 5, RGB(0, 0, 128)); + c.dc.SelectObject(&wide); + c.dc.MoveTo(10, 65); + c.dc.LineTo(110, 65); + CHECK(Dark(c.Px(50, 63)) && Dark(c.Px(50, 67)) && !Dark(c.Px(50, 69)), "wide pen width"); + + c.dc.SelectObject(&pen); + c.dc.SelectObject(&red); + POINT tri[] = {{130, 10}, {170, 10}, {150, 40}}; + c.dc.Polygon(tri, 3); + CHECK(c.Px(150, 20) == kRed && c.Px(132, 35) == kWhite, "polygon fill"); + + CBrush hatch(HS_DIAGCROSS, kBlue); + c.dc.SetBkColor(kYellow); + c.dc.SetBkMode(OPAQUE); + RECT hr{130, 50, 170, 80}; + c.dc.FillRect(&hr, &hatch); + int yellowCount = 0, blueCount = 0; + for (int y = 50; y < 80; ++y) + for (int x = 130; x < 170; ++x) { + if (Near(c.Px(x, y), kYellow, 40)) + ++yellowCount; + if (Near(c.Px(x, y), kBlue, 90)) + ++blueCount; + } + CHECK(yellowCount > 200 && blueCount > 50, "opaque hatch uses the bk colour (%d yellow %d blue)", yellowCount, + blueCount); + c.dc.SetBkMode(TRANSPARENT); + RECT hr2{175, 50, 215, 80}; + c.dc.FillRect(&hr2, &hatch); + int whiteCount = 0; + for (int y = 50; y < 80; ++y) + for (int x = 175; x < 215; ++x) + if (c.Px(x, y) == kWhite) + ++whiteCount; + CHECK(whiteCount > 200, "transparent hatch keeps the background (%d)", whiteCount); + + c.dc.SetPixel(5, 5, RGB(12, 34, 56)); + CHECK(c.Px(5, 5) == RGB(12, 34, 56), "SetPixel/GetPixel (%06x)", c.Px(5, 5)); + CHECK(c.dc.GetPixel(-1, 5) == CLR_INVALID, "GetPixel outside"); + + int saved = c.dc.SaveDC(); + CRgn clip; + clip.CreateRectRgn(100, 90, 120, 110); + c.dc.SelectClipRgn(&clip); + c.dc.FillSolidRect(90, 85, 40, 30, kRed); + CHECK(c.Px(105, 95) == kRed && c.Px(95, 95) == kWhite && c.Px(125, 95) == kWhite && c.Px(105, 110) == kWhite, + "clip region limits drawing"); + CRect box; + c.dc.GetClipBox(&box); + CHECK(box == CRect(100, 90, 120, 110), "GetClipBox (%d,%d,%d,%d)", box.left, box.top, box.right, box.bottom); + c.dc.IntersectClipRect(110, 80, 140, 100); + c.dc.FillSolidRect(90, 85, 40, 30, kGreen); + CHECK(c.Px(115, 95) == kGreen && c.Px(105, 95) == kRed && c.Px(115, 105) == kRed, "IntersectClipRect"); + c.dc.SelectObject(&yellow); + CHECK(c.dc.RestoreDC(saved), "RestoreDC"); + CHECK(c.dc.GetCurrentBrush()->m_hObject == red.m_hObject, "RestoreDC restores the brush"); + c.dc.FillSolidRect(90, 120, 40, 10, kBlue); + CHECK(c.Px(92, 125) == kBlue, "RestoreDC removes the clip region"); + + CRgn er; + er.CreateEllipticRgn(140, 100, 180, 140); + c.dc.FillRgn(&er, &blue); + CHECK(c.Px(160, 120) == kBlue && c.Px(141, 101) == kWhite, "elliptic region fill"); + CBrush black(kBlack); + c.dc.FrameRgn(&er, &black, 1, 1); + + RECT pie{190, 100, 230, 140}; + c.dc.Pie(&pie, CPoint(230, 120), CPoint(210, 100)); + CHECK(c.Px(220, 110) == kRed && c.Px(200, 130) != kRed, "pie quadrant"); + c.dc.RoundRect(190, 10, 230, 40, 10, 10); + CHECK(c.Px(210, 25) == kRed && c.Px(190, 10) == kWhite, "round rect corners"); + + c.dc.SelectObject(oldPen); + c.dc.SelectObject(oldBrush); + c.Save("shapes"); +} + +void TestText() { + Canvas c(320, 260); + c.dc.SetBkMode(TRANSPARENT); + TEXTMETRIC tm; + CHECK(c.dc.GetTextMetrics(&tm), "GetTextMetrics"); + CHECK(tm.tmHeight > 8 && tm.tmAscent + tm.tmDescent == tm.tmHeight && tm.tmAveCharWidth > 2, + "metrics h=%d a=%d d=%d ave=%d", tm.tmHeight, tm.tmAscent, tm.tmDescent, tm.tmAveCharWidth); + CSize hello = c.dc.GetTextExtent("Hello"); + CSize hello2 = c.dc.GetTextExtent("HelloHello"); + CHECK(hello.cy == tm.tmHeight && hello.cx > 10, "extent %dx%d", hello.cx, hello.cy); + CHECK(std::abs(hello2.cx - 2 * hello.cx) <= 2, "extent additivity %d vs %d", hello2.cx, hello.cx); + CHECK(c.dc.GetTextExtent("", 0).cx == 0, "empty extent"); + + c.dc.SetTextAlign(TA_LEFT | TA_BASELINE); + c.dc.TextOut(10, 40, "HHH", 3); + Box b = c.DarkBox(0, 0, 100, 60); + CHECK(!b.Empty() && b.bottom == 39, "baseline: glyph bottom at y-1 (%d)", b.bottom); + CHECK(b.left >= 10 && b.left <= 12, "TA_LEFT starts at x (%d)", b.left); + + c.dc.SetTextAlign(TA_LEFT | TA_TOP); + c.dc.TextOut(110, 10, "HHH", 3); + b = c.DarkBox(100, 0, 200, 60); + CHECK(!b.Empty() && b.top >= 10 && b.top <= 10 + tm.tmInternalLeading + 4, "TA_TOP (%d)", b.top); + int capTop = b.top - 10; + + c.dc.SetTextAlign(TA_RIGHT | TA_TOP); + c.dc.TextOut(300, 10, "HHH", 3); + b = c.DarkBox(200, 0, 320, 60); + CHECK(!b.Empty() && b.right <= 299 && b.right >= 295, "TA_RIGHT ends at x (%d)", b.right); + + c.dc.SetTextAlign(TA_CENTER | TA_BOTTOM); + c.dc.TextOut(160, 90, "HHHH", 4); + b = c.DarkBox(100, 60, 220, 100); + CHECK(!b.Empty() && std::abs((b.left + b.right) / 2 - 160) <= 2, "TA_CENTER (%d..%d)", b.left, b.right); + CHECK(b.bottom < 90 && b.bottom >= 90 - tm.tmDescent - 2, "TA_BOTTOM (%d)", b.bottom); + + c.dc.SetTextAlign(TA_LEFT | TA_TOP); + c.dc.SetBkMode(OPAQUE); + c.dc.SetBkColor(kYellow); + c.dc.TextOut(10, 60, "Opaque", 6); + CSize op = c.dc.GetTextExtent("Opaque"); + CHECK(Near(c.Px(10, 60), kYellow) && Near(c.Px(10 + op.cx - 1, 60 + tm.tmHeight - 1), kYellow), + "opaque text background box"); + CHECK(c.Px(10, 60 + tm.tmHeight) == kWhite && c.Px(10 + op.cx, 60) == kWhite, "opaque box size"); + c.dc.SetBkMode(TRANSPARENT); + + c.dc.MoveTo(10, 100); + c.dc.SetTextAlign(TA_UPDATECP); + c.dc.TextOut(0, 0, "ab", 2); + CHECK(c.dc.GetCurrentPosition().x == 10 + c.dc.GetTextExtent("ab").cx, "TA_UPDATECP advances"); + c.dc.SetTextAlign(TA_LEFT | TA_TOP); + + CRect r(0, 0, 0, 0); + int hgt = c.dc.DrawText("Hello World", -1, &r, DT_SINGLELINE | DT_CALCRECT); + CHECK(hgt == tm.tmHeight && r.Height() == tm.tmHeight && r.Width() == c.dc.GetTextExtent("Hello World").cx, + "DT_CALCRECT single line (%d, %dx%d)", hgt, r.Width(), r.Height()); + r.SetRect(0, 0, 60, 0); + hgt = c.dc.DrawText("aaa bbb ccc ddd eee", -1, &r, DT_WORDBREAK | DT_CALCRECT); + CHECK(hgt >= 2 * tm.tmHeight && hgt % tm.tmHeight == 0 && r.right <= 60, "DT_WORDBREAK wraps (%d, right %d)", hgt, + r.right); + r.SetRect(0, 0, 200, 0); + hgt = c.dc.DrawText("a\nb\r\nc", -1, &r, DT_CALCRECT); + CHECK(hgt == 3 * tm.tmHeight, "line breaks (%d)", hgt); + r.SetRect(0, 0, 0, 0); + c.dc.DrawText("&File", -1, &r, DT_SINGLELINE | DT_CALCRECT); + CHECK(r.Width() == c.dc.GetTextExtent("File").cx, "prefix removed (%d)", r.Width()); + r.SetRect(0, 0, 0, 0); + c.dc.DrawText("&File", -1, &r, DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX); + CHECK(r.Width() == c.dc.GetTextExtent("&File").cx, "DT_NOPREFIX keeps '&'"); + r.SetRect(0, 0, 0, 0); + c.dc.DrawText("a\tb", -1, &r, DT_SINGLELINE | DT_CALCRECT | DT_EXPANDTABS); + CHECK(std::abs(r.Width() - (8 * tm.tmAveCharWidth + c.dc.GetTextExtent("b").cx)) <= 2, "DT_EXPANDTABS (%d)", + r.Width()); + + CRect cr(10, 120, 190, 160); + c.dc.FrameRect(&cr, CBrush::FromHandle(::GetStockObject(GRAY_BRUSH))); + int ret = c.dc.DrawText("Centered", -1, &cr, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + b = c.DarkBox(11, 121, 189, 159); + CHECK(!b.Empty() && std::abs((b.left + b.right) / 2 - 100) <= 2, "DT_CENTER (%d..%d)", b.left, b.right); + CHECK(std::abs((b.top + b.bottom) / 2 - 140) <= 4, "DT_VCENTER (%d..%d)", b.top, b.bottom); + CHECK(ret == (40 - tm.tmHeight) / 2 + tm.tmHeight, "DT_VCENTER return value (%d)", ret); + + CRect rr(200, 120, 300, 140); + c.dc.DrawText("Right", -1, &rr, DT_RIGHT | DT_SINGLELINE); + b = c.DarkBox(200, 120, 320, 140); + CHECK(!b.Empty() && b.right >= 296 && b.right <= 299, "DT_RIGHT (%d)", b.right); + + CRect er(10, 170, 70, 190); + c.dc.DrawText("abcdefghijklmnopqrstuvwxyz", -1, &er, DT_SINGLELINE | DT_END_ELLIPSIS); + b = c.DarkBox(0, 170, 320, 190); + CHECK(!b.Empty() && b.right < 70, "DT_END_ELLIPSIS fits (%d)", b.right); + CRect clipR(80, 170, 120, 190); + c.dc.DrawText("abcdefghijklmnopqrstuvwxyz", -1, &clipR, DT_SINGLELINE); + b = c.DarkBox(75, 170, 320, 190); + CHECK(!b.Empty() && b.right < 120, "DrawText clips to the rectangle (%d)", b.right); + CRect noclip(130, 170, 150, 190); + c.dc.DrawText("abcdefghij", -1, &noclip, DT_SINGLELINE | DT_NOCLIP); + b = c.DarkBox(125, 170, 320, 190); + CHECK(b.right > 150, "DT_NOCLIP draws outside (%d)", b.right); + + CRect pr(10, 200, 100, 220); + c.dc.DrawText("&Underline", -1, &pr, DT_SINGLELINE); + int under = 0; + for (int x = 10; x < 10 + c.dc.GetTextExtent("U").cx; ++x) + if (Dark(c.Px(x, 200 + tm.tmAscent + 1))) + ++under; + CHECK(under >= 3, "mnemonic underline (%d)", under); + + CRect wr(120, 200, 200, 260); + c.dc.DrawText("word wrapped text in a box", -1, &wr, DT_WORDBREAK | DT_CENTER); + b = c.DarkBox(115, 200, 320, 260); + CHECK(b.right < 200 && b.bottom > 200 + tm.tmHeight, "word wrap drawing (%d,%d)", b.right, b.bottom); + + c.Save("text"); + (void)capTop; +} + +void TestFonts() { + Canvas c(420, 260); + c.dc.SetBkMode(TRANSPARENT); + CFont arial; + arial.CreateFont(-20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); + CFont* old = c.dc.SelectObject(&arial); + TEXTMETRIC tm; + c.dc.GetTextMetrics(&tm); + CHECK(std::abs(tm.tmHeight - tm.tmInternalLeading - 20) <= 1, "negative lfHeight is the em height (%d-%d)", + tm.tmHeight, tm.tmInternalLeading); + c.dc.TextOut(10, 10, "Arial -20: The quick brown fox", 30); + + CFont cell; + cell.CreateFont(30, 0, 0, 0, FW_BOLD, TRUE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, "Times New Roman"); + c.dc.SelectObject(&cell); + c.dc.GetTextMetrics(&tm); + CHECK(std::abs(tm.tmHeight - 30) <= 1, "positive lfHeight is the cell height (%d)", tm.tmHeight); + CHECK(tm.tmWeight == FW_BOLD && tm.tmItalic, "weight/italic in metrics"); + c.dc.TextOut(10, 40, "Times 30 bold italic", 20); + + CFont courier; + courier.CreatePointFont(100, "Courier New"); + LOGFONT lf; + courier.GetLogFont(&lf); + CHECK(lf.lfHeight == -13, "CreatePointFont(100) -> lfHeight -13 (%d)", lf.lfHeight); + c.dc.SelectObject(&courier); + CHECK(c.dc.GetTextExtent("iiii").cx == c.dc.GetTextExtent("WWWW").cx, "Courier New maps to a monospace font"); + c.dc.GetTextMetrics(&tm); + CHECK((tm.tmPitchAndFamily & 1) == 0, "TMPF_FIXED_PITCH clear for fixed fonts (%x)", tm.tmPitchAndFamily); + c.dc.TextOut(10, 80, "Courier New 10pt: 0123456789 ABCDEF", 35); + CString face; + c.dc.GetTextFace(face); + CHECK(face == "Courier New", "GetTextFace (%s)", face.GetString()); + + CFont fixedStock; + fixedStock.CreateStockObject(SYSTEM_FIXED_FONT); + LOGFONT slf; + fixedStock.GetLogFont(&slf); + CHECK((slf.lfPitchAndFamily & 3) == FIXED_PITCH, "SYSTEM_FIXED_FONT is fixed pitch"); + CHECK(FontFromHandle(fixedStock).IsFixedWidth(), "SYSTEM_FIXED_FONT wx font is fixed"); + c.dc.SelectObject(&fixedStock); + c.dc.TextOut(10, 100, "SYSTEM_FIXED_FONT", 17); + + LOGFONT gui; + ::GetObject(DefaultGuiFont(), sizeof gui, &gui); + CHECK(strcmp(gui.lfFaceName, "MS Shell Dlg") == 0 && gui.lfHeight < 0, "DEFAULT_GUI_FONT LOGFONT (%s %d)", + gui.lfFaceName, gui.lfHeight); + gui.lfWeight = FW_BOLD; + CFont bold; + bold.CreateFontIndirect(&gui); + CHECK(FontFromHandle(bold).GetWeight() == wxFONTWEIGHT_BOLD, "bold copy of the GUI font"); + CHECK(FontFromHandle(bold).GetFaceName() == FontFromHandle(DefaultGuiFont()).GetFaceName(), + "GUI font face round-trips (%s)", (const char*)FontFromHandle(bold).GetFaceName().utf8_str()); + c.dc.SelectObject(&bold); + c.dc.TextOut(10, 120, "Bold GUI font", 13); + + LOGFONT garbage; + memset(&garbage, 0xCC, sizeof garbage); + garbage.lfWeight = FW_BOLD; + CFont g; + CHECK(g.CreateFontIndirect(&garbage) && FontFromHandle(g).IsOk(), "uninitialized LOGFONT is tolerated"); + + CFont underline; + underline.CreateFont(-16, 0, 0, 0, FW_NORMAL, FALSE, TRUE, TRUE, 0, 0, 0, 0, 0, "Tahoma"); + c.dc.SelectObject(&underline); + c.dc.TextOut(10, 140, "Tahoma underline strikeout", 26); + + CFont unknown; + unknown.CreateFont(15, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "ArialBold"); + c.dc.SelectObject(&unknown); + c.dc.TextOut(10, 165, "ArialBold (unknown face) 15", 27); + + CFont fixedNoFace; + fixedNoFace.CreateFont(0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_RASTER_PRECIS, 0, DEFAULT_QUALITY, + FIXED_PITCH | FF_DONTCARE, nullptr); + CHECK(FontFromHandle(fixedNoFace).IsFixedWidth(), "FIXED_PITCH without a face is monospace"); + c.dc.SelectObject(&fixedNoFace); + c.dc.TextOut(10, 185, "FIXED_PITCH no face", 19); + + c.dc.SetTextColor(RGB(200, 0, 0)); + c.dc.SelectObject(&arial); + c.dc.TextOut(10, 205, "\xC4\xD6\xDC \xE4\xF6\xFC \xDF \x80 (cp1252)", -1); + c.dc.SelectObject(old); + c.Save("fonts"); +} + +void TestBlit() { + Canvas src(40, 40); + src.dc.FillSolidRect(0, 0, 20, 40, kRed); + src.dc.FillSolidRect(20, 0, 20, 40, kBlue); + Canvas d(260, 140); + + d.dc.BitBlt(10, 10, 40, 40, &src.dc, 0, 0, SRCCOPY); + CHECK(d.Px(15, 15) == kRed && d.Px(45, 15) == kBlue && d.Px(50, 15) == kWhite && d.Px(10, 50) == kWhite, + "SRCCOPY (%06x %06x)", d.Px(15, 15), d.Px(45, 15)); + d.dc.BitBlt(60, 10, 40, 40, &src.dc, 0, 0, NOTSRCCOPY); + CHECK(d.Px(65, 15) == RGB(0, 255, 255) && d.Px(95, 15) == kYellow, "NOTSRCCOPY (%06x)", d.Px(65, 15)); + + const COLORREF gray = RGB(128, 128, 128); + d.dc.FillSolidRect(110, 10, 40, 40, gray); + d.dc.BitBlt(110, 10, 40, 40, &src.dc, 0, 0, SRCAND); + CHECK(d.Px(115, 15) == RGB(128, 0, 0) && d.Px(145, 15) == RGB(0, 0, 128), "SRCAND (%06x)", d.Px(115, 15)); + d.dc.FillSolidRect(160, 10, 40, 40, gray); + d.dc.BitBlt(160, 10, 40, 40, &src.dc, 0, 0, SRCPAINT); + CHECK(d.Px(165, 15) == RGB(255, 128, 128), "SRCPAINT (%06x)", d.Px(165, 15)); + d.dc.FillSolidRect(210, 10, 40, 40, gray); + d.dc.BitBlt(210, 10, 40, 40, &src.dc, 0, 0, SRCINVERT); + CHECK(d.Px(215, 15) == RGB(127, 128, 128), "SRCINVERT (%06x)", d.Px(215, 15)); + + CBrush green(kGreen); + d.dc.SelectObject(&green); + d.dc.PatBlt(10, 60, 20, 20, PATCOPY); + d.dc.PatBlt(35, 60, 20, 20, BLACKNESS); + d.dc.FillSolidRect(60, 60, 20, 20, kRed); + d.dc.PatBlt(60, 60, 10, 20, DSTINVERT); + CHECK(d.Px(15, 65) == kGreen && d.Px(40, 65) == kBlack && d.Px(62, 65) == RGB(0, 255, 255) && + d.Px(75, 65) == kRed, + "PatBlt PATCOPY/BLACKNESS/DSTINVERT"); + d.dc.InvertRect(CRect(70, 60, 80, 70)); + CHECK(d.Px(75, 65) == RGB(0, 255, 255), "InvertRect"); + + d.dc.StretchBlt(90, 60, 80, 20, &src.dc, 0, 0, 40, 10, SRCCOPY); + CHECK(d.Px(92, 70) == kRed && d.Px(168, 70) == kBlue && d.Px(130, 79) != kWhite && d.Px(130, 80) == kWhite, + "StretchBlt"); + d.dc.StretchBlt(250, 90, -60, 20, &src.dc, 0, 0, 40, 40, SRCCOPY); + CHECK(d.Px(195, 95) == kBlue && d.Px(245, 95) == kRed, "StretchBlt mirrored (%06x %06x)", d.Px(195, 95), + d.Px(245, 95)); + + Canvas mask(40, 40); + mask.dc.FillSolidRect(10, 10, 20, 20, kRed); + d.dc.FillSolidRect(10, 90, 40, 40, kYellow); + d.dc.TransparentBlt(10, 90, 40, 40, &mask.dc, 0, 0, 40, 40, kWhite); + CHECK(d.Px(12, 92) == kYellow && d.Px(25, 105) == kRed, "TransparentBlt"); + + unsigned char dib[] = {255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0}; + BITMAPINFO bmi; + memset(&bmi, 0, sizeof bmi); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 2; + bmi.bmiHeader.biHeight = 2; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + ::StretchDIBits(d.dc, 60, 90, 2, 2, 0, 0, 2, 2, dib, &bmi, DIB_RGB_COLORS, SRCCOPY); + CHECK(d.Px(60, 90) == kRed && d.Px(61, 90) == kWhite && d.Px(60, 91) == kBlue && d.Px(61, 91) == kGreen, + "bottom-up DIB orientation (%06x %06x %06x %06x)", d.Px(60, 90), d.Px(61, 90), d.Px(60, 91), d.Px(61, 91)); + ::StretchDIBits(d.dc, 70, 90, 20, 20, 0, 0, 2, 2, dib, &bmi, DIB_RGB_COLORS, SRCCOPY); + CHECK(d.Px(75, 95) == kRed && d.Px(85, 105) == kGreen, "StretchDIBits scaled"); + ::SetDIBitsToDevice(d.dc, 95, 90, 2, 2, 0, 0, 0, 2, dib, &bmi, DIB_RGB_COLORS); + CHECK(d.Px(95, 90) == kRed && d.Px(96, 91) == kGreen, "SetDIBitsToDevice"); + d.Save("blit"); +} + +void TestBitmaps() { + const unsigned char bits[] = {0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0, 255, 255, 255, 0, + 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0, 10, 11, 12, 0}; + CBitmap b; + CHECK(b.CreateBitmap(4, 2, 1, 32, bits), "CreateBitmap 32bpp"); + BITMAP bm; + b.GetBitmap(&bm); + CHECK(bm.bmWidth == 4 && bm.bmHeight == 2 && bm.bmBitsPixel == 32 && bm.bmWidthBytes == 16 && bm.bmPlanes == 1, + "GetBitmap %dx%d %dbpp %d", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, bm.bmWidthBytes); + unsigned char back[32]; + CHECK(b.GetBitmapBits(sizeof back, back) == 32 && memcmp(back, bits, 32) == 0, "GetBitmapBits round trip"); + CDC dc; + dc.CreateCompatibleDC(nullptr); + CBitmap* old = dc.SelectObject(&b); + CHECK(dc.GetPixel(0, 0) == kRed && dc.GetPixel(1, 0) == kGreen && dc.GetPixel(3, 0) == kWhite && + dc.GetPixel(0, 1) == RGB(3, 2, 1), + "pixels of a 32bpp DDB (%06x)", dc.GetPixel(0, 0)); + dc.SetPixel(2, 1, kYellow); + unsigned char after[32]; + b.GetBitmapBits(sizeof after, after); + CHECK(after[24] == 0 && after[25] == 255 && after[26] == 255, "GetBitmapBits sees drawing in a selected bitmap"); + unsigned char set[32]; + memset(set, 0x40, sizeof set); + b.SetBitmapBits(sizeof set, set); + CHECK(dc.GetPixel(1, 1) == RGB(0x40, 0x40, 0x40), "SetBitmapBits on a selected bitmap (%06x)", dc.GetPixel(1, 1)); + dc.SelectObject(old); + + const unsigned char mono[] = {0xAA, 0x55}; + CBitmap m; + m.CreateBitmap(16, 1, 1, 1, mono); + m.GetBitmap(&bm); + CHECK(bm.bmBitsPixel == 1 && bm.bmWidthBytes == 2, "monochrome GetBitmap"); + old = dc.SelectObject(&m); + CHECK(dc.GetPixel(0, 0) == kWhite && dc.GetPixel(1, 0) == kBlack && dc.GetPixel(9, 0) == kWhite, + "monochrome bits (1 = white)"); + dc.SelectObject(old); + + CBitmap res; + CHECK(res.LoadBitmap(1), "LoadBitmap through LoadBitmapResource"); + res.GetBitmap(&bm); + CHECK(bm.bmWidth == 4 && bm.bmHeight == 2, "loaded bitmap size"); + old = dc.SelectObject(&res); + CHECK(dc.GetPixel(0, 0) == kRed && dc.GetPixel(3, 1) == kBlue, "loaded bitmap pixels"); + dc.SelectObject(old); + CHECK(!CBitmap().LoadBitmap(2), "missing bitmap"); + + CBitmap other; + other.CreateCompatibleBitmap(&dc, 2, 2); + CDC dc2; + dc2.CreateCompatibleDC(nullptr); + dc.SelectObject(&other); + CHECK(dc2.SelectObject(&other) == nullptr, "a bitmap can be selected into one DC only"); + + HBITMAP h = CreateBitmapHandle(wxBitmap(3, 5, 24)); + CHECK(GetObject(h, sizeof bm, &bm) && bm.bmWidth == 3 && bm.bmHeight == 5, "CreateBitmapHandle"); + CHECK(DeleteObject(h) && !DeleteObject(h), "DeleteObject once"); + CBrush pattern(&res); + CHECK(pattern.m_hObject && BrushFromHandle(pattern).GetStyle() == wxBRUSHSTYLE_STIPPLE, "pattern brush"); +} + +void TestMapping() { + Canvas c(200, 200); + c.dc.SetMapMode(MM_ANISOTROPIC); + c.dc.SetWindowExt(1280, 1280); + c.dc.SetViewportExt(200, -200); + c.dc.SetViewportOrg(0, 200); + CPoint p[2] = {CPoint(0, 0), CPoint(1280, 1280)}; + c.dc.LPtoDP(p, 2); + CHECK(p[0] == CPoint(0, 200) && p[1] == CPoint(200, 0), "LPtoDP (%d,%d) (%d,%d)", p[0].x, p[0].y, p[1].x, p[1].y); + CPoint q(100, 100); + c.dc.DPtoLP(&q); + CHECK(q == CPoint(640, 640), "DPtoLP (%d,%d)", q.x, q.y); + CPen pen(PS_SOLID, 1, kBlack); + CBrush red(kRed); + c.dc.SelectObject(&pen); + c.dc.SelectObject(&red); + c.dc.Rectangle(0, 0, 640, 640); + CSize ext = c.dc.GetTextExtent("Plot"); + CSize dev = ext; + c.dc.LPtoDP(&dev); + CHECK(ext.cx > dev.cx * 5, "text extent in logical units (%d vs %d)", ext.cx, dev.cx); + TEXTMETRIC tm; + c.dc.GetTextMetrics(&tm); + CHECK(tm.tmHeight > 40, "metrics in logical units (%d)", tm.tmHeight); + c.dc.SetBkMode(TRANSPARENT); + c.dc.SetTextAlign(TA_CENTER | TA_BASELINE); + c.dc.TextOut(640, 1100, "Headline", 8); + CPen wide(PS_SOLID, 13, kBlue); + c.dc.SelectObject(&wide); + c.dc.MoveTo(700, 300); + c.dc.LineTo(1200, 300); + c.dc.SelectObject(&pen); + c.dc.SetMapMode(MM_TEXT); + c.dc.SetViewportOrg(0, 0); + CHECK(c.Px(50, 150) == kRed && c.Px(150, 50) == kWhite, "y-up rectangle placement"); + CHECK(c.Px(0, 150) == kBlack && c.Px(99, 150) == kBlack && c.Px(100, 150) == kWhite, "y-up rectangle edges"); + Box b = c.DarkBox(0, 0, 200, 60); + CHECK(!b.Empty() && b.bottom == 27 && std::abs((b.left + b.right) / 2 - 100) <= 2, + "text at a mapped point (%d %d..%d)", b.bottom, b.left, b.right); + int thick = 0; + for (int y = 145; y < 160; ++y) + if (Near(c.Px(150, y), kBlue, 60)) + ++thick; + CHECK(thick == 2, "pen width scales with the mapping (%d)", thick); + c.Save("mapping"); + + CDC m; + m.CreateCompatibleDC(nullptr); + m.SetMapMode(MM_LOMETRIC); + CPoint lm(254, -254); + m.LPtoDP(&lm); + CHECK(lm == CPoint(96, 96), "MM_LOMETRIC (%d,%d)", lm.x, lm.y); + m.SetMapMode(MM_ISOTROPIC); + m.SetWindowExt(100, 100); + m.SetViewportExt(200, 100); + CHECK(m.GetViewportExt() == CSize(100, 100), "MM_ISOTROPIC keeps the aspect ratio"); + m.SetMapMode(MM_TEXT); + m.SetWindowOrg(-10, -10); + CPoint o(0, 0); + m.LPtoDP(&o); + CHECK(o == CPoint(10, 10), "window origin in MM_TEXT"); + CHECK(m.GetDeviceCaps(LOGPIXELSY) == 96, "LOGPIXELSY"); +} + +void TestRegionsAndHandles() { + CRgn a, b, c; + a.CreateRectRgn(0, 0, 10, 10); + b.CreateRectRgn(5, 5, 15, 15); + c.CreateRectRgn(0, 0, 0, 0); + CHECK(c.CombineRgn(&a, &b, RGN_OR) == COMPLEXREGION, "RGN_OR"); + CHECK(c.PtInRegion(12, 12) && !c.PtInRegion(12, 2), "PtInRegion"); + CRect box; + c.GetRgnBox(&box); + CHECK(box == CRect(0, 0, 15, 15), "GetRgnBox"); + CHECK(c.CombineRgn(&a, &b, RGN_AND) == SIMPLEREGION, "RGN_AND"); + c.GetRgnBox(&box); + CHECK(box == CRect(5, 5, 10, 10), "intersection box"); + CHECK(c.CombineRgn(&a, &b, RGN_DIFF) == COMPLEXREGION && !c.PtInRegion(7, 7), "RGN_DIFF"); + c.OffsetRgn(100, 0); + CHECK(c.PtInRegion(101, 1), "OffsetRgn"); + + CGdiObject* t1 = CGdiObject::FromHandle(GetStockObject(BLACK_PEN)); + CGdiObject* t2 = CGdiObject::FromHandle(GetStockObject(BLACK_PEN)); + CHECK(t1 && t1 == t2 && t1->IsKindOf(RUNTIME_CLASS(CPen)), "temporary wrappers are reused and typed"); + CPen perm(PS_SOLID, 1, kRed); + CHECK(CGdiObject::FromHandle(perm.m_hObject) == &perm, "FromHandle returns the permanent object"); + PurgeTemporaryGdiWrappers(); + CHECK(DeleteObject(GetStockObject(WHITE_BRUSH)), "deleting a stock object succeeds"); + + { + CBitmap bmp; + bmp.CreateCompatibleBitmap(nullptr, 10, 10); + CDC memdc; + memdc.CreateCompatibleDC(nullptr); + memdc.SelectObject(&bmp); + ::DeleteDC(memdc); + ::DeleteObject(bmp); + CHECK(memdc.m_hDC == nullptr && bmp.m_hObject == nullptr, "Win32 deletes clear the MFC wrappers"); + } + + Canvas cv(40, 20); + { + CPen temp(PS_SOLID, 1, kRed); + cv.dc.SelectObject(&temp); + } + cv.dc.MoveTo(0, 5); + cv.dc.LineTo(30, 5); + CHECK(cv.Px(10, 5) == kRed, "a pen destroyed while selected stays usable"); + cv.dc.SelectStockObject(BLACK_PEN); + + HDC raw = ::CreateCompatibleDC(nullptr); + CDC* tdc = CDC::FromHandle(raw); + CHECK(tdc && tdc->m_hDC == raw && CDC::FromHandle(raw) == tdc, "temporary CDC"); + ::DeleteDC(raw); + CHECK(tdc->m_hDC == nullptr, "DeleteDC detaches the temporary CDC"); + CDC::DeleteTempMap(); + + CHECK(GetObject(GetStockObject(BLACK_PEN), 0, nullptr) == sizeof(LOGPEN), "GetObject size query"); + LOGBRUSH lb; + CHECK(GetObject(reinterpret_cast(COLOR_WINDOW + 1), sizeof lb, &lb) == sizeof lb && + lb.lbColor == GetSysColor(COLOR_WINDOW), + "system colour brush handle"); +} + +void TestWrapAndColors() { + wxBitmap target(120, 60, 24); + { + wxMemoryDC mdc(target); + mdc.SetBackground(*wxWHITE_BRUSH); + mdc.Clear(); + CDC* cdc = WrapDC(&mdc, nullptr); + cdc->SetTextColor(0xFFFFFFFF); + CHECK(cdc->GetTextColor() == 0xFFFFFFFF, "CTLCOLOR sentinel text colour is preserved"); + cdc->SetBkMode(TRANSPARENT); + CHECK(cdc->GetBkMode() == TRANSPARENT, "bk mode"); + CHECK(CDC::FromHandle(cdc->m_hDC) == cdc, "FromHandle of a wrapped DC"); + CPen pen(PS_SOLID, 1, kBlack); + CBrush br(kRed); + cdc->SelectObject(&pen); + cdc->SelectObject(&br); + cdc->Rectangle(10, 10, 20, 20); + RECT fr{30, 10, 40, 20}; + ::FillRect(cdc->m_hDC, &fr, reinterpret_cast(COLOR_WINDOW + 1)); + RECT er{50, 10, 70, 30}; + cdc->DrawEdge(&er, EDGE_RAISED, BF_RECT | BF_ADJUST); + CHECK(er.left == 52 && er.top == 12 && er.right == 68 && er.bottom == 28, "BF_ADJUST"); + cdc->Draw3dRect(80, 10, 20, 20, kBlue, kGreen); + UnwrapDC(cdc); + } + wxImage img = target.ConvertToImage(); + auto px = [&](int x, int y) { return RGB(img.GetRed(x, y), img.GetGreen(x, y), img.GetBlue(x, y)); }; + CHECK(Near(px(10, 10), kBlack, 2) && Near(px(19, 19), kBlack, 2) && px(20, 20) == kWhite && px(15, 15) == kRed, + "rectangle on a borrowed wx DC"); + CHECK(Near(px(35, 15), GetSysColor(COLOR_WINDOW), 2), "FillRect with (HBRUSH)(COLOR_WINDOW+1)"); + CHECK(Near(px(50, 10), GetSysColor(COLOR_3DLIGHT), 2) && Near(px(69, 29), GetSysColor(COLOR_3DDKSHADOW), 2) && + Near(px(51, 11), GetSysColor(COLOR_3DHILIGHT), 2) && Near(px(68, 28), GetSysColor(COLOR_3DSHADOW), 2), + "DrawEdge colours"); + CHECK(px(80, 10) == kBlue && px(99, 29) == kGreen && px(81, 11) == kWhite, "Draw3dRect"); + target.SaveFile(g_out + "/wrapped.png", wxBITMAP_TYPE_PNG); + + CHECK(BrushFromHandle(GetStockObject(NULL_BRUSH)).GetStyle() == wxBRUSHSTYLE_TRANSPARENT, "NULL_BRUSH"); + CHECK(!BrushFromHandle(nullptr).IsOk(), "null brush handle"); + CHECK(BrushFromHandle(GetSysColorBrush(COLOR_BTNFACE)).GetColour() == ToWxColour(GetSysColor(COLOR_BTNFACE)), + "GetSysColorBrush"); + CHECK(FromWxColour(ToWxColour(RGB(1, 2, 3))) == RGB(1, 2, 3), "colour round trip"); + CHECK(PenFromHandle(GetStockObject(NULL_PEN)).GetStyle() == wxPENSTYLE_TRANSPARENT, "NULL_PEN"); + HFONT fh = FontHandleFor(*wxNORMAL_FONT); + CHECK(fh == FontHandleFor(*wxNORMAL_FONT) && FontFromHandle(fh).IsOk(), "FontHandleFor caches"); +} + +void TestHiDpi() { + wxBitmap hb; + hb.CreateWithDIPSize(wxSize(120, 40), 2.0, 24); + wxMemoryDC hm(hb); + hm.SetBackground(*wxWHITE_BRUSH); + hm.Clear(); + CDC* wrapped = WrapDC(&hm, nullptr); + { + CDC mem; + mem.CreateCompatibleDC(wrapped); + CBitmap cb; + cb.CreateCompatibleBitmap(&mem, 120, 40); + CHECK(BitmapFromHandle(cb)->GetScaleFactor() == 2.0, "compatible bitmap inherits the scale factor"); + BITMAP bm; + cb.GetBitmap(&bm); + CHECK(bm.bmWidth == 120 && bm.bmHeight == 40, "BITMAP reports logical size"); + CBitmap* old = mem.SelectObject(&cb); + mem.FillSolidRect(0, 0, 120, 40, RGB(230, 240, 255)); + mem.FillSolidRect(100, 10, 10, 10, kRed); + CHECK(mem.GetPixel(105, 15) == kRed && mem.GetPixel(110, 15) == RGB(230, 240, 255), + "GetPixel in logical coordinates on a 2x bitmap"); + mem.SetBkMode(TRANSPARENT); + mem.TextOut(4, 10, "HiDPI text", 10); + wrapped->BitBlt(0, 0, 120, 40, &mem, 0, 0, SRCCOPY); + mem.SelectObject(old); + } + UnwrapDC(wrapped); + hm.SelectObject(wxNullBitmap); + CHECK(hb.GetWidth() == 240, "physical size %d", hb.GetWidth()); + wxImage img = hb.ConvertToImage(); + CHECK(img.GetRed(210, 30) == 255 && img.GetGreen(210, 30) == 0, "blit of a 2x bitmap to a 2x DC"); + hb.SaveFile(g_out + "/hidpi.png", wxBITMAP_TYPE_PNG); +} + +bool WaitFor(const std::function& done) { + for (int i = 0; i < 200 && !done(); ++i) { + wxYield(); + wxMilliSleep(10); + } + return done(); +} + +void TestWindows() { + auto* frame = new wxFrame(nullptr, wxID_ANY, "mfcwx gdi test", wxPoint(50, 50), wxSize(320, 240)); + auto* panel = new wxPanel(frame, wxID_ANY, wxPoint(0, 0), wxSize(300, 200)); + HWND hwnd = ToHwnd(panel); + + HDC h = ::GetDC(hwnd); + CDC* cdc = CDC::FromHandle(h); + CHECK(cdc && cdc->GetTextExtent("Measure").cx > 10, "measuring through GetDC outside paint"); + TEXTMETRIC tm; + CHECK(cdc->GetTextMetrics(&tm) && tm.tmHeight > 8, "metrics through GetDC"); + cdc->FillSolidRect(10, 10, 30, 20, kRed); + ::ReleaseDC(hwnd, h); +#ifdef __WXOSX__ + CHECK(HasClientDCOverlay(panel), "client DC drawing goes to the overlay on macOS"); +#endif + if (HasClientDCOverlay(panel)) { + wxBitmap out(panel->GetClientSize().x, panel->GetClientSize().y, 24); + { + wxMemoryDC md(out); + md.SetBackground(*wxWHITE_BRUSH); + md.Clear(); + PaintClientDCOverlay(panel, md); + } + wxImage img = out.ConvertToImage(); + CHECK(img.GetRed(15, 15) == 255 && img.GetGreen(15, 15) == 0 && img.GetRed(45, 15) == 255 && + img.GetGreen(45, 15) == 255, + "overlay content"); + ClearClientDCOverlay(panel); + CHECK(!HasClientDCOverlay(panel), "overlay cleared"); + } + + HDC leaked = ::GetDC(hwnd); + bool bridged = false, borrowed = false, ownSession = false, painted = false; + int pass = 0; + panel->Bind(wxEVT_PAINT, [&](wxPaintEvent&) { + ++pass; + if (pass == 1) { + wxPaintDC pdc(panel); + CDC* w = WrapDC(&pdc, panel); + PAINTSTRUCT ps; + HDC p = ::BeginPaint(hwnd, &ps); + HDC g = ::GetDC(hwnd); + bridged = DCFromHandle(p)->Target(true) == &pdc; + borrowed = DCFromHandle(g)->Target(true) == &pdc; + CDC::FromHandle(g)->FillSolidRect(0, 0, 20, 20, kBlue); + ::EndPaint(hwnd, &ps); + HDC inPaintLeak = ::GetDC(hwnd); + CDC::FromHandle(inPaintLeak)->FillSolidRect(20, 0, 20, 20, kGreen); + PaintClientDCOverlay(panel, pdc); + UnwrapDC(w); + CHECK(DCFromHandle(inPaintLeak)->dc == nullptr, "leaked paint DC detached at UnwrapDC"); + ::ReleaseDC(hwnd, g); + } else { + PAINTSTRUCT ps; + HDC p = ::BeginPaint(hwnd, &ps); + HDC g = ::GetDC(hwnd); + wxDC* pd = DCFromHandle(p)->Target(true); + ownSession = pd && DCFromHandle(g)->Target(true) == pd; + CDC::FromHandle(g)->FillSolidRect(0, 0, 20, 20, kRed); + ::ReleaseDC(hwnd, g); + ::EndPaint(hwnd, &ps); + painted = true; + } + }); + { + frame->Show(); + panel->Refresh(); + bool got = WaitFor([&] { return pass >= 1; }); + if (got) { + CHECK(bridged, "CPaintDC draws through the bridge's wxPaintDC"); + CHECK(borrowed, "GetDC inside paint borrows the paint DC"); + panel->Refresh(); + WaitFor([&] { return painted; }); + CHECK(painted && ownSession, "BeginPaint without bridge shares one wxPaintDC with GetDC"); + } else { + printf("SKIP paint tests: no paint event was delivered\n"); + } + } + frame->Destroy(); + wxTheApp->ProcessIdle(); + WaitFor([] { return false; }); + CDC* l = CDC::FromHandle(leaked); + CHECK(l && l->GetTextExtent("after destroy").cx > 10, "a GetDC handle survives its window"); + l->FillSolidRect(0, 0, 10, 10, kRed); + ::ReleaseDC(nullptr, leaked); + PurgeTemporaryGdiWrappers(); +} + +} // namespace + +class TestApp : public wxApp { +public: + bool OnInit() override { + for (int i = 1; i < argc; ++i) { + wxString a = argv[i]; + if (a == "--no-window") + g_windowTests = false; + else + g_out = a; + } + wxInitAllImageHandlers(); + wxFileName::Mkdir(g_out, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); + CallAfter([this] { + TestShapes(); + TestText(); + TestFonts(); + TestBlit(); + TestBitmaps(); + TestMapping(); + TestRegionsAndHandles(); + TestWrapAndColors(); + TestHiDpi(); + if (g_windowTests) + TestWindows(); + PurgeTemporaryGdiWrappers(); + printf("%d checks, %d failures; images in %s\n", g_checks, g_failures, (const char*)g_out.utf8_str()); + ExitMainLoop(); + }); + return true; + } + int OnRun() override { + wxApp::OnRun(); + return g_failures ? 1 : 0; + } +}; + +wxIMPLEMENT_APP_NO_MAIN(TestApp); + +int main(int argc, char** argv) { + int rc = wxEntry(argc, argv); + return g_failures ? 1 : rc; +} diff --git a/port/mfcwx/tests/runtime_stubs.cpp b/port/mfcwx/tests/runtime_stubs.cpp new file mode 100644 index 000000000..34cfe52a0 --- /dev/null +++ b/port/mfcwx/tests/runtime_stubs.cpp @@ -0,0 +1,38 @@ +// Stand-ins for GUI-side symbols so the runtime tests link without the window/app parts. + +#include "afxwin.h" + +#include +#include + +CRuntimeClass CCmdTarget::classCCmdTarget = {"CCmdTarget", sizeof(CCmdTarget), 0xFFFF, nullptr, + &CObject::GetThisClass, nullptr}; +static AFX_CLASSINIT _init_CCmdTarget(&CCmdTarget::classCCmdTarget); +CRuntimeClass* CCmdTarget::GetThisClass() { return &CCmdTarget::classCCmdTarget; } +CRuntimeClass* CCmdTarget::GetRuntimeClass() const { return &CCmdTarget::classCCmdTarget; } +BOOL CCmdTarget::OnCmdMsg(UINT, int, void*, AFX_CMDHANDLERINFO*) { return FALSE; } +const AFX_MSGMAP* CCmdTarget::GetThisMessageMap() { return nullptr; } +const AFX_MSGMAP* CCmdTarget::GetMessageMap() const { return nullptr; } + +CWinApp* AFXAPI AfxGetApp() { return nullptr; } + +int AFXAPI AfxMessageBox(const char* lpszText, UINT, UINT) { + fprintf(stderr, "AfxMessageBox: %s\n", lpszText ? lpszText : ""); + return IDOK; +} + +int AFXAPI AfxMessageBox(UINT nIDPrompt, UINT, UINT) { + fprintf(stderr, "AfxMessageBox: #%u\n", nIDPrompt); + return IDOK; +} + +namespace mfcwx { + +bool LoadResourceString(UINT, std::string&) { return false; } + +std::string GetDataDirectory() { + char buf[4096]; + return getcwd(buf, sizeof buf) ? std::string(buf) : std::string("/"); +} + +} // namespace mfcwx diff --git a/port/mfcwx/tests/runtime_tests.cpp b/port/mfcwx/tests/runtime_tests.cpp new file mode 100644 index 000000000..8cf9b7774 --- /dev/null +++ b/port/mfcwx/tests/runtime_tests.cpp @@ -0,0 +1,1066 @@ +// Tests of the non-GUI runtime of mfcwx (paths, files, archives, profiles, registry, threads, +// processes, CRT and Win32 helpers). + +#include + +#include "afxmt.h" +#include "afxole.h" +#include "afxwin.h" +#include "process.h" +#include "runtime.h" + +#include +#include +#include + +#include +#include +#include + +namespace { + +int g_checks = 0; +int g_failures = 0; + +#define CHECK(cond) \ + do { \ + ++g_checks; \ + if (!(cond)) { \ + ++g_failures; \ + fprintf(stderr, "FAILED %s:%d: %s\n", __FILE__, __LINE__, #cond); \ + } \ + } while (0) + +#define CHECK_EQ_STR(a, b) \ + do { \ + ++g_checks; \ + std::string va_ = (a), vb_ = (b); \ + if (va_ != vb_) { \ + ++g_failures; \ + fprintf(stderr, "FAILED %s:%d: %s == %s (\"%s\" vs \"%s\")\n", __FILE__, __LINE__, #a, #b, \ + va_.c_str(), vb_.c_str()); \ + } \ + } while (0) + +std::string g_root; // native scratch directory +std::string g_appRoot; // the same in application form + +std::string Native(const std::string& name) { return g_root + "/" + name; } +std::string App(const std::string& name) { return g_appRoot + "\\" + name; } + +void WriteRaw(const std::string& native, const std::string& data) { + FILE* f = ::mfcwx_fopen(native.c_str(), "wb"); + if (f) { + fwrite(data.data(), 1, data.size(), f); + fclose(f); + } +} + +std::string ReadRaw(const std::string& native) { + std::string data; + FILE* f = ::mfcwx_fopen(native.c_str(), "rb"); + if (!f) + return data; + char buf[4096]; + size_t n; + while ((n = fread(buf, 1, sizeof buf, f)) > 0) + data.append(buf, n); + fclose(f); + return data; +} + +void TestPaths() { + CHECK_EQ_STR(mfcwx::NativePath("C:\\dir\\sub\\file.txt"), "/dir/sub/file.txt"); + CHECK_EQ_STR(mfcwx::NativePath("rel\\file.txt"), "rel/file.txt"); + CHECK_EQ_STR(mfcwx::AppPath("/Users/x/a.txt"), "\\Users\\x\\a.txt"); + mfcwx::SetAnsiCodePage(1250); + std::string utf8 = "/tmp/za\xC5\xBC\xC3\xB3\xC5\x82\xC4\x87"; + std::string app = mfcwx::AppPath(utf8.c_str()); + CHECK_EQ_STR(app, "\\tmp\\za\xBF\xF3\xB3\xE6"); + CHECK_EQ_STR(mfcwx::NativePath(app.c_str()), utf8); + mfcwx::SetAnsiCodePage(1252); + + char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; + _splitpath("C:\\dir\\sub\\file.tar.gz", drive, dir, fname, ext); + CHECK_EQ_STR(drive, "C:"); + CHECK_EQ_STR(dir, "\\dir\\sub\\"); + CHECK_EQ_STR(fname, "file.tar"); + CHECK_EQ_STR(ext, ".gz"); + _splitpath("\\Users\\x\\noext", drive, dir, fname, ext); + CHECK_EQ_STR(drive, ""); + CHECK_EQ_STR(dir, "\\Users\\x\\"); + CHECK_EQ_STR(fname, "noext"); + CHECK_EQ_STR(ext, ""); + _splitpath("plain.txt", drive, dir, fname, ext); + CHECK_EQ_STR(dir, ""); + CHECK_EQ_STR(fname, "plain"); + char path[_MAX_PATH]; + _makepath(path, "", "\\Users\\x", "name", "txt"); + CHECK_EQ_STR(path, "\\Users\\x\\name.txt"); + + char cwd[1024]; + CHECK(_getcwd(cwd, sizeof cwd) != nullptr); + CHECK(cwd[0] == '\\'); + CHECK(strchr(cwd, '/') == nullptr); + DWORD n = GetCurrentDirectory(sizeof cwd, cwd); + CHECK(n == strlen(cwd)); + CHECK(GetCurrentDirectory(2, cwd) > 2); + + char full[1024]; + char* filePart = nullptr; + GetFullPathName("a\\..\\b\\c.txt", sizeof full, full, &filePart); + char expected[1024]; + _getcwd(expected, sizeof expected); + CHECK_EQ_STR(full, std::string(expected) + "\\b\\c.txt"); + CHECK(filePart && strcmp(filePart, "c.txt") == 0); + char* fp = _fullpath(nullptr, "x\\y", 0); + CHECK_EQ_STR(fp, std::string(expected) + "\\x\\y"); + free(fp); + + char temp[1024]; + DWORD t = GetTempPath(sizeof temp, temp); + CHECK(t > 0 && temp[t - 1] == '\\'); + struct stat st; + CHECK(stat(mfcwx::NativePath(temp).c_str(), &st) == 0 && S_ISDIR(st.st_mode)); + + mkdir(Native("CaseDir").c_str(), 0755); + WriteRaw(Native("CaseDir/MixedCase.TXT"), "x"); + CHECK(GetFileAttributes(App("casedir\\mixedcase.txt").c_str()) != INVALID_FILE_ATTRIBUTES); + CHECK(_access(App("CASEDIR\\MIXEDCASE.txt").c_str(), 0) == 0); + CHECK((GetFileAttributes(App("CaseDir").c_str()) & FILE_ATTRIBUTE_DIRECTORY) != 0); + + char exe[1024]; + DWORD len = GetModuleFileName(nullptr, exe, sizeof exe); + CHECK(len > 0 && exe[0] == '\\'); + CHECK(strstr(exe, "mfcwx_runtime_tests") != nullptr); + CHECK(strncmp(GetCommandLine(), "\\", 1) == 0 || GetCommandLine()[0] == '"'); +} + +void TestFiles() { + std::string name = App("data.bin"); + { + CFile f; + CFileException e; + CHECK(f.Open(name.c_str(), CFile::modeCreate | CFile::modeWrite, &e)); + const char data[] = "0123456789"; + f.Write(data, 10); + CHECK(f.GetLength() == 10); + CHECK(f.GetFileName() == "data.bin"); + CHECK(f.GetFileTitle() == "data"); + CHECK(f.GetFilePath() == name.c_str()); + f.Close(); + } + { + CFile f(name.c_str(), CFile::modeRead); + char buf[16] = {}; + f.Seek(3, CFile::begin); + CHECK(f.Read(buf, 4) == 4); + CHECK_EQ_STR(buf, "3456"); + CHECK(f.GetPosition() == 7); + CHECK(f.Read(buf, 16) == 3); + CFileStatus status; + CHECK(f.GetStatus(status)); + CHECK(status.m_size == 10); + } + { + CFile f(name.c_str(), CFile::modeReadWrite | CFile::modeCreate | CFile::modeNoTruncate); + CHECK(f.GetLength() == 10); + f.SeekToEnd(); + f.Write("AB", 2); + f.SetLength(11); + } + CHECK_EQ_STR(ReadRaw(Native("data.bin")), "0123456789A"); + + CFile missing; + CFileException e; + CHECK(!missing.Open(App("missing.bin").c_str(), CFile::modeRead, &e)); + CHECK(e.m_cause == CFileException::fileNotFound); + bool thrown = false; + try { + CFile f(App("missing.bin").c_str(), CFile::modeRead); + } catch (CFileException* ex) { + thrown = ex->m_cause == CFileException::fileNotFound; + char msg[256]; + ex->GetErrorMessage(msg, sizeof msg); + CHECK(strstr(msg, "was not found") != nullptr); + ex->Delete(); + } + CHECK(thrown); + + CFileStatus st; + CHECK(CFile::GetStatus(name.c_str(), st)); + CHECK(st.m_size == 11); + CFile::Rename(name.c_str(), App("renamed.bin").c_str()); + CHECK(!CFile::GetStatus(name.c_str(), st)); + CFile::Remove(App("renamed.bin").c_str()); + CHECK(!CFile::GetStatus(App("renamed.bin").c_str(), st)); + thrown = false; + try { + CFile::Remove(App("renamed.bin").c_str()); + } catch (CFileException* ex) { + thrown = true; + ex->Delete(); + } + CHECK(thrown); + + WriteRaw(Native("crlf.txt"), "first line\r\nsecond\r\n\r\nlast"); + { + CStdioFile f; + CHECK(f.Open(App("crlf.txt").c_str(), CFile::modeRead)); + CString line; + CHECK(f.ReadString(line) && line == "first line"); + CHECK(f.ReadString(line) && line == "second"); + CHECK(f.ReadString(line) && line.IsEmpty()); + CHECK(f.ReadString(line) && line == "last"); + CHECK(!f.ReadString(line)); + f.SeekToBegin(); + char buf[64]; + CHECK(f.ReadString(buf, sizeof buf) != nullptr); + CHECK_EQ_STR(buf, "first line\n"); + } + { + CStdioFile f(App("out.txt").c_str(), CFile::modeCreate | CFile::modeWrite | CFile::typeText); + f.WriteString("alpha\n"); + f.WriteString("beta"); + } + CHECK_EQ_STR(ReadRaw(Native("out.txt")), "alpha\nbeta"); + + CMemFile mem; + mem.Write("hello", 5); + mem.Write(" world", 6); + CHECK(mem.GetLength() == 11); + mem.SeekToBegin(); + char buf[16] = {}; + CHECK(mem.Read(buf, 5) == 5); + CHECK_EQ_STR(buf, "hello"); + mem.SetLength(3); + CHECK(mem.GetLength() == 3 && mem.GetPosition() == 3); + + HANDLE h = CreateFile(App("api.bin").c_str(), GENERIC_WRITE | GENERIC_READ, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); + CHECK(h != INVALID_HANDLE_VALUE); + DWORD written = 0; + CHECK(WriteFile(h, "abcdef", 6, &written, nullptr) && written == 6); + CHECK(SetFilePointer(h, 2, nullptr, FILE_BEGIN) == 2); + char rb[8] = {}; + DWORD read = 0; + CHECK(ReadFile(h, rb, 3, &read, nullptr) && read == 3); + CHECK_EQ_STR(rb, "cde"); + CHECK(GetFileSize(h, nullptr) == 6); + FILETIME ftWrite; + CHECK(GetFileTime(h, nullptr, nullptr, &ftWrite)); + CTime written_at(ftWrite); + CHECK(llabs(static_cast(written_at.GetTime() - time(nullptr))) < 60); + CHECK(CloseHandle(h)); + CHECK(!CloseHandle(h)); + CHECK(CreateFile(App("api.bin").c_str(), GENERIC_READ, 0, nullptr, CREATE_NEW, 0, nullptr) == INVALID_HANDLE_VALUE); + CHECK(GetLastError() == 80); + + CHECK(CopyFile(App("api.bin").c_str(), App("copy.bin").c_str(), TRUE)); + CHECK(!CopyFile(App("api.bin").c_str(), App("copy.bin").c_str(), TRUE)); + CHECK(!MoveFile(App("api.bin").c_str(), App("copy.bin").c_str())); + CHECK(MoveFileEx(App("api.bin").c_str(), App("copy.bin").c_str(), MOVEFILE_REPLACE_EXISTING)); + CHECK(GetFileAttributes(App("api.bin").c_str()) == INVALID_FILE_ATTRIBUTES); + CHECK(GetLastError() == ERROR_FILE_NOT_FOUND); + CHECK(SetFileAttributes(App("copy.bin").c_str(), FILE_ATTRIBUTE_READONLY)); + CHECK(GetFileAttributes(App("copy.bin").c_str()) & FILE_ATTRIBUTE_READONLY); + CHECK(SetFileAttributes(App("copy.bin").c_str(), FILE_ATTRIBUTE_NORMAL)); + CHECK(DeleteFile(App("copy.bin").c_str())); + CHECK(CreateDirectory(App("newdir").c_str(), nullptr)); + CHECK(!CreateDirectory(App("newdir").c_str(), nullptr) && GetLastError() == ERROR_ALREADY_EXISTS); + CHECK(RemoveDirectory(App("newdir").c_str())); + + char tmpName[MAX_PATH]; + UINT u = GetTempFileName(g_appRoot.c_str(), "tst", 0, tmpName); + CHECK(u != 0); + CHECK(strncmp(tmpName, g_appRoot.c_str(), g_appRoot.size()) == 0); + CHECK(GetFileAttributes(tmpName) != INVALID_FILE_ATTRIBUTES); + DeleteFile(tmpName); + + FILE* f = fopen(App("fopen.txt").c_str(), "wt"); + CHECK(f != nullptr); + if (f) { + fputs("text", f); + fclose(f); + } + CHECK(rename(App("fopen.txt").c_str(), App("fopen2.txt").c_str()) == 0); + CHECK(remove(App("fopen2.txt").c_str()) == 0); +} + +void TestFind() { + mkdir(Native("find").c_str(), 0755); + WriteRaw(Native("find/a.txt"), "1"); + WriteRaw(Native("find/b.TXT"), "22"); + WriteRaw(Native("find/c.dat"), "333"); + WriteRaw(Native("find/noext"), "4"); + struct _finddata_t fd; + intptr_t h = _findfirst(App("find\\*.txt").c_str(), &fd); + CHECK(h != -1); + std::vector names; + if (h != -1) { + do + names.push_back(fd.name); + while (_findnext(h, &fd) == 0); + CHECK(_findclose(h) == 0); + } + CHECK(names.size() == 2); + CHECK(names.size() == 2 && names[0] == "a.txt" && names[1] == "b.TXT"); + CHECK(_findfirst(App("find\\*.none").c_str(), &fd) == -1); + + WIN32_FIND_DATA wfd; + HANDLE fh = FindFirstFile(App("find\\*.*").c_str(), &wfd); + CHECK(fh != INVALID_HANDLE_VALUE); + int count = 0; + bool dots = false; + if (fh != INVALID_HANDLE_VALUE) { + do { + ++count; + if (strcmp(wfd.cFileName, ".") == 0) + dots = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + if (strcmp(wfd.cFileName, "c.dat") == 0) + CHECK(wfd.nFileSizeLow == 3); + } while (FindNextFile(fh, &wfd)); + CHECK(GetLastError() == ERROR_NO_MORE_FILES); + CHECK(FindClose(fh)); + } + CHECK(count == 6); + CHECK(dots); + fh = FindFirstFile(App("find\\*.").c_str(), &wfd); + CHECK(fh != INVALID_HANDLE_VALUE); + std::vector noExt; + if (fh != INVALID_HANDLE_VALUE) { + do + noExt.push_back(wfd.cFileName); + while (FindNextFile(fh, &wfd)); + FindClose(fh); + } + CHECK(noExt.size() == 3 && noExt[0] == "." && noExt[1] == ".." && noExt[2] == "noext"); + + CFileFind finder; + int files = 0; + BOOL more = finder.FindFile(App("find\\*.dat").c_str()); + while (more) { + more = finder.FindNextFile(); + ++files; + CHECK(finder.GetFileName() == "c.dat"); + CHECK(finder.GetFilePath() == App("find\\c.dat").c_str()); + CHECK(finder.GetRoot() == App("find\\").c_str()); + CHECK(finder.GetLength() == 3); + CHECK(!finder.IsDirectory() && !finder.IsDots()); + } + CHECK(files == 1); +} + +void TestArchive() { + CString shortStr = "abc"; + CString longStr(static_cast('x'), 300); + CString hugeStr(static_cast('y'), 70000); + { + CFile f(App("archive.bin").c_str(), CFile::modeCreate | CFile::modeWrite); + CArchive ar(&f, CArchive::store); + ar << shortStr << longStr << hugeStr; + ar << static_cast(7) << static_cast(0x1234) << static_cast(-5) << static_cast(0xDEADBEEF); + ar << 3.25 << static_cast(-1234567890123LL) << (int)42; + ar.WriteCount(5); + ar.WriteCount(70000); + CStringArray arr; + arr.Add("one"); + arr.Add("two"); + arr.Serialize(ar); + CStringArray* obj = new CStringArray; + obj->Add("serialized"); + ar << obj; + ar << obj; + ar.WriteObject(nullptr); + ar.WriteString("text line\r\n"); + ar.Close(); + delete obj; + } + std::string raw = ReadRaw(Native("archive.bin")); + CHECK(raw.size() > 8 && raw.substr(0, 4) == "\x03" "abc"); + CHECK(static_cast(raw[4]) == 0xFF && static_cast(raw[5]) == 0x2C && + static_cast(raw[6]) == 0x01); + { + CFile f(App("archive.bin").c_str(), CFile::modeRead); + CArchive ar(&f, CArchive::load); + CString a, b, c; + ar >> a >> b >> c; + CHECK(a == shortStr); + CHECK(b == longStr); + CHECK(c == hugeStr); + BYTE by; + WORD w; + LONG l; + DWORD dw; + double d; + LONGLONG ll; + int i; + ar >> by >> w >> l >> dw >> d >> ll >> i; + CHECK(by == 7 && w == 0x1234 && l == -5 && dw == 0xDEADBEEF && d == 3.25 && ll == -1234567890123LL && i == 42); + CHECK(ar.ReadCount() == 5); + CHECK(ar.ReadCount() == 70000); + CStringArray arr; + arr.Serialize(ar); + CHECK(arr.GetSize() == 2 && arr[0] == "one" && arr[1] == "two"); + CStringArray* first = nullptr; + CStringArray* second = nullptr; + ar >> first >> second; + CHECK(first != nullptr && first == second); + CHECK(first && first->GetSize() == 1 && first->GetAt(0) == "serialized"); + CHECK(first && first->IsKindOf(RUNTIME_CLASS(CStringArray))); + CObject* none = ar.ReadObject(nullptr); + CHECK(none == nullptr); + CString line; + CHECK(ar.ReadString(line) && line == "text line"); + CHECK(!ar.ReadString(line)); + bool eof = false; + try { + CString more; + ar >> more; + } catch (CArchiveException* e) { + eof = e->m_cause == CArchiveException::endOfFile; + e->Delete(); + } + CHECK(eof); + delete first; + } + WriteRaw(Native("unicode.bin"), std::string("\xFF\xFE\xFF\x02h\0i\0", 8)); + { + CFile f(App("unicode.bin").c_str(), CFile::modeRead); + CArchive ar(&f, CArchive::load); + CString s; + ar >> s; + CHECK(s == "hi"); + } + CHECK(CRuntimeClass::FromName("CStringArray") == RUNTIME_CLASS(CStringArray)); + CObject* created = CRuntimeClass::CreateObject("CDWordArray"); + CHECK(created && created->IsKindOf(RUNTIME_CLASS(CDWordArray)) && created->IsSerializable()); + delete created; +} + +void TestIni() { + std::string ini = App("test.ini"); + CHECK(WritePrivateProfileString("General", "Name", "Value one", ini.c_str())); + CHECK(WritePrivateProfileString("General", "Count", "42", ini.c_str())); + CHECK(WritePrivateProfileString("Other", "Key", "\"quoted\"", ini.c_str())); + CHECK(WritePrivateProfileString("general", "name", "Value two", ini.c_str())); + char buf[256]; + CHECK(GetPrivateProfileString("GENERAL", "NAME", "def", buf, sizeof buf, ini.c_str()) == 9); + CHECK_EQ_STR(buf, "Value two"); + CHECK(GetPrivateProfileInt("General", "Count", 0, ini.c_str()) == 42); + CHECK(GetPrivateProfileInt("General", "Missing", 7, ini.c_str()) == 7); + GetPrivateProfileString("Other", "Key", "", buf, sizeof buf, ini.c_str()); + CHECK_EQ_STR(buf, "quoted"); + GetPrivateProfileString("Nope", "Key", "fallback ", buf, sizeof buf, ini.c_str()); + CHECK_EQ_STR(buf, "fallback"); + DWORD n = GetPrivateProfileString(nullptr, nullptr, "", buf, sizeof buf, ini.c_str()); + CHECK(n == 14 && memcmp(buf, "General\0Other\0\0", 15) == 0); + n = GetPrivateProfileString("General", nullptr, "", buf, sizeof buf, ini.c_str()); + CHECK(n == 11 && memcmp(buf, "Name\0Count\0\0", 12) == 0); + n = GetPrivateProfileString("General", "Name", "", buf, 4, ini.c_str()); + CHECK(n == 3); + CHECK_EQ_STR(buf, "Val"); + n = GetPrivateProfileSection("General", buf, sizeof buf, ini.c_str()); + CHECK(n > 0 && strcmp(buf, "Name=Value two") == 0); + CHECK(WritePrivateProfileString("General", "Count", nullptr, ini.c_str())); + CHECK(GetPrivateProfileInt("General", "Count", -1, ini.c_str()) == static_cast(-1)); + CHECK(WritePrivateProfileString("Other", nullptr, nullptr, ini.c_str())); + n = GetPrivateProfileString(nullptr, nullptr, "", buf, sizeof buf, ini.c_str()); + CHECK(n == 8 && memcmp(buf, "General\0\0", 9) == 0); + std::string text = ReadRaw(Native("test.ini")); + CHECK(text == "[General]\r\nName=Value two\r\n"); +} + +void TestRegistry() { + CRegKey key; + CHECK(key.Open(HKEY_CURRENT_USER, "Software\\MfcwxTest\\Missing") == ERROR_FILE_NOT_FOUND); + DWORD disposition = 0; + CHECK(key.Create(HKEY_CURRENT_USER, "Software\\MfcwxTest\\Settings", nullptr, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, nullptr, &disposition) == ERROR_SUCCESS); + CHECK(disposition == REG_CREATED_NEW_KEY); + CHECK(key.SetDWORDValue("Number", 1234) == ERROR_SUCCESS); + CHECK(key.SetValue(77u, "Other") == ERROR_SUCCESS); + CHECK(key.SetStringValue("Text", "hello w\xF6rld") == ERROR_SUCCESS); + CHECK(key.SetValue("default value") == ERROR_SUCCESS); + BYTE bin[4] = {1, 2, 0xFE, 0}; + CHECK(key.SetBinaryValue("Blob", bin, 4) == ERROR_SUCCESS); + CHECK(key.Close() == ERROR_SUCCESS); + + HKEY sub; + CHECK(RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\MfcwxTest\\Empty", 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &sub, + &disposition) == ERROR_SUCCESS); + CHECK(RegCloseKey(sub) == ERROR_SUCCESS); + CHECK(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\MfcwxTest\\Empty", 0, KEY_READ, &sub) == ERROR_SUCCESS); + RegCloseKey(sub); + + CHECK(key.Open(HKEY_CURRENT_USER, "SOFTWARE\\mfcwxtest\\settings", KEY_READ) == ERROR_SUCCESS); + DWORD dw = 0; + CHECK(key.QueryDWORDValue("number", dw) == ERROR_SUCCESS && dw == 1234); + unsigned long other = 0; + CHECK(key.QueryValue(dw, "Other") == ERROR_SUCCESS && dw == 77); + (void)other; + char text[64]; + DWORD count = sizeof text; + CHECK(key.QueryValue(text, "Text", &count) == ERROR_SUCCESS); + CHECK_EQ_STR(text, "hello w\xF6rld"); + CHECK(count == 12); + ULONG chars = 4; + CHECK(key.QueryStringValue("Text", text, &chars) == ERROR_MORE_DATA && chars == 12); + CHECK(key.QueryDWORDValue("Text", dw) == 13); + count = sizeof text; + CHECK(key.QueryValue(text, nullptr, &count) == ERROR_SUCCESS); + CHECK_EQ_STR(text, "default value"); + BYTE out[8] = {}; + ULONG bytes = sizeof out; + CHECK(key.QueryBinaryValue("Blob", out, &bytes) == ERROR_SUCCESS && bytes == 4 && memcmp(out, bin, 4) == 0); + DWORD type = 0, size = 0; + CHECK(RegQueryValueEx(key, "Text", nullptr, &type, nullptr, &size) == ERROR_SUCCESS && type == REG_SZ && size == 12); + CHECK(key.DeleteValue("Other") == ERROR_SUCCESS); + CHECK(key.QueryDWORDValue("Other", dw) == ERROR_FILE_NOT_FOUND); + key.Close(); + + HKEY parent; + CHECK(RegOpenKey(HKEY_CURRENT_USER, "Software\\MfcwxTest", &parent) == ERROR_SUCCESS); + char name[64]; + std::vector subkeys; + for (DWORD i = 0;; ++i) { + DWORD nameSize = sizeof name; + if (RegEnumKeyEx(parent, i, name, &nameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS) + break; + subkeys.push_back(name); + } + CHECK(subkeys.size() == 2 && subkeys[0] == "Empty" && subkeys[1] == "Settings"); + CHECK(RegDeleteKey(parent, "Empty") == ERROR_SUCCESS); + CHECK(RegOpenKeyEx(parent, "Empty", 0, KEY_READ, &sub) == ERROR_FILE_NOT_FOUND); + RegCloseKey(parent); + + std::string file = ReadRaw(getenv("MFCWX_REGISTRY_FILE")); + CHECK(file.find("Number=dword:000004d2") != std::string::npos); + CHECK(file.find("HKEY_CURRENT_USER/Software/MfcwxTest/Settings") != std::string::npos); +} + +std::atomic g_counter{0}; + +UINT CountingProc(LPVOID param) { + int n = *static_cast(param); + for (int i = 0; i < n; ++i) + ++g_counter; + CHECK(AfxGetThread() != nullptr); + return 17; +} + +struct LockData { + CCriticalSection* cs; + long value; +}; + +UINT LockedIncrement(LPVOID param) { + auto* d = static_cast(param); + for (int i = 0; i < 10000; ++i) { + CSingleLock lock(d->cs, TRUE); + long v = d->value; + d->value = v + 1; + } + return 0; +} + +UINT EndEarly(LPVOID) { + AfxEndThread(99, FALSE); + return 1; +} + +UINT WaitForEvent(LPVOID param) { + auto* ev = static_cast(param); + return ::WaitForSingleObject(*ev, 5000) == WAIT_OBJECT_0 ? 5 : 6; +} + +std::atomic g_ticks{0}; +std::atomic g_stop{false}; + +DWORD Ticker(LPVOID) { + while (!g_stop) { + ++g_ticks; + Sleep(1); + } + return 3; +} + +DWORD ExitEarly(LPVOID) { + ExitThread(21); + return 0; +} + +unsigned BeginEx(void* arg) { + ++*static_cast*>(arg); + return 8; +} + +void TestThreads() { + int iterations = 1000; + CWinThread* t = AfxBeginThread(CountingProc, &iterations, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); + CHECK(t != nullptr); + t->m_bAutoDelete = FALSE; + Sleep(20); + CHECK(g_counter == 0); + DWORD code = 0; + CHECK(GetExitCodeThread(t->m_hThread, &code) && code == STILL_ACTIVE); + t->ResumeThread(); + CHECK(WaitForSingleObject(t->m_hThread, 5000) == WAIT_OBJECT_0); + CHECK(g_counter == 1000); + CHECK(GetExitCodeThread(t->m_hThread, &code) && code == 17); + delete t; + + t = AfxBeginThread(CountingProc, &iterations); + HANDLE stale = t->m_hThread; + CHECK(WaitForSingleObject(stale, 5000) == WAIT_OBJECT_0); + Sleep(20); + CHECK(WaitForSingleObject(stale, 0) == WAIT_OBJECT_0); + CHECK(g_counter == 2000); + + t = AfxBeginThread(EndEarly, nullptr, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); + t->m_bAutoDelete = FALSE; + t->ResumeThread(); + CHECK(WaitForSingleObject(*t, 5000) == WAIT_OBJECT_0); + CHECK(GetExitCodeThread(*t, &code) && code == 99); + delete t; + + CCriticalSection cs; + LockData data{&cs, 0}; + std::vector workers; + std::vector handles; + for (int i = 0; i < 4; ++i) { + CWinThread* w = AfxBeginThread(LockedIncrement, &data, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); + w->m_bAutoDelete = FALSE; + workers.push_back(w); + handles.push_back(w->m_hThread); + } + for (CWinThread* w : workers) + w->ResumeThread(); + CHECK(WaitForMultipleObjects(4, handles.data(), TRUE, 10000) == WAIT_OBJECT_0); + CHECK(data.value == 40000); + for (CWinThread* w : workers) + delete w; + + CEvent manual(FALSE, TRUE); + CHECK(WaitForSingleObject(manual, 10) == WAIT_TIMEOUT); + manual.SetEvent(); + CHECK(WaitForSingleObject(manual, 0) == WAIT_OBJECT_0); + CHECK(WaitForSingleObject(manual, 0) == WAIT_OBJECT_0); + manual.ResetEvent(); + CHECK(WaitForSingleObject(manual, 0) == WAIT_TIMEOUT); + CEvent autoEvent; + autoEvent.SetEvent(); + CHECK(WaitForSingleObject(autoEvent, 0) == WAIT_OBJECT_0); + CHECK(WaitForSingleObject(autoEvent, 0) == WAIT_TIMEOUT); + CEvent go(FALSE, TRUE); + t = AfxBeginThread(WaitForEvent, &go, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); + t->m_bAutoDelete = FALSE; + t->ResumeThread(); + Sleep(20); + CHECK(WaitForSingleObject(*t, 0) == WAIT_TIMEOUT); + go.SetEvent(); + CHECK(WaitForSingleObject(*t, 5000) == WAIT_OBJECT_0); + CHECK(GetExitCodeThread(*t, &code) && code == 5); + delete t; + + HANDLE ev1 = CreateEvent(nullptr, FALSE, FALSE, nullptr); + HANDLE ev2 = CreateEvent(nullptr, FALSE, TRUE, nullptr); + HANDLE pair[2] = {ev1, ev2}; + CHECK(WaitForMultipleObjects(2, pair, FALSE, 0) == WAIT_OBJECT_0 + 1); + CHECK(WaitForMultipleObjects(2, pair, FALSE, 10) == WAIT_TIMEOUT); + SetEvent(ev1); + SetEvent(ev2); + CHECK(WaitForMultipleObjects(2, pair, TRUE, 0) == WAIT_OBJECT_0); + CHECK(WaitForSingleObject(ev1, 0) == WAIT_TIMEOUT); + HANDLE named = CreateEvent(nullptr, TRUE, FALSE, "mfcwx-test-event"); + HANDLE again = CreateEvent(nullptr, TRUE, FALSE, "mfcwx-test-event"); + CHECK(again == named && GetLastError() == ERROR_ALREADY_EXISTS); + CloseHandle(again); + CloseHandle(named); + CloseHandle(ev1); + CloseHandle(ev2); + CHECK(WaitForSingleObject(ev1, 0) == WAIT_FAILED); + + CMutex mutex; + CSingleLock ml(&mutex); + CHECK(ml.Lock(0) && ml.IsLocked()); + CHECK(mutex.Lock(0)); + mutex.Unlock(); + ml.Unlock(); + CSemaphore sem(1, 2); + CHECK(sem.Lock(0)); + CHECK(!sem.Lock(0)); + LONG prev = -1; + CHECK(sem.Unlock(2, &prev) && prev == 0); + CHECK(!sem.Unlock(1)); + CSyncObject* objs[2] = {&manual, &sem}; + CMultiLock multi(objs, 2); + manual.SetEvent(); + CHECK(multi.Lock(100, TRUE) == WAIT_OBJECT_0); + multi.Unlock(); + + DWORD tid = 0; + HANDLE ticker = CreateThread(nullptr, 0, Ticker, nullptr, CREATE_SUSPENDED, &tid); + CHECK(ticker != nullptr && tid != 0 && tid != GetCurrentThreadId()); + Sleep(20); + CHECK(g_ticks == 0); + CHECK(ResumeThread(ticker) == 1); + Sleep(30); + CHECK(g_ticks > 0); + CHECK(SuspendThread(ticker) == 0); + Sleep(20); + int frozen = g_ticks; + Sleep(40); + CHECK(g_ticks == frozen); + CHECK(ResumeThread(ticker) == 1); + Sleep(30); + CHECK(g_ticks > frozen); + g_stop = true; + CHECK(WaitForSingleObject(ticker, 5000) == WAIT_OBJECT_0); + CHECK(GetExitCodeThread(ticker, &code) && code == 3); + CHECK(!TerminateThread(ticker, 0)); + CloseHandle(ticker); + + HANDLE early = CreateThread(nullptr, 0, ExitEarly, nullptr, 0, nullptr); + CHECK(WaitForSingleObject(early, 5000) == WAIT_OBJECT_0); + CHECK(GetExitCodeThread(early, &code) && code == 21); + CloseHandle(early); + + std::atomic hits{0}; + unsigned exTid = 0; + HANDLE ex = reinterpret_cast(_beginthreadex(nullptr, 0, BeginEx, &hits, 0, &exTid)); + CHECK(WaitForSingleObject(ex, 5000) == WAIT_OBJECT_0 && hits == 1); + CHECK(GetExitCodeThread(ex, &code) && code == 8); + CloseHandle(ex); + + HANDLE never = CreateThread(nullptr, 0, Ticker, nullptr, CREATE_SUSPENDED, nullptr); + CHECK(TerminateThread(never, 4)); + CHECK(WaitForSingleObject(never, 0) == WAIT_OBJECT_0); + CloseHandle(never); + + LONG v = 5; + CHECK(InterlockedIncrement(&v) == 6 && InterlockedDecrement(&v) == 5); + CHECK(InterlockedExchange(&v, 9) == 5 && v == 9); + CHECK(InterlockedCompareExchange(&v, 1, 9) == 9 && v == 1); + CHECK(InterlockedExchangeAdd(&v, 4) == 1 && v == 5); + CRITICAL_SECTION raw; + InitializeCriticalSection(&raw); + EnterCriticalSection(&raw); + CHECK(TryEnterCriticalSection(&raw)); + LeaveCriticalSection(&raw); + LeaveCriticalSection(&raw); + DeleteCriticalSection(&raw); + CHECK(AfxGetThread() == nullptr); +} + +void TestProcesses() { + std::string out = App("echo.txt"); + SECURITY_ATTRIBUTES sa = {sizeof sa, nullptr, TRUE}; + HANDLE file = CreateFile(out.c_str(), FILE_WRITE_DATA, FILE_SHARE_READ, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + CHECK(file != INVALID_HANDLE_VALUE); + STARTUPINFO si; + memset(&si, 0, sizeof si); + si.cb = sizeof si; + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdOutput = file; + si.hStdError = file; + PROCESS_INFORMATION pi; + char cmd[] = "/bin/echo hello \"big world\""; + CHECK(CreateProcess(nullptr, cmd, nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)); + CHECK(WaitForSingleObject(pi.hProcess, 5000) == WAIT_OBJECT_0); + DWORD code = 1234; + CHECK(GetExitCodeProcess(pi.hProcess, &code) && code == 0); + CHECK(WaitForSingleObject(pi.hThread, 0) == WAIT_OBJECT_0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(file); + CHECK_EQ_STR(ReadRaw(Native("echo.txt")), "hello big world\n"); + + char sh[] = "sh -c \"exit 3\""; + CHECK(CreateProcess(nullptr, sh, nullptr, nullptr, FALSE, 0, nullptr, g_appRoot.c_str(), nullptr, &pi)); + CHECK(WaitForSingleObject(pi.hProcess, 5000) == WAIT_OBJECT_0); + CHECK(GetExitCodeProcess(pi.hProcess, &code) && code == 3); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + char sleeper[] = "sleep 5"; + CHECK(CreateProcess(nullptr, sleeper, nullptr, nullptr, FALSE, 0, nullptr, nullptr, nullptr, &pi)); + CHECK(WaitForSingleObject(pi.hProcess, 50) == WAIT_TIMEOUT); + CHECK(GetExitCodeProcess(pi.hProcess, &code) && code == STILL_ACTIVE); + CHECK(TerminateProcess(pi.hProcess, 1)); + CHECK(WaitForSingleObject(pi.hProcess, 5000) == WAIT_OBJECT_0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + char missing[] = "definitely-not-a-program-xyz.exe --flag"; + CHECK(!CreateProcess(nullptr, missing, nullptr, nullptr, FALSE, 0, nullptr, nullptr, nullptr, &pi)); + CHECK(GetLastError() == ERROR_FILE_NOT_FOUND); + CHECK(WinExec("/usr/bin/true", SW_HIDE) > 31); + CHECK(_spawnl(_P_WAIT, "/bin/sh", "sh", "-c", "\"exit 4\"", nullptr) == 4); + char found[MAX_PATH]; + char* part = nullptr; + CHECK(SearchPath(nullptr, "sh", nullptr, sizeof found, found, &part) > 0 && part && strcmp(part, "sh") == 0); + CHECK(found[0] == '\\'); + CHECK(SearchPath(nullptr, "AESTool.exe", nullptr, sizeof found, found, &part) == 0); + CHECK(reinterpret_cast(ShellExecute(nullptr, "open", "/no/such/file.xyz", nullptr, nullptr, SW_SHOW)) <= 32); +} + +void TestCrt() { + char buf[80]; + CHECK_EQ_STR(_itoa(-255, buf, 10), "-255"); + CHECK_EQ_STR(_itoa(-1, buf, 16), "ffffffff"); + CHECK_EQ_STR(_itoa(255, buf, 2), "11111111"); + CHECK_EQ_STR(_itoa(35, buf, 36), "z"); + CHECK_EQ_STR(itoa(0, buf, 10), "0"); + CHECK_EQ_STR(_ltoa(-1L, buf, 16), "ffffffff"); + CHECK_EQ_STR(_ltoa(-123456L, buf, 10), "-123456"); + CHECK_EQ_STR(_ultoa(4294967295UL, buf, 10), "4294967295"); + CHECK_EQ_STR(_i64toa(-1LL, buf, 16), "ffffffffffffffff"); + CHECK_EQ_STR(_i64toa(LLONG_MIN, buf, 10), "-9223372036854775808"); + CHECK_EQ_STR(_ui64toa(18446744073709551615ULL, buf, 10), "18446744073709551615"); + CHECK(_itoa_s(12345, buf, 4, 10) == ERANGE && buf[0] == 0); + CHECK(_itoa_s(123, buf, 4, 10) == 0 && strcmp(buf, "123") == 0); + CHECK_EQ_STR(_gcvt(1.0, 5, buf), "1."); + CHECK_EQ_STR(_gcvt(3.14159, 3, buf), "3.14"); + int dec = 0, sign = 0; + CHECK_EQ_STR(_ecvt(3.1415926535, 5, &dec, &sign), "31416"); + CHECK(dec == 1 && sign == 0); + CHECK_EQ_STR(_fcvt(-3.1415926535, 7, &dec, &sign), "31415927"); + CHECK(dec == 1 && sign == 1); + CHECK_EQ_STR(_fcvt(0.012, 4, &dec, &sign), "120"); + CHECK(dec == -1); + char s[] = "Hello"; + CHECK_EQ_STR(_strupr(s), "HELLO"); + CHECK_EQ_STR(_strlwr(s), "hello"); + CHECK_EQ_STR(_strrev(s), "olleh"); + CHECK_EQ_STR(_strnset(s, '*', 2), "**leh"); + CHECK(sprintf_s(buf, 4, "%s", "toolong") == -1 && buf[0] == 0); + CHECK(sprintf_s(buf, sizeof buf, "%I64d", 1234567890123LL) == 13 && strcmp(buf, "1234567890123") == 0); + CHECK(_snprintf_s(buf, sizeof buf, _TRUNCATE, "%s", "abc") == 3); + CHECK(_snprintf_s(buf, 4, static_cast(-1), "%s", "abcdef") == -1 && strcmp(buf, "abc") == 0); + CHECK(strcpy_s(buf, 3, "abc") == ERANGE && buf[0] == 0); + CHECK(strcpy_s(buf, sizeof buf, "abc") == 0 && strcat_s(buf, sizeof buf, "def") == 0 && strcmp(buf, "abcdef") == 0); + CHECK(strncpy_s(buf, sizeof buf, "abcdef", 3) == 0 && strcmp(buf, "abc") == 0); + CHECK(mfcwx_rotl(0x80000001u, 1) == 3u && mfcwx_rotr(3u, 1) == 0x80000001u); + time_t now = time(nullptr); + struct tm tm; + CHECK(localtime_s(&tm, &now) == 0); + char* env = nullptr; + size_t envLen = 0; + CHECK(_dupenv_s(&env, &envLen, "HOME") == 0 && env && envLen == strlen(env) + 1); + free(env); + char templ[MAX_PATH]; + snprintf(templ, sizeof templ, "%s\\tmpXXXXXX", g_appRoot.c_str()); + CHECK(_mktemp(templ) != nullptr && strstr(templ, "XXXXXX") == nullptr); + char* tn = _tempnam(g_appRoot.c_str(), "pse"); + CHECK(tn && strncmp(tn, (g_appRoot + "\\pse").c_str(), g_appRoot.size() + 4) == 0); + free(tn); + CHECK(_mkdir(App("crtdir").c_str()) == 0); + CHECK(_rmdir(App("crtdir").c_str()) == 0); + int fd = _open(App("open.bin").c_str(), _O_CREAT | _O_WRONLY | _O_BINARY, _S_IREAD | _S_IWRITE); + CHECK(fd >= 0); + CHECK(_write(fd, "12345", 5) == 5); + CHECK(_filelength(fd) == 5); + CHECK(_chsize(fd, 2) == 0 && _filelength(fd) == 2); + _close(fd); +} + +void TestWin32() { + mfcwx::SetAnsiCodePage(1250); + const char polish[] = "\xB9\xE6\x9C\xBF\xA3"; + wchar_t wide[16]; + int n = MultiByteToWideChar(1250, 0, polish, -1, nullptr, 0); + CHECK(n == 6); + CHECK(MultiByteToWideChar(1250, 0, polish, -1, wide, 16) == 6); + CHECK(wide[0] == 0x105 && wide[1] == 0x107 && wide[2] == 0x15B && wide[3] == 0x17C && wide[4] == 0x141 && wide[5] == 0); + CHECK(MultiByteToWideChar(CP_ACP, 0, polish, 2, wide, 16) == 2 && wide[0] == 0x105); + char back[16]; + BOOL usedDefault = TRUE; + CHECK(WideCharToMultiByte(1250, 0, wide, 2, back, sizeof back, nullptr, &usedDefault) == 2); + CHECK(memcmp(back, polish, 2) == 0 && !usedDefault); + CHECK(WideCharToMultiByte(1252, 0, wide, 1, back, sizeof back, nullptr, &usedDefault) == 1 && back[0] == '?' && + usedDefault); + CHECK(WideCharToMultiByte(CP_UTF8, 0, wide, 1, back, sizeof back, nullptr, nullptr) == 2); + CHECK(memcmp(back, "\xC4\x85", 2) == 0); + CHECK(MultiByteToWideChar(CP_UTF8, 0, "\xF0\x9F\x98\x80", 4, wide, 16) == 1 && wide[0] == 0x1F600); + CHECK(MultiByteToWideChar(1250, 0, polish, 5, wide, 2) == 0 && GetLastError() == 122); + + char upper[] = "\xB9\xE6\x9F" "abc"; + CharUpper(upper); + CHECK_EQ_STR(upper, "\xA5\xC6\x8F" "ABC"); + CharLowerBuff(upper, 2); + CHECK_EQ_STR(upper, "\xB9\xE6\x8F" "ABC"); + CHECK(IsCharAlpha('\xB9') && IsCharLower('\xB9') && IsCharUpper('\xA5') && !IsCharAlpha('1')); + CHECK(IsCharAlphaNumeric('7') && !IsCharAlpha('\xA7')); + CHECK(GetACP() == 1250); + mfcwx::SetAnsiCodePage(1252); + CHECK(lstrcmpi("\xC4pfel", "\xE4PFEL") == 0); + CHECK(lstrcmp("a", "B") < 0 && lstrcmp("a", "A") < 0 && lstrcmp("abc", "abc") == 0); + char buf[256]; + CHECK(wsprintf(buf, "%d-%s-%I64u", 5, "x", 99ULL) == 6 && strcmp(buf, "5-x-99") == 0); + lstrcpyn(buf, "abcdef", 4); + CHECK_EQ_STR(buf, "abc"); + + LPSTR msg = nullptr; + DWORD len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, ERROR_FILE_NOT_FOUND, 0, reinterpret_cast(&msg), 0, nullptr); + CHECK(len > 0 && msg && strstr(msg, "cannot find the file") != nullptr); + CHECK(LocalFree(msg) == nullptr); + DWORD_PTR args[2] = {reinterpret_cast("file.txt"), 7}; + len = FormatMessage(FORMAT_MESSAGE_FROM_STRING | 0x2000, "Open %1 failed (%2!d!)%n", 0, 0, buf, sizeof buf, + reinterpret_cast(args)); + CHECK_EQ_STR(buf, "Open file.txt failed (7)\r\n"); + + HGLOBAL g = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 16); + CHECK(g && GlobalSize(g) == 16); + char* p = static_cast(GlobalLock(g)); + CHECK(p && p[15] == 0); + strcpy(p, "clip"); + GlobalUnlock(g); + g = GlobalReAlloc(g, 4096, GMEM_MOVEABLE); + CHECK(g && GlobalSize(g) == 4096 && strcmp(static_cast(GlobalLock(g)), "clip") == 0); + GlobalUnlock(g); + CHECK(GlobalFree(g) == nullptr); + char* fixed = static_cast(GlobalAlloc(GPTR, 8)); + CHECK(fixed && fixed[7] == 0 && GlobalLock(fixed) == fixed); + GlobalFree(fixed); + + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof vi; + CHECK(GetVersionEx(&vi) && vi.dwMajorVersion == 5 && vi.dwMinorVersion == 1); + SYSTEM_INFO si; + GetSystemInfo(&si); + CHECK(si.dwNumberOfProcessors >= 1 && si.dwPageSize >= 4096); + MEMORYSTATUS ms; + GlobalMemoryStatus(&ms); + CHECK(ms.dwTotalPhys > 0 && ms.dwAvailPhys <= ms.dwTotalPhys); + LARGE_INTEGER f, c1, c2; + CHECK(QueryPerformanceFrequency(&f) && f.QuadPart == 10000000); + QueryPerformanceCounter(&c1); + DWORD t0 = GetTickCount(); + Sleep(20); + QueryPerformanceCounter(&c2); + CHECK(c2.QuadPart - c1.QuadPart >= 150000); + CHECK(GetTickCount() - t0 >= 15); + SYSTEMTIME st; + GetSystemTime(&st); + FILETIME ft, ft2; + CHECK(SystemTimeToFileTime(&st, &ft)); + SYSTEMTIME st2; + CHECK(FileTimeToSystemTime(&ft, &st2)); + CHECK(st2.wYear == st.wYear && st2.wSecond == st.wSecond && st2.wMilliseconds == st.wMilliseconds); + st.wYear = 1601; + st.wMonth = 1; + st.wDay = 1; + st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; + CHECK(SystemTimeToFileTime(&st, &ft2) && ft2.dwLowDateTime == 0 && ft2.dwHighDateTime == 0); + CHECK(MulDiv(10, 3, 4) == 8 && MulDiv(-10, 3, 4) == -8 && MulDiv(1, 1, 0) == -1); + WORD lang = static_cast(GetUserDefaultLangID()); + CHECK(PRIMARYLANGID(lang) != 0); + + CHECK(SetEnvironmentVariable("MFCWX_TEST_VAR", "abc")); + CHECK(GetEnvironmentVariable("MFCWX_TEST_VAR", buf, sizeof buf) == 3 && strcmp(buf, "abc") == 0); + CHECK(ExpandEnvironmentStrings("x%MFCWX_TEST_VAR%y%UNDEFINED_MFCWX%", buf, sizeof buf) == 23); + CHECK_EQ_STR(buf, "xabcy%UNDEFINED_MFCWX%"); + CHECK(SetEnvironmentVariable("MFCWX_TEST_VAR", nullptr)); + CHECK(GetEnvironmentVariable("MFCWX_TEST_VAR", buf, sizeof buf) == 0); + DWORD size = sizeof buf; + CHECK(GetUserName(buf, &size) && size == strlen(buf) + 1); + size = sizeof buf; + CHECK(GetComputerName(buf, &size) && size == strlen(buf)); + CHECK(LoadLibrary("NoSuchLib.dll") == nullptr && GetLastError() == 126); + HMODULE sci = LoadLibrary("SciLexer.DLL"); + CHECK(sci != nullptr && GetModuleHandle("scilexer.dll") == sci); + CHECK(GetProcAddress(sci, "Scintilla_DirectFunction") == nullptr); + CHECK(FreeLibrary(sci)); + mfcwx::RegisterBuiltinModule("extra.dll"); + CHECK(LoadLibraryEx("C:\\x\\EXTRA.dll", nullptr, 0) != nullptr); + CHECK(GetModuleHandle(nullptr) != nullptr); + + CTime ct(2024, 3, 5, 7, 8, 9); + CHECK(ct.GetYear() == 2024 && ct.GetMonth() == 3 && ct.GetDay() == 5 && ct.GetHour() == 7); + CHECK(ct.Format("%#d.%#m.%Y %H:%M:%S") == "5.3.2024 07:08:09"); + CHECK(ct.Format("%#x") == "Tuesday, March 5, 2024"); + CHECK(ct.GetDayOfWeek() == 3); + CHECK((ct + CTimeSpan(1, 2, 3, 4)).Format("%d %H:%M:%S") == "06 09:11:13"); + CHECK(CTimeSpan(1, 2, 3, 4).Format("%D:%H:%M:%S") == "1:02:03:04"); + COleDateTime od(2024, 2, 29, 12, 30, 15); + CHECK(od.m_status == COleDateTime::valid); + CHECK(od.GetYear() == 2024 && od.GetMonth() == 2 && od.GetDay() == 29 && od.GetHour() == 12 && + od.GetMinute() == 30 && od.GetSecond() == 15); + CHECK(od.GetDayOfWeek() == 5); + CHECK(static_cast(od.m_dt) == 45351); + CHECK(od.Format("%Y-%m-%d") == "2024-02-29"); + COleDateTime bad(2023, 2, 29, 0, 0, 0); + CHECK(bad.m_status == COleDateTime::invalid); + CHECK(COleDateTime::GetCurrentTime().GetYear() >= 2024); +} + +void TestExceptions() { + bool caught = false; + try { + AfxThrowArchiveException(CArchiveException::badSchema, "doc.ct"); + } catch (CException* e) { + char msg[256]; + caught = e->IsKindOf(RUNTIME_CLASS(CArchiveException)) && e->GetErrorMessage(msg, sizeof msg) && + strcmp(msg, "doc.ct contains an incorrect schema.") == 0; + e->Delete(); + } + CHECK(caught); + caught = false; + try { + AfxThrowMemoryException(); + } catch (CMemoryException* e) { + caught = true; + e->Delete(); + } + CHECK(caught); + CHECK(CFileException::ErrnoToException(ENOENT) == CFileException::fileNotFound); + CHECK(CFileException::OsErrorToException(5) == CFileException::accessDenied); +} + +} // namespace + +int main(int argc, char** argv) { + wxInitializer initializer(argc, argv); + if (!initializer.IsOk()) { + fprintf(stderr, "wxWidgets initialization failed\n"); + return 2; + } + const char* tmp = getenv("TMPDIR"); + std::string base = tmp && *tmp ? tmp : "/tmp"; + while (base.size() > 1 && base.back() == '/') + base.pop_back(); + std::string templ = base + "/mfcwx-tests-XXXXXX"; + std::vector buf(templ.begin(), templ.end()); + buf.push_back(0); + if (!mkdtemp(buf.data())) { + perror("mkdtemp"); + return 2; + } + g_root = buf.data(); + char real[PATH_MAX]; + if (realpath(g_root.c_str(), real)) + g_root = real; + g_appRoot = mfcwx::AppPath(g_root.c_str()); + std::string registry = g_root + "/registry.ini"; + setenv("MFCWX_REGISTRY_FILE", registry.c_str(), 1); + + TestPaths(); + TestFiles(); + TestFind(); + TestArchive(); + TestIni(); + TestRegistry(); + TestThreads(); + TestProcesses(); + TestCrt(); + TestWin32(); + TestExceptions(); + + std::string cleanup = "rm -rf '" + g_root + "'"; + if (g_failures == 0 && system(cleanup.c_str()) != 0) + fprintf(stderr, "cleanup of %s failed\n", g_root.c_str()); + printf("%d checks, %d failures\n", g_checks, g_failures); + return g_failures ? 1 : 0; +} diff --git a/port/mfcwx/tests/scintilla_tests.cpp b/port/mfcwx/tests/scintilla_tests.cpp new file mode 100644 index 000000000..1a9eca985 --- /dev/null +++ b/port/mfcwx/tests/scintilla_tests.cpp @@ -0,0 +1,731 @@ +// Built without the rest of mfcwx: the window functions scintilla.cpp calls are recording stubs below. + +#include "windows_impl.h" + +#include + +#include "../../../scintilla/include/Scintilla.h" +#include "../../../scintilla/include/SciLexer.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +struct Note { + unsigned code = 0; + int position = 0; + int length = 0; + int modificationType = 0; + int ch = 0; + std::string text; +}; + +std::vector g_notes; +std::vector g_commands; +std::vector> g_remembered; +std::function g_onNotify; + +int g_failures = 0; +int g_checks = 0; + +#define CHECK(cond) \ + do { \ + ++g_checks; \ + if (!(cond)) { \ + ++g_failures; \ + fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, #cond); \ + } \ + } while (0) + +#define CHECK_EQ(a, b) \ + do { \ + ++g_checks; \ + long long va_ = static_cast(a); \ + long long vb_ = static_cast(b); \ + if (va_ != vb_) { \ + ++g_failures; \ + fprintf(stderr, "%s:%d: CHECK_EQ failed: %s (%lld) != %s (%lld)\n", __FILE__, __LINE__, #a, \ + va_, #b, vb_); \ + } \ + } while (0) + +#define CHECK_STR(a, b) \ + do { \ + ++g_checks; \ + std::string sa_(a); \ + std::string sb_(b); \ + if (sa_ != sb_) { \ + ++g_failures; \ + fprintf(stderr, "%s:%d: CHECK_STR failed: %s (\"%s\") != %s (\"%s\")\n", __FILE__, __LINE__, #a, \ + sa_.c_str(), #b, sb_.c_str()); \ + } \ + } while (0) + +wxStyledTextCtrl* g_stc = nullptr; + +LRESULT Send(UINT msg, WPARAM wp = 0, LPARAM lp = 0) { + bool handled = false; + LRESULT r = mfcwx::ScintillaWindowProc(g_stc, msg, wp, lp, handled); + if (!handled) + fprintf(stderr, "message %u not handled\n", msg); + return r; +} + +LRESULT Send(UINT msg, WPARAM wp, const char* text) { return Send(msg, wp, reinterpret_cast(text)); } +LRESULT Send(UINT msg, WPARAM wp, const void* p) { return Send(msg, wp, reinterpret_cast(p)); } +WPARAM W(int v) { return static_cast(static_cast(v)); } + +std::string GetAll() { + LRESULT len = Send(SCI_GETLENGTH); + std::vector buf(static_cast(len) + 1, 'x'); + Send(SCI_GETTEXT, static_cast(len + 1), buf.data()); + return std::string(buf.data(), static_cast(len)); +} + +std::string Range(int a, int b) { + std::vector buf(static_cast((b < 0 ? Send(SCI_GETLENGTH) : b) - a) + 1, 'x'); + TextRange tr; + tr.chrg.cpMin = a; + tr.chrg.cpMax = b; + tr.lpstrText = buf.data(); + LRESULT n = Send(SCI_GETTEXTRANGE, 0, &tr); + return std::string(buf.data(), static_cast(n)); +} + +void SetBytes(const std::string& s) { + Send(SCI_CLEARALL); + Send(SCI_ADDTEXT, s.size(), s.data()); +} + +void TestCp1252RoundTrip() { + mfcwx::SetAnsiCodePage(1252); + const char* t = "Gr\xFC\xDF" "e \x80\n\x89 caf\xE9"; + Send(SCI_SETTEXT, 0, t); + CHECK_EQ(Send(SCI_GETLENGTH), strlen(t)); + CHECK_EQ(Send(SCI_GETTEXTLENGTH), strlen(t)); + CHECK_EQ(Send(WM_GETTEXTLENGTH), strlen(t)); + CHECK(g_stc->GetLength() > static_cast(strlen(t))); + CHECK(g_stc->GetText() == wxString::FromUTF8("Gr\xC3\xBC\xC3\x9F" "e \xE2\x82\xAC\n\xE2\x80\xB0 caf\xC3\xA9")); + CHECK_STR(GetAll(), t); + + char buf[64]; + memset(buf, 'x', sizeof buf); + CHECK_EQ(Send(SCI_GETTEXT, 5, buf), 4); + CHECK_STR(buf, "Gr\xFC\xDF"); + memset(buf, 'x', sizeof buf); + CHECK_EQ(Send(WM_GETTEXT, 5, buf), 4); + CHECK_STR(buf, "Gr\xFC\xDF"); + + CHECK_EQ(Send(SCI_GETCHARAT, 2), static_cast('\xFC')); + CHECK_EQ(Send(SCI_GETCHARAT, 1), 'r'); + CHECK_STR(Range(3, 7), "\xDF" "e \x80"); + CHECK_STR(Range(9, -1), " caf\xE9"); + + CHECK_EQ(Send(SCI_LINEFROMPOSITION, 8), 1); + CHECK_EQ(Send(SCI_LINEFROMPOSITION, 6), 0); + CHECK_EQ(Send(SCI_POSITIONFROMLINE, 1), 8); + CHECK_EQ(Send(SCI_GETLINEENDPOSITION, 0), 7); + CHECK_EQ(Send(SCI_LINELENGTH, 0), 8); + CHECK_EQ(Send(SCI_GETCOLUMN, 11), 3); + CHECK_EQ(Send(SCI_POSITIONAFTER, 2), 3); + CHECK_EQ(Send(SCI_POSITIONBEFORE, 7), 6); + + Send(SCI_SETSEL, 2, 7); + CHECK_EQ(Send(SCI_GETSELECTIONSTART), 2); + CHECK_EQ(Send(SCI_GETSELECTIONEND), 7); + CHECK_EQ(Send(SCI_GETCURRENTPOS), 7); + CHECK_EQ(Send(SCI_GETANCHOR), 2); + CHECK_EQ(Send(SCI_GETSELTEXT, 0, static_cast(0)), 6); + memset(buf, 'x', sizeof buf); + CHECK_EQ(Send(SCI_GETSELTEXT, 0, buf), 6); + CHECK_STR(buf, "\xFC\xDF" "e \x80"); + Send(SCI_SETSEL, W(-1), W(-1)); + CHECK_EQ(Send(SCI_GETCURRENTPOS), strlen(t)); + Send(SCI_GOTOPOS, 10); + CHECK_EQ(Send(SCI_GETCURRENTPOS), 10); + CHECK_EQ(g_stc->GetCurrentPos(), 16); + + char line[64]; + memset(line, 'x', sizeof line); + CHECK_EQ(Send(SCI_GETLINE, 0, line), 8); + CHECK_STR(std::string(line, 8), "Gr\xFC\xDF" "e \x80\n"); + memset(line, 'x', sizeof line); + CHECK_EQ(Send(SCI_GETCURLINE, sizeof line, line), 2); + CHECK_STR(line, "\x89 caf\xE9"); + CHECK_EQ(Send(SCI_GETCURLINE, 0, static_cast(0)), 7); + + const char* p = reinterpret_cast(Send(SCI_GETCHARACTERPOINTER)); + CHECK_STR(p, t); + + Send(SCI_INSERTTEXT, 3, "\xE9"); + CHECK_STR(GetAll(), "Gr\xFC\xE9\xDF" "e \x80\n\x89 caf\xE9"); + Send(SCI_INSERTTEXT, W(-1), "\xA7"); + CHECK_EQ(Send(SCI_GETCHARAT, 11), static_cast('\xA7')); +} + +void TestAllBytes() { + mfcwx::SetAnsiCodePage(1252); + std::string all; + for (int i = 0; i < 256; ++i) + all.push_back(static_cast(i)); + SetBytes(all); + CHECK_EQ(Send(SCI_GETLENGTH), 256); + CHECK(Range(0, -1) == all); + CHECK(GetAll() == all); + const char* p = reinterpret_cast(Send(SCI_GETCHARACTERPOINTER)); + CHECK(memcmp(p, all.data(), 256) == 0); + for (int i = 0; i < 256; i += 17) + CHECK_EQ(Send(SCI_GETCHARAT, W(i)), static_cast(i)); + + std::vector cells(256 * 2 + 2, 'x'); + TextRange tr; + tr.chrg.cpMin = 0; + tr.chrg.cpMax = 256; + tr.lpstrText = cells.data(); + CHECK_EQ(Send(SCI_GETSTYLEDTEXT, 0, &tr), 512); + bool same = true; + for (int i = 0; i < 256; ++i) + same = same && cells[i * 2] == static_cast(i); + CHECK(same); + CHECK(cells[512] == 0 && cells[513] == 0); +} + +void TestCp1250Positions() { + mfcwx::SetAnsiCodePage(1250); + const char* t = "Za\xBF\xF3\xB3\xE6 g\xEA\x9Cl\xB9 ja\x9F\xF1\r\nZA\xAF\xD3\xA3\xC6 koniec"; + size_t len = strlen(t); + Send(SCI_SETTEXT, 0, t); + CHECK_STR(GetAll(), t); + CHECK(g_stc->GetText() == wxString::FromUTF8("Za\xC5\xBC\xC3\xB3\xC5\x82\xC4\x87 g\xC4\x99\xC5\x9Bl\xC4\x85 " + "ja\xC5\xBA\xC5\x84\r\nZA\xC5\xBB\xC3\x93\xC5\x81\xC4\x86 koniec")); + CHECK_EQ(Send(SCI_GETLENGTH), len); + + TextToFind ft; + ft.chrg.cpMin = 0; + ft.chrg.cpMax = static_cast(len); + ft.lpstrText = const_cast("g\xEA\x9Cl\xB9"); + CHECK_EQ(Send(SCI_FINDTEXT, SCFIND_MATCHCASE, &ft), 7); + CHECK_EQ(ft.chrgText.cpMin, 7); + CHECK_EQ(ft.chrgText.cpMax, 12); + CHECK_EQ(ft.chrg.cpMax, static_cast(len)); + + ft.chrg.cpMin = static_cast(len); + ft.chrg.cpMax = 0; + ft.lpstrText = const_cast("ja\x9F\xF1"); + CHECK_EQ(Send(SCI_FINDTEXT, SCFIND_MATCHCASE, &ft), 13); + CHECK_EQ(ft.chrgText.cpMax, 17); + + ft.chrg.cpMin = 0; + ft.chrg.cpMax = static_cast(len); + ft.lpstrText = const_cast("\xAF\xD3\xA3\xC6"); + CHECK_EQ(Send(SCI_FINDTEXT, SCFIND_MATCHCASE, &ft), 21); + // Scintilla 1.77 folds only ASCII when searching case-insensitively; so does wx's Scintilla. + CHECK_EQ(Send(SCI_FINDTEXT, 0, &ft), 21); + ft.lpstrText = const_cast("KONIEC"); + CHECK_EQ(Send(SCI_FINDTEXT, 0, &ft), 26); + CHECK_EQ(ft.chrgText.cpMax, 32); + + ft.lpstrText = const_cast("nothere"); + CHECK_EQ(Send(SCI_FINDTEXT, 0, &ft), -1); + + CHECK_EQ(Send(SCI_LINEFROMPOSITION, 21), 1); + CHECK_EQ(Send(SCI_POSITIONFROMLINE, 1), 19); + CHECK_EQ(Send(SCI_GETLINEENDPOSITION, 0), 17); + Send(SCI_SETSEL, 21, 25); + char buf[64]; + Send(SCI_GETSELTEXT, 0, buf); + CHECK_STR(buf, "\xAF\xD3\xA3\xC6"); + CHECK_STR(Range(2, 6), "\xBF\xF3\xB3\xE6"); + + Send(SCI_SETSEL, 0, static_cast(0)); + Send(SCI_SETSEARCHFLAGS, SCFIND_MATCHCASE); + Send(SCI_SETTARGETSTART, 0); + Send(SCI_SETTARGETEND, W(static_cast(len))); + CHECK_EQ(Send(SCI_SEARCHINTARGET, 2, "\xB3\xE6"), 4); + CHECK_EQ(Send(SCI_GETTARGETSTART), 4); + CHECK_EQ(Send(SCI_GETTARGETEND), 6); + CHECK_EQ(Send(SCI_REPLACETARGET, W(-1), "\xA3\xC6!"), 3); + CHECK_STR(GetAll(), "Za\xBF\xF3\xA3\xC6! g\xEA\x9Cl\xB9 ja\x9F\xF1\r\nZA\xAF\xD3\xA3\xC6 koniec"); + CHECK_EQ(Send(SCI_GETLENGTH), len + 1); + + Send(SCI_SETTEXT, 0, "\xB9\xB9 a \xB9"); + const char* find = "\xB9"; + const char* repl = "\xA5\xA5"; + int count = 0; + long lEnd = static_cast(Send(SCI_GETTEXTLENGTH)); + Send(SCI_SETTARGETSTART, 0); + Send(SCI_SETTARGETEND, static_cast(lEnd)); + long lPos = static_cast(Send(SCI_SEARCHINTARGET, strlen(find), find)); + while (lPos < lEnd && lPos >= 0) { + long lLen = static_cast(Send(SCI_REPLACETARGET, strlen(repl), repl)); + lEnd = static_cast(Send(SCI_GETTEXTLENGTH)); + Send(SCI_SETTARGETSTART, static_cast(lPos + lLen)); + Send(SCI_SETTARGETEND, static_cast(lEnd)); + lPos = static_cast(Send(SCI_SEARCHINTARGET, strlen(find), find)); + ++count; + } + CHECK_EQ(count, 3); + CHECK_STR(GetAll(), "\xA5\xA5\xA5\xA5 a \xA5\xA5"); + + TEXTRANGE tr; + char out[16]; + tr.chrg.cpMin = 1; + tr.chrg.cpMax = 5; + tr.lpstrText = out; + bool handled = false; + CHECK_EQ(mfcwx::ScintillaWindowProc(g_stc, EM_GETTEXTRANGE, 0, reinterpret_cast(&tr), handled), 4); + CHECK(handled); + CHECK_STR(out, "\xA5\xA5\xA5 "); + int s0 = -1; + int s1 = -1; + Send(SCI_SETSEL, 2, 4); + mfcwx::ScintillaWindowProc(g_stc, EM_GETSEL, reinterpret_cast(&s0), reinterpret_cast(&s1), handled); + CHECK_EQ(s0, 2); + CHECK_EQ(s1, 4); + mfcwx::ScintillaWindowProc(g_stc, EM_SETSEL, 0, -1, handled); + CHECK_EQ(Send(SCI_GETSELECTIONEND), 9); + CHECK(Send(SCI_CANUNDO) != 0); + mfcwx::ScintillaWindowProc(g_stc, EM_EMPTYUNDOBUFFER, 0, 0, handled); + CHECK(handled); + CHECK_EQ(Send(SCI_CANUNDO), 0); + mfcwx::SetAnsiCodePage(1252); +} + +void TestDirectFunction() { + mfcwx::SetAnsiCodePage(1252); + auto fn = reinterpret_cast(Send(SCI_GETDIRECTFUNCTION)); + sptr_t ptr = static_cast(Send(SCI_GETDIRECTPOINTER)); + CHECK(fn != nullptr); + CHECK(ptr == reinterpret_cast(g_stc)); + fn(ptr, SCI_SETTEXT, 0, reinterpret_cast("\xE9t\xE9 \x80")); + CHECK_EQ(fn(ptr, SCI_GETLENGTH, 0, 0), 5); + CHECK_EQ(fn(ptr, SCI_GETCHARAT, 2, 0), static_cast('\xE9')); + fn(ptr, SCI_GOTOPOS, 4, 0); + CHECK_EQ(fn(ptr, SCI_GETCURRENTPOS, 0, 0), 4); + CHECK_EQ(g_stc->GetCurrentPos(), 6); + CHECK_STR(GetAll(), "\xE9t\xE9 \x80"); +} + +void TestCrypToolLexer() { + mfcwx::SetAnsiCodePage(1252); + Send(SCI_SETMODEVENTMASK, SC_MODEVENTMASKALL); + Send(SCI_SETTEXT, 0, "A\xE4\xC4" "b \xD6x"); + Send(SCI_STYLESETFORE, 2, RGB(192, 192, 192)); + Send(SCI_SETPROPERTY, reinterpret_cast("cryptool.nonalphabetstyle"), "2"); + Send(SCI_SETPROPERTY, reinterpret_cast("cryptool.alphabet"), "ABCDEFGHIJKLMNOPQRSTUVWXYZ\xC4\xD6\xDC"); + Send(SCI_SETSTYLEBITS, 5); + Send(SCI_SETLEXERLANGUAGE, 0, "CrypTool"); + CHECK(Send(SCI_GETLEXER) != SCLEX_NULL); + CHECK_EQ(g_stc->GetLexer(), SCLEX_CONTAINER); + char prop[64]; + CHECK_EQ(Send(SCI_GETPROPERTY, reinterpret_cast("cryptool.alphabet"), prop), 29); + CHECK_STR(prop, "ABCDEFGHIJKLMNOPQRSTUVWXYZ\xC4\xD6\xDC"); + Send(SCI_CLEARDOCUMENTSTYLE); + g_notes.clear(); + Send(SCI_COLOURISE, 0, 1); + CHECK(Send(SCI_GETENDSTYLED) >= 1); + Send(SCI_COLOURISE, 0, W(-1)); + CHECK_EQ(Send(SCI_GETENDSTYLED), 7); + const int expected[] = {0, 2, 0, 2, 2, 0, 2}; + for (int i = 0; i < 7; ++i) + CHECK_EQ(Send(SCI_GETSTYLEAT, W(i)), expected[i]); + CHECK_EQ(g_stc->GetStyleAt(2), 2); + bool styleNote = false; + for (const Note& n : g_notes) + if (n.code == SCN_MODIFIED && (n.modificationType & SC_MOD_CHANGESTYLE) && n.position == 1 && n.length == 6) + styleNote = true; + CHECK(styleNote); + bool styleNeededForwarded = false; + for (const Note& n : g_notes) + styleNeededForwarded = styleNeededForwarded || n.code == SCN_STYLENEEDED; + CHECK(!styleNeededForwarded); + + Send(SCI_SETPROPERTY, reinterpret_cast("cryptool.alphabet"), "abcdefghijklmnopqrstuvwxyz\xE4"); + Send(SCI_CLEARDOCUMENTSTYLE); + Send(SCI_COLOURISE, 0, W(-1)); + const int expected2[] = {2, 0, 2, 0, 2, 2, 0}; + for (int i = 0; i < 7; ++i) + CHECK_EQ(Send(SCI_GETSTYLEAT, W(i)), expected2[i]); + + Send(SCI_SETLEXER, SCLEX_NULL); + CHECK_EQ(Send(SCI_GETLEXER), SCLEX_NULL); + Send(SCI_CLEARDOCUMENTSTYLE); + CHECK_EQ(Send(SCI_GETSTYLEAT, 1), 0); + CHECK_EQ(Send(SCI_LOADLEXERLIBRARY, 0, "LexCrypTool"), 0); +} + +void TestContainerStyling() { + mfcwx::SetAnsiCodePage(1252); + Send(SCI_SETLEXER, SCLEX_CONTAINER); + Send(SCI_SETTEXT, 0, "\xE4\xF6\xFC" "abc"); + Send(SCI_CLEARDOCUMENTSTYLE); + Send(SCI_STARTSTYLING, 1, 0x1f); + Send(SCI_SETSTYLING, 2, 5); + CHECK_EQ(Send(SCI_GETSTYLEAT, 0), 0); + CHECK_EQ(Send(SCI_GETSTYLEAT, 1), 5); + CHECK_EQ(Send(SCI_GETSTYLEAT, 2), 5); + CHECK_EQ(Send(SCI_GETSTYLEAT, 3), 0); + CHECK_EQ(Send(SCI_GETENDSTYLED), 3); + Send(SCI_SETSTYLINGEX, 2, "\x07\x08"); + CHECK_EQ(Send(SCI_GETSTYLEAT, 3), 7); + CHECK_EQ(Send(SCI_GETSTYLEAT, 4), 8); + CHECK_EQ(Send(SCI_GETENDSTYLED), 5); + Send(SCI_STARTSTYLING, 0, 0x1f); + Send(SCI_SETSTYLINGEX, 3, "\x01\x02\x03"); + CHECK_EQ(g_stc->GetStyleAt(1), 1); + CHECK_EQ(g_stc->GetStyleAt(3), 2); + CHECK_EQ(g_stc->GetStyleAt(5), 3); + CHECK_EQ(Send(SCI_GETENDSTYLED), 3); + + std::vector cells(6 * 2 + 2); + TextRange tr; + tr.chrg.cpMin = 0; + tr.chrg.cpMax = 6; + tr.lpstrText = cells.data(); + CHECK_EQ(Send(SCI_GETSTYLEDTEXT, 0, &tr), 12); + CHECK(cells[0] == '\xE4' && cells[1] == 1 && cells[2] == '\xF6' && cells[3] == 2 && cells[6] == 'a' && cells[7] == 7); + + Send(SCI_CLEARALL); + const char styled[] = {'\xC4', 4, 'x', 6}; + Send(SCI_ADDSTYLEDTEXT, 4, styled); + CHECK_STR(GetAll(), "\xC4x"); + CHECK_EQ(Send(SCI_GETSTYLEAT, 0), 4); + CHECK_EQ(Send(SCI_GETSTYLEAT, 1), 6); + + Send(SCI_SETTEXT, 0, "\xE4\xF6\xFC" "abc"); + Send(SCI_CLEARDOCUMENTSTYLE); + g_notes.clear(); + Send(SCI_COLOURISE, 0, 4); + bool found = false; + for (const Note& n : g_notes) + if (n.code == SCN_STYLENEEDED && n.position == 4) + found = true; + CHECK(found); + Send(SCI_SETLEXER, SCLEX_NULL); +} + +void TestNotifications() { + mfcwx::SetAnsiCodePage(1252); + Send(SCI_SETMODEVENTMASK, SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT); + CHECK_EQ(Send(SCI_GETMODEVENTMASK), SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT); + Send(SCI_SETTEXT, 0, "ab"); + g_notes.clear(); + g_commands.clear(); + std::vector seen; + g_onNotify = [&seen](const SCNotification& scn) { + if (scn.nmhdr.code == SCN_MODIFIED) + seen.push_back(GetAll()); + }; + Send(SCI_INSERTTEXT, 1, "\xFC\xFC"); + CHECK_EQ(g_notes.size(), 1); + if (!g_notes.empty()) { + CHECK_EQ(g_notes[0].code, SCN_MODIFIED); + CHECK(g_notes[0].modificationType & SC_MOD_INSERTTEXT); + CHECK_EQ(g_notes[0].position, 1); + CHECK_EQ(g_notes[0].length, 2); + CHECK_STR(g_notes[0].text, "\xFC\xFC"); + } + CHECK_EQ(g_commands.size(), 1); + if (!g_commands.empty()) + CHECK_EQ(g_commands[0], SCEN_CHANGE); + CHECK_EQ(seen.size(), 1); + if (!seen.empty()) + CHECK_STR(seen[0], "a\xFC\xFC" "b"); + + g_notes.clear(); + Send(SCI_SETSEL, 1, 3); + Send(SCI_CLEAR); + CHECK_EQ(g_notes.size(), 1); + if (!g_notes.empty()) { + CHECK(g_notes[0].modificationType & SC_MOD_DELETETEXT); + CHECK_EQ(g_notes[0].position, 1); + CHECK_EQ(g_notes[0].length, 2); + CHECK_STR(g_notes[0].text, "\xFC\xFC"); + } + g_onNotify = nullptr; + + Send(SCI_SETSAVEPOINT); + g_notes.clear(); + Send(SCI_ADDTEXT, 1, "\xE9"); + bool left = false; + for (const Note& n : g_notes) + left = left || n.code == SCN_SAVEPOINTLEFT; + CHECK(left); + g_notes.clear(); + Send(SCI_UNDO); + bool reached = false; + for (const Note& n : g_notes) + reached = reached || n.code == SCN_SAVEPOINTREACHED; + CHECK(reached); + + Send(SCI_SETMODEVENTMASK, SC_MODEVENTMASKALL); + g_notes.clear(); + Send(SCI_SETTEXT, 0, "\xE4x"); + bool before = false; + for (const Note& n : g_notes) + before = before || (n.modificationType & SC_MOD_BEFOREINSERT); + CHECK(before); + Send(SCI_SETMODEVENTMASK, SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT); +} + +void TestSanitizedInput() { + mfcwx::SetAnsiCodePage(1252); + g_stc->SetText(wxString::FromUTF8("x\xE4\xB8\xAD" "y\xC5\x82\xC3\xA9")); + CHECK_STR(GetAll(), "x?y?\xE9"); + CHECK(g_stc->GetText() == wxString::FromUTF8("x?y?\xC3\xA9")); + g_stc->InsertText(0, wxString::FromUTF8("\xE2\x82\xAC")); + CHECK_STR(GetAll(), "\x80x?y?\xE9"); + CHECK_EQ(Send(SCI_GETLENGTH), 6); +} + +void TestMisc() { + mfcwx::SetAnsiCodePage(1252); + Send(SCI_SETWRAPMODE, SC_WRAP_WORD); + CHECK_EQ(Send(SCI_GETWRAPMODE), SC_WRAP_WORD); + CHECK_EQ(g_stc->GetWrapMode(), wxSTC_WRAP_WHITESPACE); + Send(SCI_SETWRAPMODE, SC_WRAP_CHAR); + CHECK_EQ(Send(SCI_GETWRAPMODE), SC_WRAP_CHAR); + Send(SCI_SETWRAPMODE, SC_WRAP_NONE); + + Send(SCI_SETCODEPAGE, 0); + CHECK_EQ(Send(SCI_GETCODEPAGE), 0); + CHECK_EQ(g_stc->GetCodePage(), wxSTC_CP_UTF8); + + Send(SCI_SETTEXT, 0, "\xE4\xF6\xFC"); + struct { + void* hdc; + void* hdcTarget; + int rc[4]; + int rcPage[4]; + CharacterRange chrg; + } fr = {nullptr, nullptr, {0, 0, 100, 100}, {0, 0, 100, 100}, {0, 3}}; + CHECK_EQ(Send(SCI_FORMATRANGE, 1, &fr), 3); + CHECK(Send(SCI_TEXTWIDTH, STYLE_LINENUMBER, "9") > 0); + Send(SCI_STYLESETFONT, STYLE_DEFAULT, "Courier"); + char font[64]; + CHECK_EQ(Send(SCI_STYLEGETFONT, STYLE_DEFAULT, font), 7); + CHECK_STR(font, "Courier"); + + Send(SCI_EMPTYUNDOBUFFER); + CHECK_EQ(Send(SCI_CANUNDO), 0); + Send(SCI_SETSEL, 0, 3); + Send(SCI_COPY); + Send(SCI_SETUNDOCOLLECTION, 0); + Send(SCI_SETUNDOCOLLECTION, 1); + CHECK_EQ(Send(SCI_BRACEMATCH, W(-1)), -1); + Send(SCI_SETTEXT, 0, "(\xE4)"); + CHECK_EQ(Send(SCI_BRACEMATCH, 0), 2); + CHECK_EQ(Send(SCI_BRACEMATCH, 2), 0); + Send(SCI_BRACEHIGHLIGHT, 0, 2); +} + +void TestClipboardBytes() { + mfcwx::SetAnsiCodePage(1252); + const std::string t("ab\0c\xE9\r\nd\0", 9); + SetBytes(t); + + g_remembered.clear(); + Send(SCI_SETSEL, 1, 8); + Send(SCI_COPY); + CHECK_EQ(g_remembered.size(), 1); + CHECK(g_remembered.back().first == t.substr(1, 7)); + CHECK_EQ(g_remembered.back().second, 7); + + g_remembered.clear(); + Send(SCI_SETSEL, 3, 3); + Send(SCI_COPY); + CHECK_EQ(g_remembered.size(), 0); + + g_remembered.clear(); + Send(SCI_COPYRANGE, 2, 5); + CHECK_EQ(g_remembered.size(), 1); + CHECK(g_remembered.back().first == t.substr(2, 3)); + + g_remembered.clear(); + Send(SCI_COPYTEXT, 4, "x\0y\xFC"); + CHECK_EQ(g_remembered.size(), 1); + CHECK(g_remembered.back().first == std::string("x\0y\xFC", 4)); + + g_remembered.clear(); + Send(WM_COPY); + CHECK_EQ(g_remembered.size(), 0); + Send(SCI_SETSEL, 0, 9); + Send(WM_COPY); + CHECK_EQ(g_remembered.size(), 1); + CHECK(g_remembered.back().first == t); + + g_remembered.clear(); + Send(SCI_SETSEL, 2, 4); + Send(WM_CUT); + CHECK_EQ(g_remembered.size(), 1); + CHECK(g_remembered.back().first == t.substr(2, 2)); + CHECK_STR(GetAll(), t.substr(0, 2) + t.substr(4)); + mfcwx::SetAnsiCodePage(1252); +} + +void TestLargeDocument() { + mfcwx::SetAnsiCodePage(1250); + std::mt19937 rng(12345); + auto randomText = [&rng](size_t n) { + std::string s; + s.reserve(n); + for (size_t i = 0; i < n; ++i) { + unsigned r = rng() % 100; + if (r < 60) + s.push_back(static_cast('a' + rng() % 26)); + else if (r < 65) + s.append("\r\n"); + else + s.push_back(static_cast(0x80 + rng() % 128)); + } + return s; + }; + std::string model = randomText(300000); + auto t0 = std::chrono::steady_clock::now(); + SetBytes(model); + std::string copy = GetAll(); + long long sum = 0; + for (int i = 0; i < 20000; ++i) { + int p = static_cast(rng() % (model.size() + 1)); + sum += Send(SCI_LINEFROMPOSITION, W(p)) + Send(SCI_POSITIONAFTER, W(p)); + } + for (int i = 0; i < 2000; ++i) { + int p = static_cast(rng() % model.size()); + Send(SCI_INSERTTEXT, W(p), "\xE4"); + Send(SCI_SETTARGETSTART, W(p)); + Send(SCI_SETTARGETEND, W(p + 1)); + Send(SCI_REPLACETARGET, 0, ""); + sum += Send(SCI_GETLENGTH); + } + double proxyMs = std::chrono::duration(std::chrono::steady_clock::now() - t0).count(); + auto t1 = std::chrono::steady_clock::now(); + for (int i = 0; i < 20000; ++i) { + int p = static_cast(rng() % (model.size() + 1)); + sum += g_stc->SendMsg(SCI_LINEFROMPOSITION, p) + g_stc->SendMsg(SCI_POSITIONAFTER, p); + } + for (int i = 0; i < 2000; ++i) { + int p = static_cast(rng() % model.size()); + g_stc->SendMsg(SCI_INSERTTEXT, p, reinterpret_cast("\xC3\xA4")); + g_stc->SendMsg(SCI_SETTARGETSTART, p); + g_stc->SendMsg(SCI_SETTARGETEND, p + 2); + g_stc->SendMsg(SCI_REPLACETARGET, 0, reinterpret_cast("")); + sum += g_stc->SendMsg(SCI_GETLENGTH); + } + double rawMs = std::chrono::duration(std::chrono::steady_clock::now() - t1).count(); + printf("large document: load + 20000 lookups + 2000 edits: proxy %.1f ms, same calls sent to wx directly %.1f ms (%lld)\n", + proxyMs, rawMs, sum); + CHECK(copy == model); + CHECK(GetAll() == model); + bool ok = Send(SCI_GETLENGTH) == static_cast(model.size()); + for (int i = 0; i < 300 && ok; ++i) { + int p = static_cast(rng() % (model.size() + 1)); + Send(SCI_GOTOPOS, W(p)); + ok = Send(SCI_GETCURRENTPOS) == p && g_stc->GetCurrentPos() == g_stc->PositionRelative(0, p); + if (!ok) + fprintf(stderr, "position %d mismatch\n", p); + if (p < static_cast(model.size())) + ok = ok && Send(SCI_GETCHARAT, W(p)) == static_cast(model[static_cast(p)]); + } + CHECK(ok); + for (int i = 0; i < 300 && ok; ++i) { + int op = static_cast(rng() % 3); + int p = static_cast(rng() % (model.size() + 1)); + if (op == 0) { + std::string ins = randomText(1 + rng() % 20); + Send(SCI_INSERTTEXT, W(p), ins.c_str()); + model.insert(static_cast(p), ins); + } else if (op == 1 && p < static_cast(model.size())) { + int n = std::min(static_cast(1 + rng() % 30), static_cast(model.size()) - p); + Send(SCI_SETSEL, W(p), static_cast(p + n)); + Send(SCI_CLEAR); + model.erase(static_cast(p), static_cast(n)); + } else { + int n = std::min(static_cast(rng() % 50), static_cast(model.size()) - p); + ok = Range(p, p + n) == model.substr(static_cast(p), static_cast(n)); + } + ok = ok && Send(SCI_GETLENGTH) == static_cast(model.size()); + int q = static_cast(rng() % (model.size() + 1)); + ok = ok && Send(SCI_LINEFROMPOSITION, W(q)) == g_stc->LineFromPosition(g_stc->PositionRelative(0, q)); + } + CHECK(ok); + CHECK(GetAll() == model); + double ms = std::chrono::duration(std::chrono::steady_clock::now() - t0).count(); + printf("large document: %zu chars, total with brute-force verification %.1f ms\n", model.size(), ms); + mfcwx::SetAnsiCodePage(1252); +} + +int RunTests() { + wxFrame* frame = new wxFrame(nullptr, wxID_ANY, "scintilla tests"); + g_stc = new wxStyledTextCtrl(frame, wxID_ANY); + mfcwx::BindScintillaEvents(g_stc); + TestCp1252RoundTrip(); + TestAllBytes(); + TestCp1250Positions(); + TestDirectFunction(); + TestCrypToolLexer(); + TestContainerStyling(); + TestNotifications(); + TestSanitizedInput(); + TestMisc(); + TestClipboardBytes(); + TestLargeDocument(); + frame->Destroy(); + printf("%d checks, %d failures\n", g_checks, g_failures); + return g_failures ? 1 : 0; +} + +int g_rc = 1; + +class TestApp : public wxApp { +public: + bool OnInit() override { + g_rc = RunTests(); + return false; + } +}; + +} // namespace + +namespace mfcwx { + +void NotifyParent(wxWindow*, UINT code) { g_commands.push_back(code); } + +LRESULT NotifyParentNM(wxWindow* control, NMHDR* hdr) { + hdr->hwndFrom = ToHwnd(control); + const SCNotification& scn = *reinterpret_cast(hdr); + Note n; + n.code = scn.nmhdr.code; + n.position = scn.position; + n.length = scn.length; + n.modificationType = scn.modificationType; + n.ch = scn.ch; + if (scn.text) + n.text.assign(scn.text, static_cast(scn.length)); + g_notes.push_back(n); + if (g_onNotify) + g_onNotify(scn); + return 0; +} + +void RememberClipboardText(std::string ansiBytes, size_t minSize) { g_remembered.emplace_back(std::move(ansiBytes), minSize); } + +bool IsMainThread() { return true; } +void RunOnMainThread(const std::function& fn) { fn(); } + +} // namespace mfcwx + +CDC* CDC::FromHandle(HDC) { return nullptr; } +wxDC* CDC::GetWx() const { return nullptr; } + +wxIMPLEMENT_APP_NO_MAIN(TestApp); + +int main(int argc, char** argv) { + wxEntry(argc, argv); + return g_rc; +} diff --git a/port/rc/rc2cpp.cmake b/port/rc/rc2cpp.cmake new file mode 100644 index 000000000..6c6307dac --- /dev/null +++ b/port/rc/rc2cpp.cmake @@ -0,0 +1,133 @@ +include_guard(GLOBAL) + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Cached so the function also works in directories other than the one that included this file first. +set(MFCWX_RC_PYTHON "${Python3_EXECUTABLE}" CACHE INTERNAL "") +set(MFCWX_RC2CPP_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/rc2cpp.py" CACHE INTERNAL "") +get_filename_component(rc_include_dir "${CMAKE_CURRENT_LIST_DIR}/../mfcwx/include" ABSOLUTE) +set(MFCWX_RC_INCLUDE_DIR "${rc_include_dir}" CACHE INTERNAL "") + +# mfcwx_add_rc( RC [MODULE ] [HEADERS ...] [OUTPUT_DIR ] [INCLUDE_DIRS ...] [DEFINES ...] +# [REPLACE ...] [CODEPAGE ]) +function(mfcwx_add_rc target) + cmake_parse_arguments(PARSE_ARGV 1 ARG "" "RC;MODULE;OUTPUT_DIR;CODEPAGE" "HEADERS;INCLUDE_DIRS;DEFINES;REPLACE") + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "mfcwx_add_rc: unexpected arguments: ${ARG_UNPARSED_ARGUMENTS}") + endif() + if(NOT ARG_RC) + message(FATAL_ERROR "mfcwx_add_rc: RC is required") + endif() + + get_filename_component(rc "${ARG_RC}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(rc_dir "${rc}" DIRECTORY) + get_filename_component(rc_name "${rc}" NAME) + if(NOT ARG_MODULE) + get_filename_component(ARG_MODULE "${rc}" NAME_WE) + endif() + string(MAKE_C_IDENTIFIER "${ARG_MODULE}" module) + if(NOT ARG_OUTPUT_DIR) + set(ARG_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/rc2cpp/${module}") + endif() + get_filename_component(out_dir "${ARG_OUTPUT_DIR}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + + set(headers) + foreach(h IN LISTS ARG_HEADERS) + get_filename_component(h "${h}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + list(APPEND headers "${h}") + endforeach() + + set(args "${rc}" --module "${module}" --out-dir "${out_dir}" -I "${MFCWX_RC_INCLUDE_DIR}") + foreach(d IN LISTS ARG_INCLUDE_DIRS) + get_filename_component(d "${d}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + list(APPEND args -I "${d}") + endforeach() + foreach(d IN LISTS ARG_DEFINES) + list(APPEND args -D "${d}") + endforeach() + foreach(r IN LISTS ARG_REPLACE) + list(APPEND args --replace "${r}") + endforeach() + if(ARG_CODEPAGE) + list(APPEND args --codepage "${ARG_CODEPAGE}") + endif() + + # Output names depend on the language set; the build rewrites outputs_file when it changes, which re-runs CMake. + set(outputs_file "${out_dir}/${module}_outputs.txt") + execute_process( + COMMAND "${MFCWX_RC_PYTHON}" "${MFCWX_RC2CPP_SCRIPT}" ${args} --list-outputs --outputs-file "${outputs_file}" + OUTPUT_VARIABLE listed + ERROR_VARIABLE errors + RESULT_VARIABLE result) + if(NOT result EQUAL 0) + message(FATAL_ERROR "mfcwx_add_rc: rc2cpp.py failed for ${rc}:\n${errors}") + endif() + string(STRIP "${listed}" listed) + string(REPLACE "\n" ";" listed "${listed}") + set(sources ${listed}) + list(FILTER sources INCLUDE REGEX "\\.cpp$") + set(files_list "${out_dir}/${module}_files.txt") + + set(depfile_args) + set(depfile_cli) + if(CMAKE_GENERATOR MATCHES "Ninja") + set(depfile "${out_dir}/${module}.d") + set(depfile_args DEPFILE "${depfile}") + set(depfile_cli --depfile "${depfile}") + endif() + + add_custom_command( + OUTPUT ${sources} "${files_list}" + COMMAND "${MFCWX_RC_PYTHON}" "${MFCWX_RC2CPP_SCRIPT}" ${args} --quiet --outputs-file "${outputs_file}" ${depfile_cli} + DEPENDS + "${rc}" ${headers} "${MFCWX_RC2CPP_SCRIPT}" + "${MFCWX_RC_INCLUDE_DIR}/mfcwx/winconst.h" "${MFCWX_RC_INCLUDE_DIR}/afxres.h" + ${depfile_args} + COMMENT "rc2cpp: generating resource tables for ${module} from ${rc_name}" + VERBATIM) + + target_sources(${target} PRIVATE ${sources}) + set_source_files_properties(${sources} PROPERTIES GENERATED TRUE) + set_property(SOURCE ${sources} APPEND PROPERTY INCLUDE_DIRECTORIES "${MFCWX_RC_INCLUDE_DIR}") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${outputs_file}") + set_property(TARGET ${target} APPEND PROPERTY MFCWX_RC_FILE_LISTS "${files_list}") + set_property(TARGET ${target} APPEND PROPERTY MFCWX_RC_BASE_DIRS "${rc_dir}") + + set(MFCWX_RC_${module}_SOURCES "${sources}" PARENT_SCOPE) + set(MFCWX_RC_${module}_FILES_LIST "${files_list}" PARENT_SCOPE) +endfunction() + +# mfcwx_install_rc_files( DESTINATION [COMPONENT ]): installs the files referenced by the target's .rc files. +function(mfcwx_install_rc_files target) + cmake_parse_arguments(PARSE_ARGV 1 ARG "" "DESTINATION;COMPONENT" "") + if(NOT ARG_DESTINATION) + message(FATAL_ERROR "mfcwx_install_rc_files: DESTINATION is required") + endif() + get_property(lists TARGET ${target} PROPERTY MFCWX_RC_FILE_LISTS) + get_property(dirs TARGET ${target} PROPERTY MFCWX_RC_BASE_DIRS) + if(IS_ABSOLUTE "${ARG_DESTINATION}") + set(dest "${ARG_DESTINATION}") + else() + set(dest "\${CMAKE_INSTALL_PREFIX}/${ARG_DESTINATION}") + endif() + set(component) + if(ARG_COMPONENT) + set(component COMPONENT "${ARG_COMPONENT}") + endif() + list(LENGTH lists count) + if(count EQUAL 0) + return() + endif() + math(EXPR last "${count} - 1") + foreach(i RANGE ${last}) + list(GET lists ${i} list_file) + list(GET dirs ${i} base_dir) + install(CODE " + file(STRINGS \"${list_file}\" _mfcwx_rc_files) + foreach(_mfcwx_rc_file IN LISTS _mfcwx_rc_files) + get_filename_component(_mfcwx_rc_dir \"\${_mfcwx_rc_file}\" DIRECTORY) + file(INSTALL DESTINATION \"${dest}/\${_mfcwx_rc_dir}\" TYPE FILE FILES \"${base_dir}/\${_mfcwx_rc_file}\") + endforeach()" + ${component}) + endforeach() +endfunction() diff --git a/port/rc/rc2cpp.py b/port/rc/rc2cpp.py new file mode 100755 index 000000000..67bc5361d --- /dev/null +++ b/port/rc/rc2cpp.py @@ -0,0 +1,2019 @@ +#!/usr/bin/env python3 +"""Convert a Windows resource script (.rc) into C++ tables for mfcwx::rc (see mfcwx/rcdata.h).""" + +import argparse +import codecs +import os +import re +import sys + +WS_POPUP = 0x80000000 +WS_CHILD = 0x40000000 +WS_VISIBLE = 0x10000000 +WS_CAPTION = 0x00C00000 +WS_BORDER = 0x00800000 +WS_SYSMENU = 0x00080000 +WS_GROUP = 0x00020000 +WS_TABSTOP = 0x00010000 +DS_SETFONT = 0x40 +SS_LEFT, SS_CENTER, SS_RIGHT, SS_ICON = 0, 1, 2, 3 +(BS_PUSHBUTTON, BS_DEFPUSHBUTTON, BS_CHECKBOX, BS_AUTOCHECKBOX, BS_RADIOBUTTON, BS_3STATE, + BS_AUTO3STATE, BS_GROUPBOX, BS_USERBUTTON, BS_AUTORADIOBUTTON, BS_PUSHBOX) = range(11) +ES_LEFT = 0 +CBS_SIMPLE = 0x1 +CBS_TYPEMASK = 0x3 +LBS_NOTIFY = 0x1 +SBS_HORZ = 0 + +MF_GRAYED = 0x1 +MF_DISABLED = 0x2 +MF_CHECKED = 0x8 +MF_POPUP = 0x10 +MF_MENUBARBREAK = 0x20 +MF_MENUBREAK = 0x40 +MF_SEPARATOR = 0x800 +MF_HELP = 0x4000 + +FVIRTKEY = 0x01 +FNOINVERT = 0x02 +FSHIFT = 0x04 +FCONTROL = 0x08 +FALT = 0x10 + +CHILD = WS_CHILD | WS_VISIBLE + +TEXT_CONTROLS = { + 'LTEXT': ('Static', SS_LEFT | WS_GROUP), + 'RTEXT': ('Static', SS_RIGHT | WS_GROUP), + 'CTEXT': ('Static', SS_CENTER | WS_GROUP), + 'PUSHBUTTON': ('Button', BS_PUSHBUTTON | WS_TABSTOP), + 'DEFPUSHBUTTON': ('Button', BS_DEFPUSHBUTTON | WS_TABSTOP), + 'PUSHBOX': ('Button', BS_PUSHBOX | WS_TABSTOP), + 'USERBUTTON': ('Button', BS_USERBUTTON | WS_TABSTOP), + 'CHECKBOX': ('Button', BS_CHECKBOX | WS_TABSTOP), + 'AUTOCHECKBOX': ('Button', BS_AUTOCHECKBOX | WS_TABSTOP), + 'STATE3': ('Button', BS_3STATE | WS_TABSTOP), + 'AUTO3STATE': ('Button', BS_AUTO3STATE | WS_TABSTOP), + 'RADIOBUTTON': ('Button', BS_RADIOBUTTON), + 'AUTORADIOBUTTON': ('Button', BS_AUTORADIOBUTTON), + 'GROUPBOX': ('Button', BS_GROUPBOX), +} + +PLAIN_CONTROLS = { + 'EDITTEXT': ('Edit', ES_LEFT | WS_BORDER | WS_TABSTOP), + 'COMBOBOX': ('ComboBox', WS_TABSTOP), + 'LISTBOX': ('ListBox', LBS_NOTIFY | WS_BORDER), + 'SCROLLBAR': ('ScrollBar', SBS_HORZ), +} + +CLASS_NAMES = {'BUTTON': 'Button', 'EDIT': 'Edit', 'STATIC': 'Static', 'LISTBOX': 'ListBox', + 'SCROLLBAR': 'ScrollBar', 'COMBOBOX': 'ComboBox'} +CLASS_ORDINALS = {0x80: 'Button', 0x81: 'Edit', 0x82: 'Static', 0x83: 'ListBox', 0x84: 'ScrollBar', + 0x85: 'ComboBox'} + +MENU_OPTIONS = {'GRAYED': MF_GRAYED, 'INACTIVE': MF_DISABLED, 'CHECKED': MF_CHECKED, + 'MENUBARBREAK': MF_MENUBARBREAK, 'MENUBREAK': MF_MENUBREAK, 'HELP': MF_HELP} +ACCEL_OPTIONS = {'VIRTKEY': FVIRTKEY, 'ASCII': 0, 'NOINVERT': FNOINVERT, 'SHIFT': FSHIFT, + 'CONTROL': FCONTROL, 'ALT': FALT} + +MEMORY_OPTIONS = {'DISCARDABLE', 'MOVEABLE', 'FIXED', 'PURE', 'IMPURE', 'PRELOAD', 'LOADONCALL', + 'SHARED', 'NONSHARED'} +FILE_TYPES = {'BITMAP', 'ICON', 'CURSOR', 'FONT', 'FONTDIR', 'HTML', 'MESSAGETABLE', 'ANICURSOR', + 'ANIICON', 'MANIFEST', 'PLUGPLAY', 'VXD', 'RCDATA', 'DLGINCLUDE'} +SKIP_TYPES = {'TEXTINCLUDE', 'DESIGNINFO', 'AFX_DIALOG_LAYOUT'} +TOP_TYPES = {'DIALOG', 'DIALOGEX', 'MENU', 'MENUEX', 'ACCELERATORS', 'TOOLBAR', 'DLGINIT', + 'VERSIONINFO'} | FILE_TYPES | SKIP_TYPES +RT_NAMES = {1: 'CURSOR', 2: 'BITMAP', 3: 'ICON', 4: 'MENU', 5: 'DIALOG', 6: 'STRING', 7: 'FONTDIR', + 8: 'FONT', 9: 'ACCELERATOR', 10: 'RCDATA', 11: 'MESSAGETABLE', 12: 'GROUP_CURSOR', + 14: 'GROUP_ICON', 16: 'VERSION', 17: 'DLGINCLUDE', 19: 'PLUGPLAY', 20: 'VXD', + 21: 'ANICURSOR', 22: 'ANIICON', 23: 'HTML', 24: 'MANIFEST', 240: 'DLGINIT', 241: 'TOOLBAR'} + +DLGINIT_TEXT_MESSAGES = {0x0401, 0x0403, 0x1234} + +BUILTIN_SYMBOLS = { + 'LANG_NEUTRAL': 0x00, 'LANG_CHINESE': 0x04, 'LANG_CZECH': 0x05, 'LANG_DANISH': 0x06, + 'LANG_GERMAN': 0x07, 'LANG_GREEK': 0x08, 'LANG_ENGLISH': 0x09, 'LANG_SPANISH': 0x0a, + 'LANG_FINNISH': 0x0b, 'LANG_FRENCH': 0x0c, 'LANG_HUNGARIAN': 0x0e, 'LANG_ITALIAN': 0x10, + 'LANG_JAPANESE': 0x11, 'LANG_KOREAN': 0x12, 'LANG_DUTCH': 0x13, 'LANG_NORWEGIAN': 0x14, + 'LANG_POLISH': 0x15, 'LANG_PORTUGUESE': 0x16, 'LANG_RUSSIAN': 0x19, 'LANG_CROATIAN': 0x1a, + 'LANG_SERBIAN': 0x1a, 'LANG_SWEDISH': 0x1d, 'LANG_TURKISH': 0x1f, + 'SUBLANG_NEUTRAL': 0x00, 'SUBLANG_DEFAULT': 0x01, 'SUBLANG_SYS_DEFAULT': 0x02, + 'SUBLANG_GERMAN': 0x01, 'SUBLANG_GERMAN_SWISS': 0x02, 'SUBLANG_GERMAN_AUSTRIAN': 0x03, + 'SUBLANG_ENGLISH_US': 0x01, 'SUBLANG_ENGLISH_UK': 0x02, 'SUBLANG_FRENCH': 0x01, + 'SUBLANG_FRENCH_SWISS': 0x04, 'SUBLANG_SPANISH': 0x01, 'SUBLANG_SPANISH_MODERN': 0x03, + 'SUBLANG_SERBIAN_LATIN': 0x02, 'SUBLANG_SERBIAN_CYRILLIC': 0x03, 'SUBLANG_POLISH_POLAND': 0x01, + 'SUBLANG_GREEK_GREECE': 0x01, 'SUBLANG_RUSSIAN_RUSSIA': 0x01, + 'VS_VERSION_INFO': 1, +} + +LANG_CODE_BY_ID = {(0x07, 0x02): 'de-CH', (0x1a, 0x01): 'hr'} +LANG_CODE_BY_PRIMARY = { + 0x04: 'zh', 0x05: 'cs', 0x06: 'da', 0x07: 'de', 0x08: 'el', 0x09: 'en', 0x0a: 'es', 0x0b: 'fi', + 0x0c: 'fr', 0x0e: 'hu', 0x10: 'it', 0x11: 'ja', 0x12: 'ko', 0x13: 'nl', 0x14: 'no', 0x15: 'pl', + 0x16: 'pt', 0x19: 'ru', 0x1a: 'rs', 0x1d: 'sv', 0x1f: 'tr', +} + +HEADER_ALIASES = {name: 'mfcwx/winconst.h' for name in ( + 'windows.h', 'winres.h', 'winresrc.h', 'winuser.h', 'winver.h', 'commctrl.h', 'winnt.h', + 'windef.h', 'richedit.h', 'dlgs.h', 'winuser.rh', 'commctrl.rh', 'winnt.rh')} +RC_EXTENSIONS = {'.rc', '.rc2', '.rc3', '.dlg'} + +CAST_TYPES = { + 'BYTE': (8, False), 'UCHAR': (8, False), 'unsigned char': (8, False), 'char': (8, True), + 'WORD': (16, False), 'USHORT': (16, False), 'WCHAR': (16, False), 'ATOM': (16, False), + 'unsigned short': (16, False), 'SHORT': (16, True), 'short': (16, True), + 'DWORD': (32, False), 'UINT': (32, False), 'ULONG': (32, False), 'unsigned': (32, False), + 'unsigned int': (32, False), 'unsigned long': (32, False), 'COLORREF': (32, False), + 'LCID': (32, False), 'int': (32, True), 'INT': (32, True), 'LONG': (32, True), + 'long': (32, True), 'BOOL': (32, True), +} + +PREC = {'||': 1, '&&': 2, '|': 3, '^': 4, '&': 5, '==': 6, '!=': 6, '<': 7, '>': 7, '<=': 7, + '>=': 7, '<<': 8, '>>': 8, '+': 9, '-': 9, '*': 10, '/': 10, '%': 10} + + +class Tok: + __slots__ = ('k', 'v', 's', 'x', 'cp', 'ln', 'fi') + + def __init__(self, k, v, s, x, cp, ln, fi): + self.k = k + self.v = v + self.s = s + self.x = x + self.cp = cp + self.ln = ln + self.fi = fi + + +EOF_TOK = Tok('eof', None, '', None, 0, 0, 0) + +LEX_RE = re.compile(r''' + (?P[ \t\f\v\x00\x1a]+) + | (?P//.*) + | (?P/\*) + | (?PL?"(?:[^"\\]|\\.|"")*") + | (?PL?"(?:[^"\\]|\\.|"")*) + | (?P0[xX][0-9A-Fa-f]*[uUlL]*|[0-9]+[uUlL]*) + | (?P[A-Za-z_][A-Za-z0-9_]*) + | (?P<<|>>|<=|>=|==|!=|&&|\|\||.) +''', re.X) + + +def lex(text, out, cp, ln, fi, unterminated=None): + pos = 0 + n = len(text) + match = LEX_RE.match + append = out.append + while pos < n: + m = match(text, pos) + g = m.lastgroup + pos = m.end() + if g == 'ws': + continue + if g == 'lc': + break + if g == 'bc': + e = text.find('*/', pos) + if e < 0: + return True + pos = e + 2 + continue + s = m.group() + if g == 'i': + append(Tok('id', s, s, None, cp, ln, fi)) + elif g == 'n': + body = s.rstrip('uUlL') + suffix = s[len(body):].lower() + if body[:2] in ('0x', '0X'): + v = int(body[2:], 16) if len(body) > 2 else 0 + else: + v = int(body) + append(Tok('num', v, s, 'l' in suffix, cp, ln, fi)) + elif g == 's': + wide = s[0] == 'L' + append(Tok('str', s[2 if wide else 1:-1], s, wide, cp, ln, fi)) + elif g == 'su': + wide = s[0] == 'L' + if unterminated is not None: + unterminated(ln, fi) + append(Tok('str', s[2 if wide else 1:], s, wide, cp, ln, fi)) + else: + append(Tok('op', s, s, None, cp, ln, fi)) + return False + + +def describe(t): + if t.k == 'eof': + return 'end of input' + if t.k == 'str': + return 'string' + return "'%s'" % t.s + + +class Diag: + def __init__(self, quiet): + self.quiet = quiet + self.errors = 0 + self.warnings = 0 + + def error(self, loc, msg): + self.errors += 1 + print('%s: error: %s' % (loc, msg), file=sys.stderr) + + def warn(self, loc, msg): + self.warnings += 1 + if not self.quiet: + print('%s: warning: %s' % (loc, msg), file=sys.stderr) + + def note(self, msg): + if not self.quiet: + print('rc2cpp: %s' % msg, file=sys.stderr) + + +class EvalError(Exception): + pass + + +class ParseError(Exception): + def __init__(self, tok, msg): + Exception.__init__(self, msg) + self.tok = tok + self.msg = msg + + +class Cursor: + __slots__ = ('t', 'i', 'n', 'eof') + + def __init__(self, toks, eof=None): + self.t = toks + self.i = 0 + self.n = len(toks) + self.eof = eof or EOF_TOK + + def peek(self, k=0): + j = self.i + k + return self.t[j] if j < self.n else self.eof + + def next(self): + i = self.i + if i < self.n: + self.i = i + 1 + return self.t[i] + return self.eof + + def at_eof(self): + return self.i >= self.n + + +def apply_cast(name, v): + spec = CAST_TYPES.get(name) + if spec is None: + return v + bits, signed = spec + v &= (1 << bits) - 1 + if signed and v >> (bits - 1): + v -= 1 << bits + return v + + +def binop(o, a, b): + if o == '|': + return a | b + if o == '&': + return a & b + if o == '+': + return a + b + if o == '-': + return a - b + if o == '^': + return a ^ b + if o == '<<': + return a << (b & 63) + if o == '>>': + return a >> (b & 63) + if o == '*': + return a * b + if o in ('/', '%'): + if b == 0: + raise EvalError('division by zero') + q = abs(a) // abs(b) + if (a < 0) != (b < 0): + q = -q + return q if o == '/' else a - q * b + if o == '==': + return int(a == b) + if o == '!=': + return int(a != b) + if o == '<': + return int(a < b) + if o == '>': + return int(a > b) + if o == '<=': + return int(a <= b) + if o == '>=': + return int(a >= b) + if o == '&&': + return int(bool(a) and bool(b)) + if o == '||': + return int(bool(a) or bool(b)) + raise EvalError("unsupported operator '%s'" % o) + + +class Evaluator: + def __init__(self, macros): + self.macros = macros + self.expanding = set() + self.cache = None + self.saw_long = False + self.undefined = {} + self.undefined_hits = 0 + self.builtins_used = set() + + def freeze(self): + self.cache = {} + + def eval_pp(self, toks): + cur = Cursor(toks) + v = self.expr(cur, 1, True) + if not cur.at_eof(): + raise EvalError('unexpected %s in #if expression' % describe(cur.peek())) + return v + + def expr(self, cur, min_prec=1, pp=False): + v = self.unary(cur, pp) + while True: + t = cur.peek() + if t.k != 'op': + return v + p = PREC.get(t.v) + if p is None or p < min_prec: + return v + cur.next() + v = binop(t.v, v, self.expr(cur, p + 1, pp)) + + def expect_close(self, cur): + t = cur.next() + if t.k != 'op' or t.v != ')': + raise EvalError("expected ')' but found %s" % describe(t)) + + def unary(self, cur, pp=False): + t = cur.next() + k = t.k + if k == 'num': + if t.x: + self.saw_long = True + return t.v + if k == 'id': + if pp and t.v == 'defined': + nt = cur.peek() + paren = nt.k == 'op' and nt.v == '(' + if paren: + cur.next() + n = cur.next() + if n.k != 'id': + raise EvalError("expected identifier after 'defined'") + if paren: + self.expect_close(cur) + return 1 if n.v in self.macros else 0 + if not pp and t.v.upper() == 'NOT' and t.v not in self.macros: + return ~self.unary(cur, pp) + return self.ident(t, cur, pp) + if k == 'op': + o = t.v + if o == '(': + cast = self.try_cast(cur) + if cast is not None: + return apply_cast(cast, self.unary(cur, pp)) + v = self.expr(cur, 1, pp) + self.expect_close(cur) + return v + if o == '-': + return -self.unary(cur, pp) + if o == '+': + return self.unary(cur, pp) + if o == '~': + return ~self.unary(cur, pp) + if o == '!': + return 0 if self.unary(cur, pp) else 1 + if k == 'eof': + raise EvalError('unexpected end of expression') + raise EvalError('unexpected %s in expression' % describe(t)) + + def is_object_macro(self, name): + m = self.macros.get(name) + return m is not None and m[0] is None + + def is_symbol(self, name): + return self.is_object_macro(name) or name in BUILTIN_SYMBOLS + + def try_cast(self, cur): + j = 0 + words = [] + while True: + t = cur.peek(j) + if t.k == 'id' and not self.is_symbol(t.v): + words.append(t.v) + elif t.k == 'op' and t.v == '*' and words: + words.append('*') + else: + break + j += 1 + if not words: + return None + t = cur.peek(j) + if t.k != 'op' or t.v != ')': + return None + a = cur.peek(j + 1) + if not (a.k in ('num', 'id') or (a.k == 'op' and a.v in ('(', '-', '~', '+', '!'))): + return None + for _ in range(j + 1): + cur.next() + return ' '.join(words) + + def collect_args(self, cur): + cur.next() + args = [[]] + depth = 1 + while True: + t = cur.next() + if t.k == 'eof': + raise EvalError('unterminated macro argument list') + if t.k == 'op': + if t.v == '(': + depth += 1 + elif t.v == ')': + depth -= 1 + if depth == 0: + break + elif t.v == ',' and depth == 1: + args.append([]) + continue + args[-1].append(t) + return args + + def ident(self, t, cur, pp): + name = t.v + m = self.macros.get(name) + if m is None: + if pp: + return 0 + b = BUILTIN_SYMBOLS.get(name) + if b is not None: + self.builtins_used.add(name) + return b + self.undefined_hits += 1 + rec = self.undefined.get(name) + if rec is None: + self.undefined[name] = [1, t] + else: + rec[0] += 1 + return 0 + params, body = m + if params is not None: + nt = cur.peek() + if nt.k != 'op' or nt.v != '(': + if not pp: + self.undefined_hits += 1 + self.undefined.setdefault(name, [0, t])[0] += 1 + return 0 + args = self.collect_args(cur) + index = {p: i for i, p in enumerate(params)} + expanded = [] + for bt in body: + if bt.k == 'id' and bt.v in index and index[bt.v] < len(args): + expanded.extend(args[index[bt.v]]) + else: + expanded.append(bt) + body = expanded + elif self.cache is not None and not pp: + c = self.cache.get(name) + if c is not None: + if c[1]: + self.saw_long = True + return c[0] + if name in self.expanding: + raise EvalError("recursive macro '%s'" % name) + self.expanding.add(name) + saved = self.saw_long + self.saw_long = False + try: + if body: + sub = Cursor(body) + v = self.expr(sub, 1, pp) + if not sub.at_eof(): + raise EvalError("macro '%s' is not a constant expression" % name) + else: + v = 0 + finally: + self.expanding.discard(name) + long_seen = self.saw_long + self.saw_long = saved or long_seen + if params is None and self.cache is not None and not pp: + self.cache[name] = (v, long_seen) + return v + + +def codec_for(cp): + if cp == 65001: + return 'utf-8' + name = 'cp%d' % cp + try: + codecs.lookup(name) + return name + except LookupError: + return None + + +STRING_ESC_RE = re.compile(r'""|\\(?:[0-7]{1,3}|[xX][0-9A-Fa-f]{1,2}|.)') +STRING_ESC_WIDE_RE = re.compile(r'""|\\(?:[0-7]{1,3}|[xX][0-9A-Fa-f]{1,4}|.)') +SIMPLE_ESCAPES = {'n': '\n', 't': '\t', 'r': '\r', '\\': '\\', '"': '"', + 'a': '\x08'} # rc.exe maps \a to 0x08, not BEL + + +def _esc_value(e): + if e == '""': + return 34, False + c = e[1] + if c in SIMPLE_ESCAPES: + return ord(SIMPLE_ESCAPES[c]), False + if c in '01234567': + return int(e[1:], 8), True + if c in 'xX' and len(e) > 2: + return int(e[2:], 16), True + return None, False + + +def _narrow_sub(m): + v, _ = _esc_value(m.group()) + if v is None: + return m.group() + return chr(v & 0xFF) + + +def string_bytes(raw, wide, cp): + if not wide and cp != 1200: + if '\\' in raw or '"' in raw: + raw = STRING_ESC_RE.sub(_narrow_sub, raw) + return raw.encode('latin-1') + return decode_rc_string(raw, cp, wide).encode('utf-16-le') + + +def decode_rc_string(raw, cp, wide): + if not wide and cp != 1200: + b = string_bytes(raw, False, cp) + return b.decode(codec_for(cp) or 'cp1252', 'replace') + out = [] + pos = 0 + pending = [] + + def flush(): + if pending: + s = ''.join(pending) + if cp == 1200: + out.append(s) + else: + out.append(s.encode('latin-1').decode(codec_for(cp) or 'cp1252', 'replace')) + del pending[:] + + for m in STRING_ESC_WIDE_RE.finditer(raw): + pending.append(raw[pos:m.start()]) + pos = m.end() + v, numeric = _esc_value(m.group()) + if v is None: + pending.append(m.group()) + elif numeric: + flush() + out.append(chr(v)) + else: + pending.append(chr(v)) + pending.append(raw[pos:]) + flush() + return ''.join(out) + + +def read_source(path): + data = open(path, 'rb').read() + if data.startswith(b'\xff\xfe'): + return data[2:].decode('utf-16-le', 'replace'), 1200 + if data.startswith(b'\xfe\xff'): + return data[2:].decode('utf-16-be', 'replace'), 1200 + if data.startswith(b'\xef\xbb\xbf'): + return data[3:].decode('latin-1'), 65001 + return data.decode('latin-1'), None + + +class DirCache: + def __init__(self): + self.cache = {} + + def names(self, d): + r = self.cache.get(d) + if r is None: + try: + r = os.listdir(d) + except OSError: + r = [] + self.cache[d] = r + return r + + def resolve(self, base, rel): + cur = base + out = [] + for part in rel.split('/'): + if part in ('', '.'): + continue + if part == '..': + cur = os.path.dirname(cur) + out.append('..') + continue + names = self.names(cur) + if part in names: + actual = part + else: + low = part.lower() + matches = sorted(n for n in names if n.lower() == low) + if not matches: + return None + actual = matches[0] + out.append(actual) + cur = os.path.join(cur, actual) + return out + + +class Preprocessor: + def __init__(self, include_dirs, diag, default_cp, dirs): + self.include_dirs = include_dirs + self.diag = diag + self.default_cp = default_cp + self.cp = default_cp + self.dirs = dirs + self.macros = {} + self.tokens = [] + self.files = [] + self.deps = [] + self.once = set() + self.stack = [] + self.skipped_includes = [] + self.ev = Evaluator(self.macros) + + def define_cmdline(self, spec): + name, _, value = spec.partition('=') + toks = [] + lex(value if _ else '1', toks, 0, 0, 0) + self.macros[name.strip()] = (None, toks) + + def find_include(self, name, cur_dir, angle): + rel = name.replace('\\', '/') + if os.path.isabs(rel): + return rel if os.path.isfile(rel) else None + dirs = [] + if not angle: + dirs.append(cur_dir) + dirs.extend(reversed(self.stack)) + dirs.extend(self.include_dirs) + for d in dirs: + p = os.path.join(d, rel) + if os.path.isfile(p): + return p + parts = self.dirs.resolve(d, rel) + if parts: + p = os.path.join(d, *parts) + if os.path.isfile(p): + return p + alias = HEADER_ALIASES.get(os.path.basename(rel).lower()) + if alias and alias != rel: + return self.find_include(alias, cur_dir, True) + return None + + def process_file(self, path, rc_mode): + real = os.path.realpath(path) + if real in self.once: + return + if len(self.stack) > 40: + self.diag.error(path, 'includes nested too deeply') + return + text, forced_cp = read_source(path) + fi = len(self.files) + self.files.append(path) + self.deps.append(os.path.abspath(path)) + saved_cp = self.cp + if forced_cp is not None: + self.cp = forced_cp + cur_dir = os.path.dirname(os.path.abspath(path)) + self.stack.append(cur_dir) + diag = self.diag + toks = self.tokens + sink = [] + + def unterminated(ln, fi_): + diag.warn('%s:%d' % (self.files[fi_], ln), 'unterminated string literal') + + lines = text.split('\n') + n = len(lines) + cond = [] + active = True + in_block = False + i = 0 + while i < n: + line = lines[i] + ln = i + 1 + i += 1 + if line.endswith('\r'): + line = line[:-1] + if in_block: + e = line.find('*/') + if e < 0: + continue + line = ' ' * (e + 2) + line[e + 2:] + in_block = False + stripped = line.lstrip() + if stripped.startswith('#'): + while line.endswith('\\') and i < n: + line = line[:-1] + lines[i].rstrip('\r') + i += 1 + loc = '%s:%d' % (path, ln) + m = re.match(r'\s*#\s*([A-Za-z_]\w*)?(.*)$', line) + name = m.group(1) or '' + rest = m.group(2) + if name in ('if', 'ifdef', 'ifndef'): + if not active: + cond.append([False, True, False]) + else: + if name == 'if': + val = self.eval_if(rest, ln, fi, loc) + else: + mm = re.match(r'\s*([A-Za-z_]\w*)', rest) + if not mm: + diag.warn(loc, '#%s without identifier' % name) + val = False + else: + val = (mm.group(1) in self.macros) != (name == 'ifndef') + cond.append([val, val, True]) + active = cond[-1][0] + elif name == 'elif': + if not cond: + diag.warn(loc, '#elif without #if') + continue + top = cond[-1] + if top[2] and not top[1]: + top[0] = self.eval_if(rest, ln, fi, loc) + top[1] = top[0] + else: + top[0] = False + active = top[0] + elif name == 'else': + if not cond: + diag.warn(loc, '#else without #if') + continue + top = cond[-1] + top[0] = top[2] and not top[1] + top[1] = True + active = top[0] + elif name == 'endif': + if not cond: + diag.warn(loc, '#endif without #if') + continue + cond.pop() + active = cond[-1][0] if cond else True + elif not active: + pass + elif name == 'define': + mm = re.match(r'\s*([A-Za-z_]\w*)(\([^)]*\))?(.*)$', rest) + if not mm: + diag.warn(loc, 'malformed #define') + continue + params = None + if mm.group(2) is not None: + params = [p.strip() for p in mm.group(2)[1:-1].split(',') if p.strip()] + body = [] + in_block = lex(mm.group(3), body, 0, ln, fi) + old = self.macros.get(mm.group(1)) + if old is not None and (old[0] != params or [t.s for t in old[1]] != [t.s for t in body]): + diag.warn(loc, "macro '%s' redefined" % mm.group(1)) + self.macros[mm.group(1)] = (params, body) + continue + elif name == 'undef': + mm = re.match(r'\s*([A-Za-z_]\w*)', rest) + if mm: + self.macros.pop(mm.group(1), None) + elif name == 'include': + mm = re.match(r'\s*(?:"([^"]*)"|<([^>]*)>)', rest) + if not mm: + diag.warn(loc, 'malformed #include') + continue + inc = mm.group(1) if mm.group(1) is not None else mm.group(2) + found = self.find_include(inc, cur_dir, mm.group(1) is None) + if found is None: + self.skipped_includes.append((loc, inc)) + else: + ext = os.path.splitext(found)[1].lower() + self.process_file(found, rc_mode and ext in RC_EXTENSIONS) + rest = rest[mm.end():] + elif name == 'pragma': + mm = re.match(r'\s*code_page\s*\(\s*(\w+)\s*\)', rest) + if mm: + v = mm.group(1) + if v.isdigit() and (int(v) == 1200 or codec_for(int(v))): + self.cp = int(v) + elif v.upper() == 'DEFAULT': + self.cp = self.default_cp + else: + diag.warn(loc, 'unsupported code page %s' % v) + elif re.match(r'\s*once\b', rest): + self.once.add(real) + elif name == 'error': + diag.warn(loc, '#error%s' % rest) + elif name in ('warning', 'line', ''): + pass + else: + diag.warn(loc, 'ignoring unknown directive #%s' % name) + if '/*' in rest: + del sink[:] + in_block = lex(rest, sink, 0, ln, fi) + continue + if active and rc_mode: + in_block = lex(line, toks, self.cp, ln, fi, unterminated) + elif '/*' in line: + del sink[:] + in_block = lex(line, sink, 0, ln, fi) + if cond: + diag.warn(path, 'unterminated #if at end of file') + self.stack.pop() + if forced_cp is not None: + self.cp = saved_cp + + def eval_if(self, rest, ln, fi, loc): + toks = [] + lex(rest, toks, 0, ln, fi) + try: + return bool(self.ev.eval_pp(toks)) + except EvalError as e: + self.diag.warn(loc, 'cannot evaluate #if expression (%s); treating as false' % e) + return False + + +def lang_code(primary, sub): + if primary == 0: + return 'neutral' + c = LANG_CODE_BY_ID.get((primary, sub)) + if c: + return c + c = LANG_CODE_BY_PRIMARY.get(primary) + if c: + return c + return 'lang%04x' % ((sub << 10) | primary) + + +def to_s16(v): + v &= 0xFFFF + return v - 0x10000 if v & 0x8000 else v + + +def to_s32(v): + v &= 0xFFFFFFFF + return v - 0x100000000 if v & 0x80000000 else v + + +def ctrl_id(v): + v = to_s32(v) + return -1 if v in (-1, 0xFFFF) else v + + +class Rec: + def __init__(self, **kw): + self.__dict__.update(kw) + + +class LangData: + def __init__(self, code, langid): + self.code = code + self.langid = langid + self.cp = None + self.dialogs = [] + self.menus = [] + self.strings = {} + self.accels = [] + self.toolbars = [] + self.files = [] + self.dlginits = [] + self.version = None + self.keys = set() + + +def is_begin(t): + return (t.k == 'id' and t.v.upper() == 'BEGIN') or (t.k == 'op' and t.v == '{') + + +def is_end(t): + return (t.k == 'id' and t.v.upper() == 'END') or (t.k == 'op' and t.v == '}') + + +def kw(t): + return t.v.upper() if t.k == 'id' else None + + +class RcParser: + def __init__(self, pp, rc_path, diag, dirs): + self.replacements = [] + self.pp = pp + self.ev = pp.ev + self.diag = diag + self.dirs = dirs + last = pp.tokens[-1] if pp.tokens else EOF_TOK + self.cur = Cursor(pp.tokens, Tok('eof', None, '', None, 0, last.ln, last.fi)) + self.rc_dir = os.path.dirname(os.path.abspath(rc_path)) + self.langs = {} + self.lang = None + self.string_named = {} + self.missing_files = {} + self.skipped = [] + self.decode_errors = 0 + + def loc(self, t): + return '%s:%d' % (self.pp.files[t.fi] if self.pp.files else '?', t.ln) + + def parse(self): + c = self.cur + while c.peek().k != 'eof': + start = c.i + try: + self.statement() + except ParseError as e: + self.diag.error(self.loc(e.tok), e.msg) + self.recover(start) + + def recover(self, start): + c = self.cur + if c.i <= start: + c.i = start + 1 + while c.peek().k != 'eof': + t = c.peek() + prev = c.t[c.i - 1] + if prev.ln != t.ln or prev.fi != t.fi: + u = kw(t) + if u in ('STRINGTABLE', 'LANGUAGE'): + return + t2 = c.peek(1) + if t2.k == 'id' and t2.ln == t.ln and t2.v.upper() in TOP_TYPES and t.k in ('id', 'num', 'str'): + return + c.next() + + def expr(self, min_prec=1): + t = self.cur.peek() + try: + return self.ev.expr(self.cur, min_prec) + except EvalError as e: + raise ParseError(t, str(e)) + + def expr_sym(self): + start = self.cur.i + t = self.cur.peek() + v = self.expr() + return v, (t.v if self.cur.i == start + 1 and t.k == 'id' else None) + + def unary(self): + t = self.cur.peek() + try: + return self.ev.unary(self.cur) + except EvalError as e: + raise ParseError(t, str(e)) + + def style_expr(self, value): + c = self.cur + while True: + t = c.peek() + if t.k == 'id' and t.v.upper() == 'NOT' and t.v not in self.ev.macros: + c.next() + value &= ~self.unary() + else: + value |= self.expr(PREC['^']) + nt = c.peek() + if nt.k == 'op' and nt.v == '|': + c.next() + continue + return value & 0xFFFFFFFF + + def accept_op(self, v): + t = self.cur.peek() + if t.k == 'op' and t.v == v: + self.cur.next() + return True + return False + + def expect_begin(self): + t = self.cur.next() + if not is_begin(t): + raise ParseError(t, 'expected BEGIN but found %s' % describe(t)) + + def text(self, t): + s = decode_rc_string(t.v, t.cp, t.x) + for old, new in self.replacements: + s = s.replace(old, new) + if 'ďż˝' in s: + self.decode_errors += 1 + self.diag.warn(self.loc(t), 'string contains bytes undefined in code page %d' % t.cp) + return s + + def macro_string(self, t): + m = self.ev.macros.get(t.v) if t.k == 'id' else None + if m is not None and m[0] is None and len(m[1]) == 1 and m[1][0].k == 'str': + return self.text(m[1][0]) + return None + + def string(self): + t = self.cur.next() + if t.k == 'str': + return self.text(t) + s = self.macro_string(t) + if s is None: + raise ParseError(t, 'expected string but found %s' % describe(t)) + return s + + def coords(self, n): + out = [] + for i in range(n): + if i: + self.accept_op(',') + out.append(to_s16(self.expr())) + return out + + def skip_block(self): + self.expect_begin() + depth = 1 + while depth: + t = self.cur.next() + if t.k == 'eof': + raise ParseError(t, 'unterminated BEGIN block') + if is_begin(t): + depth += 1 + elif is_end(t): + depth -= 1 + + def get_lang(self, primary, sub): + primary &= 0x3FF + sub &= 0x3F + code = lang_code(primary, sub) + L = self.langs.get(code) + if L is None: + L = LangData(code, (sub << 10) | primary if code != 'neutral' else 0) + self.langs[code] = L + return L + + def language_args(self): + p = self.expr() + self.accept_op(',') + s = self.expr() + return self.get_lang(p, s) + + def target(self, override, tok): + L = override or self.lang + if L is None: + L = self.get_lang(0, 0) + if L.cp is None: + L.cp = tok.cp + return L + + def add_unique(self, L, kind, rid, rname, tok): + key = (kind, rid, rname.upper() if rname else None) + if key in L.keys: + self.diag.warn(self.loc(tok), 'duplicate %s resource %s in language %s ignored' + % (kind, rname or rid, L.code)) + return False + L.keys.add(key) + return True + + def resource_options(self): + override = None + c = self.cur + while True: + u = kw(c.peek()) + if u in MEMORY_OPTIONS: + c.next() + elif u == 'LANGUAGE': + c.next() + override = self.language_args() + elif u in ('CHARACTERISTICS', 'VERSION'): + c.next() + self.expr() + else: + return override + + def name_ref(self): + c = self.cur + t = c.peek() + if t.k == 'str' or self.macro_string(t) is not None: + return 0, self.string(), None + if t.k == 'id': + if self.ev.is_symbol(t.v): + return self.expr() & 0xFFFF, None, t.v + c.next() + self.string_named[t.v] = self.string_named.get(t.v, 0) + 1 + return 0, t.v, t.v + if t.k == 'num' or (t.k == 'op' and t.v in ('(', '-', '~', '+')): + return self.expr() & 0xFFFF, None, None + raise ParseError(t, 'expected resource name but found %s' % describe(t)) + + def statement(self): + c = self.cur + t = c.peek() + u = kw(t) + if u == 'LANGUAGE': + c.next() + self.lang = self.language_args() + return + if u == 'STRINGTABLE': + c.next() + self.parse_stringtable(t) + return + if u in ('VERSION', 'CHARACTERISTICS'): + c.next() + self.expr() + return + rid, rname, sym = self.name_ref() + tt = c.next() + if tt.k == 'id': + ut = tt.v.upper() + if ut in ('DIALOG', 'DIALOGEX'): + return self.parse_dialog(rid, rname, sym, t, ut == 'DIALOGEX') + if ut in ('MENU', 'MENUEX'): + return self.parse_menu(rid, rname, sym, t, ut == 'MENUEX') + if ut == 'ACCELERATORS': + return self.parse_accelerators(rid, rname, sym, t) + if ut == 'TOOLBAR': + return self.parse_toolbar(rid, rname, sym, t) + if ut == 'DLGINIT': + return self.parse_dlginit(rid, rname, sym, t) + if ut == 'VERSIONINFO': + return self.parse_versioninfo(t) + if ut in SKIP_TYPES: + self.resource_options() + if is_begin(c.peek()): + self.skip_block() + return + if ut in FILE_TYPES: + typename = ut + elif self.ev.is_symbol(tt.v): + c.i -= 1 + v = self.expr() & 0xFFFF + typename = RT_NAMES.get(v, '#%d' % v) + else: + typename = tt.v + elif tt.k == 'str': + typename = self.text(tt) + elif tt.k == 'num': + typename = RT_NAMES.get(tt.v, '#%d' % tt.v) + else: + raise ParseError(tt, 'expected resource type but found %s' % describe(tt)) + self.parse_file_resource(typename, rid, rname, sym, t) + + def parse_file_resource(self, typename, rid, rname, sym, tok): + c = self.cur + override = self.resource_options() + t = c.peek() + if t.k == 'str': + path = self.string() + elif is_begin(t): + self.skip_block() + self.skipped.append((self.loc(tok), '%s resource %s with inline data' + % (typename, rname or sym or rid))) + return + else: + parts = [] + while c.peek().k != 'eof' and c.peek().ln == t.ln and c.peek().fi == t.fi: + parts.append(c.next().s) + path = ''.join(parts) + self.diag.warn(self.loc(t), 'unquoted file name %r' % path) + L = self.target(override, tok) + if not self.add_unique(L, typename, rid, rname, tok): + return + rel = path.replace('\\', '/') + if os.path.isabs(rel) or re.match(r'^[A-Za-z]:/', rel): + self.diag.warn(self.loc(tok), 'absolute resource path %r' % path) + resolved = rel if os.path.exists(rel) else None + else: + parts = self.dirs.resolve(self.rc_dir, rel) + resolved = '/'.join(parts) if parts else None + if resolved is not None and not os.path.isfile(os.path.join(self.rc_dir, resolved)): + resolved = None + if resolved is None: + resolved = '/'.join(p for p in rel.split('/') if p not in ('', '.')) + if resolved not in self.missing_files: + self.missing_files[resolved] = self.loc(tok) + self.diag.warn(self.loc(tok), 'resource file not found: %s' % path) + L.files.append(Rec(type=typename, id=rid, name=rname, path=resolved, sym=sym, + exists=resolved not in self.missing_files)) + + def parse_stringtable(self, tok): + c = self.cur + override = self.resource_options() + self.expect_begin() + L = self.target(override, tok) + while not is_end(c.peek()): + it = c.peek() + if it.k == 'eof': + raise ParseError(it, 'unterminated STRINGTABLE') + hits = self.ev.undefined_hits + sid, sym = self.expr_sym() + sid &= 0xFFFF + self.accept_op(',') + text = self.string() + if self.ev.undefined_hits != hits: + self.skipped.append((self.loc(it), 'string %s with undefined id' % (sym or ''))) + elif sid in L.strings: + self.diag.warn(self.loc(it), 'duplicate string id %d (%s) in language %s ignored' + % (sid, sym or '', L.code)) + else: + L.strings[sid] = (text, sym) + c.next() + + def parse_dialog(self, rid, rname, sym, tok, ex): + c = self.cur + override = self.resource_options() + x, y, cx, cy = self.coords(4) + if self.accept_op(','): + self.expr() + style = None + exstyle = 0 + caption = None + font = None + menu = (0, None) + while True: + t = c.peek() + if is_begin(t): + break + u = kw(t) + c.next() + if u == 'STYLE': + style = self.style_expr(0) + elif u == 'EXSTYLE': + exstyle = self.style_expr(0) + elif u == 'CAPTION': + caption = self.string() + elif u == 'FONT': + size = self.expr() + self.accept_op(',') + face = self.string() + weight = italic = 0 + if self.accept_op(','): + weight = self.expr() + if self.accept_op(','): + italic = self.expr() + if self.accept_op(','): + self.expr() + font = (to_s16(size), face, to_s16(weight), 1 if italic & 0xFF else 0) + elif u == 'MENU': + mid, mname, _ = self.name_ref() + menu = (mid, mname) + elif u == 'CLASS': + _, cname, _ = self.name_ref() + self.skipped.append((self.loc(t), 'CLASS %s of dialog %s' % (cname, rname or sym or rid))) + elif u == 'LANGUAGE': + override = self.language_args() + elif u in ('CHARACTERISTICS', 'VERSION'): + self.expr() + elif u in MEMORY_OPTIONS: + pass + else: + raise ParseError(t, 'unexpected %s in dialog header' % describe(t)) + if style is None: + style = WS_POPUP | WS_BORDER | WS_SYSMENU + if caption is not None: + style |= WS_CAPTION + if font is not None: + style |= DS_SETFONT + self.expect_begin() + controls = [] + while not is_end(c.peek()): + controls.append(self.parse_control()) + c.next() + L = self.target(override, tok) + if self.add_unique(L, 'DIALOG', rid, rname, tok): + L.dialogs.append(Rec(id=rid, name=rname, sym=sym, x=x, y=y, cx=cx, cy=cy, style=style, + exstyle=exstyle, caption=caption, font=font, menu=menu, + controls=controls)) + + def ctrl_text(self): + c = self.cur + t = c.peek() + if t.k == 'str' or self.macro_string(t) is not None: + return self.string() + if t.k == 'id' and not self.ev.is_symbol(t.v): + c.next() + return t.v + return '#%d' % (self.expr() & 0xFFFF) + + def ctrl_class(self): + c = self.cur + t = c.next() + if t.k == 'str': + name = self.text(t) + elif t.k == 'id': + name = self.macro_string(t) + if name is None: + name = t.v + elif t.k == 'num': + return CLASS_ORDINALS.get(t.v, '#%d' % t.v) + else: + raise ParseError(t, 'expected control class but found %s' % describe(t)) + return CLASS_NAMES.get(name.upper(), name) + + def ctrl_tail(self, style, exstyle): + if self.accept_op(','): + style = self.style_expr(style) + if self.accept_op(','): + exstyle = self.style_expr(exstyle) + if self.accept_op(','): + self.expr() + return style, exstyle + + def parse_control(self): + c = self.cur + t = c.next() + u = kw(t) + exstyle = 0 + if u == 'CONTROL': + text = self.ctrl_text() + self.accept_op(',') + cid, sym = self.expr_sym() + self.accept_op(',') + cls = self.ctrl_class() + self.accept_op(',') + style = self.style_expr(CHILD) + self.accept_op(',') + x, y, cx, cy = self.coords(4) + if self.accept_op(','): + exstyle = self.style_expr(0) + if self.accept_op(','): + self.expr() + elif u in TEXT_CONTROLS: + cls, default = TEXT_CONTROLS[u] + text = self.ctrl_text() + self.accept_op(',') + cid, sym = self.expr_sym() + self.accept_op(',') + x, y, cx, cy = self.coords(4) + style, exstyle = self.ctrl_tail(CHILD | default, 0) + elif u in PLAIN_CONTROLS: + cls, default = PLAIN_CONTROLS[u] + text = None + cid, sym = self.expr_sym() + self.accept_op(',') + x, y, cx, cy = self.coords(4) + style, exstyle = self.ctrl_tail(CHILD | default, 0) + if u == 'COMBOBOX' and not style & CBS_TYPEMASK: + style |= CBS_SIMPLE + elif u == 'ICON': + cls = 'Static' + text = self.ctrl_text() + self.accept_op(',') + cid, sym = self.expr_sym() + self.accept_op(',') + x, y = self.coords(2) + cx = cy = 0 + style = CHILD | SS_ICON + if self.accept_op(','): + cx, cy = self.coords(2) + style, exstyle = self.ctrl_tail(style, 0) + else: + raise ParseError(t, 'unknown control statement %s' % describe(t)) + if is_begin(c.peek()): + self.skip_block() + self.skipped.append((self.loc(t), 'control data block of %s' % (sym or cid))) + return Rec(cls=cls, text=text, id=ctrl_id(cid), x=x, y=y, cx=cx, cy=cy, + style=style & 0xFFFFFFFF, exstyle=exstyle & 0xFFFFFFFF, sym=sym) + + def menu_options(self): + c = self.cur + flags = 0 + while True: + t = c.peek() + if t.k == 'op' and t.v in (',', '|') and kw(c.peek(1)) in MENU_OPTIONS: + c.next() + continue + u = kw(t) + if u in MENU_OPTIONS: + c.next() + flags |= MENU_OPTIONS[u] + continue + return flags + + def ex_fields(self, count): + vals = [0] * count + syms = [None] * count + for i in range(count): + if not self.accept_op(','): + break + t = self.cur.peek() + if (t.k == 'op' and t.v == ',') or is_begin(t) or is_end(t): + continue + vals[i], syms[i] = self.expr_sym() + return vals, syms + + def menu_items(self, items, depth, ex): + c = self.cur + self.expect_begin() + while not is_end(c.peek()): + t = c.next() + u = kw(t) + if u == 'MENUITEM': + if kw(c.peek()) == 'SEPARATOR': + c.next() + items.append((depth, 0, MF_SEPARATOR, None, None)) + continue + text = self.string() + if ex: + (mid, mtype, state), syms = self.ex_fields(3) + items.append((depth, to_s32(mid), (mtype | state) & 0xFFFFFFFF, text, syms[0])) + else: + self.accept_op(',') + mid, sym = self.expr_sym() + items.append((depth, mid & 0xFFFF, self.menu_options(), text, sym)) + elif u == 'POPUP': + text = self.string() + if ex: + (mid, mtype, state, _), syms = self.ex_fields(4) + items.append((depth, to_s32(mid), MF_POPUP | ((mtype | state) & 0xFFFFFFFF), text, syms[0])) + else: + items.append((depth, 0, MF_POPUP | self.menu_options(), text, None)) + self.menu_items(items, depth + 1, ex) + elif t.k == 'eof': + raise ParseError(t, 'unterminated menu') + else: + raise ParseError(t, 'unexpected %s in menu' % describe(t)) + c.next() + + def parse_menu(self, rid, rname, sym, tok, ex): + override = self.resource_options() + items = [] + self.menu_items(items, 0, ex) + L = self.target(override, tok) + if self.add_unique(L, 'MENU', rid, rname, tok): + L.menus.append(Rec(id=rid, name=rname, sym=sym, items=items)) + + def parse_accelerators(self, rid, rname, sym, tok): + c = self.cur + override = self.resource_options() + self.expect_begin() + items = [] + while not is_end(c.peek()): + t = c.peek() + if t.k == 'eof': + raise ParseError(t, 'unterminated ACCELERATORS') + event = None + if t.k == 'str': + c.next() + event = self.text(t) + else: + keyval = self.expr() + self.accept_op(',') + cmd, csym = self.expr_sym() + flags = 0 + while True: + nt = c.peek() + if nt.k == 'op' and nt.v in (',', '|') and kw(c.peek(1)) in ACCEL_OPTIONS: + c.next() + continue + u = kw(nt) + if u in ACCEL_OPTIONS: + c.next() + flags |= ACCEL_OPTIONS[u] + continue + break + if event is not None: + if len(event) == 2 and event[0] == '^': + ch = event[1].upper() + key = ord(ch) - 0x40 + if not 0 < key < 0x20: + self.diag.warn(self.loc(t), 'invalid control character %r' % event) + key &= 0x1F + elif len(event) == 1: + key = ord(event.upper() if flags & FVIRTKEY else event) + else: + self.diag.warn(self.loc(t), 'invalid accelerator key %r' % event) + key = ord(event[0]) if event else 0 + else: + key = keyval & 0xFFFF + items.append((key, cmd & 0xFFFF, flags, csym)) + c.next() + L = self.target(override, tok) + if self.add_unique(L, 'ACCELERATORS', rid, rname, tok): + L.accels.append(Rec(id=rid, name=rname, sym=sym, items=items)) + + def parse_toolbar(self, rid, rname, sym, tok): + c = self.cur + self.resource_options() + w, h = self.coords(2) + override = self.resource_options() + self.expect_begin() + buttons = [] + while not is_end(c.peek()): + t = c.next() + u = kw(t) + if u == 'BUTTON': + bid, bsym = self.expr_sym() + buttons.append((bid & 0xFFFF, bsym)) + elif u == 'SEPARATOR': + buttons.append((0, None)) + else: + raise ParseError(t, 'unexpected %s in TOOLBAR' % describe(t)) + c.next() + L = self.target(override, tok) + if self.add_unique(L, 'TOOLBAR', rid, rname, tok): + L.toolbars.append(Rec(id=rid, name=rname, sym=sym, w=w, h=h, buttons=buttons)) + + def parse_dlginit(self, rid, rname, sym, tok): + c = self.cur + override = self.resource_options() + self.expect_begin() + data = bytearray() + while not is_end(c.peek()): + t = c.peek() + if t.k == 'eof': + raise ParseError(t, 'unterminated DLGINIT') + if t.k == 'str': + c.next() + data += string_bytes(t.v, t.x, t.cp) + else: + self.ev.saw_long = False + v = self.expr() + if self.ev.saw_long: + data += (v & 0xFFFFFFFF).to_bytes(4, 'little') + else: + data += (v & 0xFFFF).to_bytes(2, 'little') + self.accept_op(',') + c.next() + L = self.target(override, tok) + codec = codec_for(tok.cp) or 'cp1252' + off = 0 + n = len(data) + while off + 2 <= n: + ctl = int.from_bytes(data[off:off + 2], 'little') + off += 2 + if ctl == 0: + break + if off + 6 > n: + self.diag.warn(self.loc(tok), 'truncated DLGINIT data') + break + msg = int.from_bytes(data[off:off + 2], 'little') + length = int.from_bytes(data[off + 2:off + 6], 'little') + off += 6 + payload = bytes(data[off:off + length]) + off += length + if msg in DLGINIT_TEXT_MESSAGES: + text = payload.split(b'\0', 1)[0].decode(codec, 'replace') + L.dlginits.append(Rec(dialog=rid, control=ctrl_id(ctl), text=text, sym=sym)) + else: + self.skipped.append((self.loc(tok), 'DLGINIT entry with message 0x%04X for control %d of %s (%d bytes)' + % (msg, ctl, rname or sym or rid, length))) + if rname: + self.diag.warn(self.loc(tok), 'DLGINIT for string-named dialog %s stored with dialogId 0' % rname) + + def version_block(self): + c = self.cur + self.expect_begin() + items = [] + while not is_end(c.peek()): + t = c.next() + u = kw(t) + if u == 'BLOCK': + name = self.string() + while self.accept_op(','): + self.expr() + items.append(('BLOCK', name, self.version_block())) + elif u == 'VALUE': + key = self.string() + vals = [] + while self.accept_op(','): + if c.peek().k == 'str': + text = self.string() + while c.peek().k == 'str': + text += self.string() + vals.append(text) + else: + vals.append(self.expr()) + items.append(('VALUE', key, vals)) + elif t.k == 'eof': + raise ParseError(t, 'unterminated VERSIONINFO block') + else: + raise ParseError(t, 'unexpected %s in VERSIONINFO' % describe(t)) + c.next() + return items + + def parse_versioninfo(self, tok): + c = self.cur + override = self.resource_options() + fixed = {'FILEVERSION': [0, 0, 0, 0], 'PRODUCTVERSION': [0, 0, 0, 0]} + while not is_begin(c.peek()): + t = c.next() + u = kw(t) + if u in fixed: + vals = [self.expr()] + while self.accept_op(','): + vals.append(self.expr()) + fixed[u] = ([v & 0xFFFF for v in vals] + [0, 0, 0, 0])[:4] + elif u in ('FILEFLAGSMASK', 'FILEFLAGS', 'FILEOS', 'FILETYPE', 'FILESUBTYPE'): + self.expr() + elif u == 'LANGUAGE': + override = self.language_args() + else: + raise ParseError(t, 'unexpected %s in VERSIONINFO header' % describe(t)) + items = self.version_block() + pairs = [] + for kind, name, children in items: + if kind == 'BLOCK' and name.lower() == 'stringfileinfo': + for k2, n2, c2 in children: + if k2 == 'BLOCK': + for k3, key, vals in c2: + if k3 == 'VALUE' and all(isinstance(v, str) for v in vals): + pairs.append((key.split('\0', 1)[0], ''.join(vals).split('\0', 1)[0])) + break + break + L = self.target(override, tok) + if L.version is None: + L.version = Rec(file=fixed['FILEVERSION'], product=fixed['PRODUCTVERSION'], pairs=pairs) + + +ESCAPE_TABLE = [] +for _b in range(256): + if _b == 0x22: + ESCAPE_TABLE.append('\\"') + elif _b == 0x5C: + ESCAPE_TABLE.append('\\\\') + elif _b == 0x0A: + ESCAPE_TABLE.append('\\n') + elif _b == 0x09: + ESCAPE_TABLE.append('\\t') + elif _b == 0x0D: + ESCAPE_TABLE.append('\\r') + elif 0x20 <= _b < 0x7F: + ESCAPE_TABLE.append(chr(_b)) + else: + ESCAPE_TABLE.append('\\%03o' % _b) + + +def c_str(s): + if s is None: + return 'nullptr' + pieces = list(map(ESCAPE_TABLE.__getitem__, s.encode('utf-8'))) + chunks = [''.join(pieces[i:i + 400]) for i in range(0, len(pieces), 400)] or [''] + out = [] + for ch in chunks: + while '??' in ch: + ch = ch.replace('??', '?\\?') + out.append('"%s"' % ch) + return ' '.join(out) + + +def c_ident(s): + return re.sub(r'[^A-Za-z0-9_]', '_', s) + + +def sym_comment(sym): + return ' // %s' % sym if sym else '' + + +def u32(v): + return '0x%08Xu' % (v & 0xFFFFFFFF) + + +def emit_language(L, module, rc_name, default_cp): + o = [] + w = o.append + var = 'g_rcLang_%s_%s' % (module, c_ident(L.code)) + w('// Generated by rc2cpp.py from %s, language %s. Do not edit.' % (rc_name, L.code)) + w('#include "mfcwx/rcdata.h"') + w('') + w('namespace {') + w('') + w('using namespace mfcwx::rc;') + w('') + for i, d in enumerate(L.dialogs): + if not d.controls: + continue + w('const Control kDialog%dControls[] = {' % i) + for ct in d.controls: + w(' {%s, %s, %d, %d, %d, %d, %d, %s, %s},%s' % ( + c_str(ct.cls), c_str(ct.text), ct.id, ct.x, ct.y, ct.cx, ct.cy, u32(ct.style), + u32(ct.exstyle), sym_comment(ct.sym))) + w('};') + w('') + if L.dialogs: + w('const Dialog kDialogs[] = {') + for i, d in enumerate(L.dialogs): + size, face, weight, italic = d.font if d.font else (0, None, 0, 0) + w(' {%d, %s, %d, %d, %d, %d, %s, %s, %s, %s, %d, %d, %d, %s, %d, %s, %d},%s' % ( + d.id, c_str(d.name), d.x, d.y, d.cx, d.cy, u32(d.style), u32(d.exstyle), + c_str(d.caption), c_str(face), size, weight, italic, c_str(d.menu[1]), d.menu[0], + 'kDialog%dControls' % i if d.controls else 'nullptr', len(d.controls), + sym_comment(d.sym))) + w('};') + w('') + for i, m in enumerate(L.menus): + w('const MenuItem kMenu%dItems[] = {%s' % (i, sym_comment(m.sym))) + for depth, mid, flags, text, sym in m.items: + w(' {%d, %d, 0x%X, %s},%s' % (depth, mid, flags, c_str(text), sym_comment(sym))) + w('};') + w('') + if L.menus: + w('const Menu kMenus[] = {') + for i, m in enumerate(L.menus): + w(' {%d, %s, kMenu%dItems, %d},%s' % (m.id, c_str(m.name), i, len(m.items), sym_comment(m.sym))) + w('};') + w('') + strings = sorted(L.strings.items()) + if strings: + w('const StringEntry kStrings[] = {') + for sid, (text, sym) in strings: + w(' {%d, %s},%s' % (sid, c_str(text), sym_comment(sym))) + w('};') + w('') + for i, a in enumerate(L.accels): + w('const Accel kAccel%dItems[] = {%s' % (i, sym_comment(a.sym))) + for key, cmd, flags, sym in a.items: + w(' {0x%02X, %d, 0x%02X},%s' % (key, cmd, flags, sym_comment(sym))) + w('};') + w('') + if L.accels: + w('const AccelTable kAccels[] = {') + for i, a in enumerate(L.accels): + w(' {%d, %s, kAccel%dItems, %d},%s' % (a.id, c_str(a.name), i, len(a.items), sym_comment(a.sym))) + w('};') + w('') + for i, tb in enumerate(L.toolbars): + w('const int kToolbar%dButtons[] = {%s' % (i, sym_comment(tb.sym))) + for bid, sym in tb.buttons: + w(' %d,%s' % (bid, sym_comment(sym))) + w('};') + w('') + if L.toolbars: + w('const Toolbar kToolbars[] = {') + for i, tb in enumerate(L.toolbars): + w(' {%d, %s, %d, %d, %s, %d},%s' % (tb.id, c_str(tb.name), tb.w, tb.h, + 'kToolbar%dButtons' % i if tb.buttons else 'nullptr', + len(tb.buttons), sym_comment(tb.sym))) + w('};') + w('') + if L.files: + w('const FileResource kFiles[] = {') + for f in L.files: + w(' {%s, %d, %s, %s},%s' % (c_str(f.type), f.id, c_str(f.name), c_str(f.path), sym_comment(f.sym))) + w('};') + w('') + if L.dlginits: + w('const DlgInitEntry kDlgInits[] = {') + for e in L.dlginits: + w(' {%d, %d, %s},%s' % (e.dialog, e.control, c_str(e.text), sym_comment(e.sym))) + w('};') + w('') + if L.version: + v = L.version + if v.pairs: + w('const char* const kVersionKeys[] = {') + for key, val in v.pairs: + w(' %s, %s,' % (c_str(key), c_str(val))) + w('};') + w('') + w('const VersionInfo kVersion = {{%s}, {%s}, %s, %d};' % ( + ', '.join(str(x) for x in v.file), ', '.join(str(x) for x in v.product), + 'kVersionKeys' if v.pairs else 'nullptr', len(v.pairs))) + w('') + w('} // namespace') + w('') + w('extern const mfcwx::rc::Language %s;' % var) + w('const mfcwx::rc::Language %s = {' % var) + w(' %s, 0x%04X, %d,' % (c_str(L.code), L.langid, L.cp or default_cp)) + w(' %s, %d,' % ('kDialogs' if L.dialogs else 'nullptr', len(L.dialogs))) + w(' %s, %d,' % ('kMenus' if L.menus else 'nullptr', len(L.menus))) + w(' %s, %d,' % ('kStrings' if strings else 'nullptr', len(strings))) + w(' %s, %d,' % ('kAccels' if L.accels else 'nullptr', len(L.accels))) + w(' %s, %d,' % ('kToolbars' if L.toolbars else 'nullptr', len(L.toolbars))) + w(' %s, %d,' % ('kFiles' if L.files else 'nullptr', len(L.files))) + w(' %s, %d,' % ('kDlgInits' if L.dlginits else 'nullptr', len(L.dlginits))) + w(' %s,' % ('&kVersion' if L.version else 'nullptr')) + w('};') + w('') + return '\n'.join(o) + + +def emit_module(langs, module, rc_name): + o = [] + w = o.append + w('// Generated by rc2cpp.py from %s. Do not edit.' % rc_name) + w('#include "mfcwx/rcdata.h"') + w('') + names = ['g_rcLang_%s_%s' % (module, c_ident(L.code)) for L in langs] + for n in names: + w('extern const mfcwx::rc::Language %s;' % n) + if names: + w('') + w('namespace {') + w('const mfcwx::rc::Language* const kLanguages[] = {') + for n in names: + w(' &%s,' % n) + w('};') + w('} // namespace') + w('') + w('extern const mfcwx::rc::Module g_rcModule_%s;' % module) + w('const mfcwx::rc::Module g_rcModule_%s = {%s, %s, %d};' % ( + module, c_str(module), 'kLanguages' if names else 'nullptr', len(names))) + w('') + return '\n'.join(o) + + +def output_names(module, langs): + names = ['%s_res.cpp' % module] + names += ['%s_res_%s.cpp' % (module, L.code) for L in langs] + names.append('%s_files.txt' % module) + return names + + +def write_if_changed(path, content): + try: + with open(path, 'r', encoding='utf-8', newline='') as f: + if f.read() == content: + return False + except OSError: + pass + with open(path, 'w', encoding='utf-8', newline='\n') as f: + f.write(content) + return True + + +def write_file(path, content): + with open(path, 'w', encoding='utf-8', newline='\n') as f: + f.write(content) + + +def print_stats(rc_name, module, langs, out=sys.stdout): + cols = ('dialogs', 'controls', 'menus', 'items', 'strings', 'accels', 'keys', 'toolbars', 'files', + 'dlginit', 'version') + print('%s (module %s): %d language(s)' % (rc_name, module, len(langs)), file=out) + print('%-8s %-6s %-5s ' % ('lang', 'langid', 'cp') + ' '.join('%8s' % c for c in cols), file=out) + total = [0] * len(cols) + for L in langs: + row = [len(L.dialogs), sum(len(d.controls) for d in L.dialogs), len(L.menus), + sum(len(m.items) for m in L.menus), len(L.strings), len(L.accels), + sum(len(a.items) for a in L.accels), len(L.toolbars), len(L.files), len(L.dlginits), + 1 if L.version else 0] + total = [a + b for a, b in zip(total, row)] + print('%-8s 0x%04X %-5s ' % (L.code, L.langid, L.cp) + ' '.join('%8d' % v for v in row), file=out) + print('%-8s %-6s %-5s ' % ('total', '', '') + ' '.join('%8d' % v for v in total), file=out) + + +def depfile_escape(p): + return p.replace('\\', '/').replace(' ', '\\ ').replace('#', '\\#').replace('$', '$$') + + +def main(argv=None): + ap = argparse.ArgumentParser(description='Convert a Windows .rc resource script into mfcwx::rc C++ tables.') + ap.add_argument('rc', help='resource script to convert') + ap.add_argument('-m', '--module', help='module name used in file and symbol names (default: .rc base name)') + ap.add_argument('-o', '--out-dir', help='directory for the generated files') + ap.add_argument('-I', dest='include_dirs', action='append', default=[], metavar='DIR', + help='additional include directory') + ap.add_argument('-D', dest='defines', action='append', default=[], metavar='NAME[=VALUE]') + ap.add_argument('-U', dest='undefines', action='append', default=[], metavar='NAME') + ap.add_argument('--header', action='append', default=[], help='header read for #defines before the .rc') + ap.add_argument('--no-default-headers', action='store_true', help='do not pre-include mfcwx/winconst.h') + ap.add_argument('--replace', action='append', default=[], metavar='TEXT=VALUE', + help='replace TEXT in every string literal (like the Windows pre-build step)') + ap.add_argument('--codepage', type=int, default=1252, help='code page before the first #pragma code_page') + ap.add_argument('--stats', action='store_true', help='print per-language resource counts') + ap.add_argument('--list-outputs', action='store_true', help='print the files that would be generated and exit') + ap.add_argument('--outputs-file', help='file holding the output list; fail if the list changed') + ap.add_argument('--depfile', help='write a Makefile-style dependency file') + ap.add_argument('-q', '--quiet', action='store_true', help='only print errors and summaries') + ap.add_argument('-v', '--verbose', action='store_true', help='list every undefined/string-named symbol') + args = ap.parse_args(argv) + + rc_path = args.rc + if not os.path.isfile(rc_path): + print('rc2cpp: error: cannot open %s' % rc_path, file=sys.stderr) + return 1 + rc_name = os.path.basename(rc_path) + module = c_ident(args.module or os.path.splitext(rc_name)[0]) + if not module or module[0].isdigit(): + module = '_' + module + script_dir = os.path.dirname(os.path.abspath(__file__)) + include_dirs = [os.path.abspath(d) for d in args.include_dirs] + default_inc = os.path.normpath(os.path.join(script_dir, '..', 'mfcwx', 'include')) + if os.path.isdir(default_inc) and default_inc not in include_dirs: + include_dirs.append(default_inc) + + diag = Diag(args.quiet or args.list_outputs) + dirs = DirCache() + if codec_for(args.codepage) is None: + print('rc2cpp: error: unsupported code page %d' % args.codepage, file=sys.stderr) + return 1 + pp = Preprocessor(include_dirs, diag, args.codepage, dirs) + pp.define_cmdline('_WIN32') + pp.define_cmdline('RC_INVOKED') + for d in args.defines: + pp.define_cmdline(d) + for u in args.undefines: + pp.macros.pop(u, None) + if not args.no_default_headers: + hdr = pp.find_include('mfcwx/winconst.h', os.path.dirname(os.path.abspath(rc_path)), True) + if hdr: + pp.process_file(hdr, False) + else: + diag.warn(rc_name, 'mfcwx/winconst.h not found in include path') + for h in args.header: + pp.process_file(h, False) + pp.process_file(rc_path, True) + pp.ev.freeze() + + parser = RcParser(pp, rc_path, diag, dirs) + for r in args.replace: + old, sep, new = r.partition('=') + if not sep or not old: + print('rc2cpp: error: --replace expects TEXT=VALUE, got %r' % r, file=sys.stderr) + return 1 + parser.replacements.append((old, new)) + parser.parse() + langs = list(parser.langs.values()) + outs = output_names(module, langs) + out_dir = args.out_dir + out_paths = [os.path.join(out_dir, n) if out_dir else n for n in outs] + listing = ''.join(p.replace('\\', '/') + '\n' for p in out_paths) + + if args.list_outputs: + if diag.errors: + return 1 + if args.outputs_file: + os.makedirs(os.path.dirname(os.path.abspath(args.outputs_file)), exist_ok=True) + write_if_changed(args.outputs_file, listing) + sys.stdout.write(listing) + return 0 + + if diag.errors: + print('rc2cpp: %d error(s) in %s; nothing generated' % (diag.errors, rc_name), file=sys.stderr) + return 1 + + if out_dir: + os.makedirs(out_dir, exist_ok=True) + write_file(os.path.join(out_dir, outs[0]), emit_module(langs, module, rc_name)) + for L, name in zip(langs, outs[1:-1]): + write_file(os.path.join(out_dir, name), emit_language(L, module, rc_name, args.codepage)) + files = sorted({f.path for L in langs for f in L.files if f.exists}) + write_file(os.path.join(out_dir, outs[-1]), ''.join(f + '\n' for f in files)) + if args.depfile: + deps = sorted(set(pp.deps) | {os.path.abspath(__file__)}) + write_file(args.depfile, '%s: %s\n' % ( + depfile_escape(os.path.abspath(out_paths[0])), + ' \\\n '.join(depfile_escape(d) for d in deps))) + + if args.stats: + print_stats(rc_name, module, langs) + + report(parser, pp, diag, args.verbose, rc_name) + + if args.outputs_file: + try: + with open(args.outputs_file, encoding='utf-8') as f: + previous = f.read() + except OSError: + previous = None + if previous is not None and previous != listing: + write_file(args.outputs_file, listing) + print('rc2cpp: error: the set of languages in %s changed; re-run CMake (the next build does it ' + 'automatically)' % rc_name, file=sys.stderr) + return 1 + if previous is None: + write_file(args.outputs_file, listing) + return 0 + + +def report(parser, pp, diag, verbose, rc_name): + ev = pp.ev + if ev.undefined: + items = sorted(ev.undefined.items()) + if diag.quiet and not verbose: + print('rc2cpp: warning: %s: %d undefined symbol(s) evaluated as 0 (%s%s)' % ( + rc_name, len(items), + ', '.join(n for n, _ in items[:5]), ', ...' if len(items) > 5 else ''), file=sys.stderr) + else: + print('rc2cpp: warning: %d undefined symbol(s) evaluated as 0:' % len(items), file=sys.stderr) + for name, (count, tok) in items: + print(' %-40s %5d use(s), first at %s' % (name, count, parser.loc(tok)), file=sys.stderr) + if parser.missing_files: + print('rc2cpp: warning: %d referenced file(s) not found' % len(parser.missing_files), file=sys.stderr) + if ev.builtins_used: + diag.note('symbols taken from the built-in fallback table (missing from the headers): %s' + % ', '.join(sorted(ev.builtins_used))) + if parser.string_named: + names = sorted(parser.string_named) + shown = names if verbose else names[:12] + diag.note('%d identifier(s) without #define used as string resource names: %s%s' + % (len(names), ', '.join(shown), '' if len(shown) == len(names) else ', ...')) + for loc, inc in pp.skipped_includes: + diag.note('%s: include file "%s" not found, skipped' % (loc, inc)) + if parser.skipped: + if verbose: + for loc, what in parser.skipped: + diag.note('%s: skipped %s' % (loc, what)) + else: + diag.note('%d construct(s) skipped (use -v to list them)' % len(parser.skipped)) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/port/rc/test/CMakeLists.txt b/port/rc/test/CMakeLists.txt new file mode 100644 index 000000000..f03077fdd --- /dev/null +++ b/port/rc/test/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.16) +project(rc2cpp_test LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include("${CMAKE_CURRENT_LIST_DIR}/../rc2cpp.cmake") +get_filename_component(ROOT "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) + +add_executable(rc_test rc_test.cpp cryptool_checks.cpp numbershark_checks.cpp aestool_volren_checks.cpp) +target_include_directories(rc_test PRIVATE "${MFCWX_RC_INCLUDE_DIR}") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_options(rc_test PRIVATE -Wall -Wextra -pedantic) +endif() + +mfcwx_add_rc(rc_test RC "${ROOT}/CrypTool/CrypTool.rc" MODULE CrypTool HEADERS "${ROOT}/CrypTool/resource.h") +mfcwx_add_rc(rc_test RC "${ROOT}/aestool/aestool.rc" MODULE aestool HEADERS "${ROOT}/aestool/resource.h") +mfcwx_add_rc(rc_test RC "${ROOT}/NumberShark/MFC-ZahlenHai.rc" MODULE NumberShark HEADERS "${ROOT}/NumberShark/resource.h") +mfcwx_add_rc(rc_test RC "${ROOT}/libVolRen/VolRen.rc" MODULE VolRen HEADERS "${ROOT}/libVolRen/resource.h") + +install(TARGETS rc_test RUNTIME DESTINATION bin) +mfcwx_install_rc_files(rc_test DESTINATION share/rc_test) + +enable_testing() +add_test(NAME rc_test COMMAND rc_test) diff --git a/port/rc/test/aestool_volren_checks.cpp b/port/rc/test/aestool_volren_checks.cpp new file mode 100644 index 000000000..68eb2a189 --- /dev/null +++ b/port/rc/test/aestool_volren_checks.cpp @@ -0,0 +1,36 @@ +#include "rc_test.h" + +#include "afxres.h" +#include "../../../aestool/Resource.h" +#include "../../../libVolRen/resource.h" + +namespace rctest { + +void runAesToolVolRenChecks() { + const Module& aes = g_rcModule_aestool; + RC_CHECK(aes.languageCount == 7); + const Language* el = language(aes, "el"); + RC_CHECK(el && startsWith(string(*el, IDS_STRING_DECOK), "Το αποκρυπτογραφημένο αρχείο %s")); + const Language* de = language(aes, "de"); + RC_CHECK(de && dialog(*de, IDD_AESTOOL_DIALOG) != nullptr); + RC_CHECK(de && file(*de, "ICON", IDR_MAINFRAME, nullptr) != nullptr); + const Language* pl = language(aes, "pl"); + RC_CHECK(pl && file(*pl, "CURSOR", 0, "AFX_IDC_CONTEXTHELP") != nullptr); + + const Module& volren = g_rcModule_VolRen; + RC_CHECK(volren.languageCount == 1); + const Language* en = language(volren, "en"); + RC_CHECK(en && en->langId == 0x0409 && en->dlgInitCount == 0); + if (!en) + return; + const Dialog* editor = dialog(*en, IDD_EDITOR); + RC_CHECK(editor && equals(editor->caption, "Transfer Function Dialog") && editor->controlCount == 1); + RC_CHECK(editor && editor->style == (DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SETFONT)); + const Control* ctrl = editor ? control(*editor, IDC_GTTRAPEZEDITORCTRL1) : nullptr; + RC_CHECK(ctrl && equals(ctrl->cls, "{90393A34-2F31-48A4-9323-8CEC42C73954}")); + RC_CHECK(ctrl && ctrl->style == (WS_CHILD | WS_VISIBLE | WS_TABSTOP) && ctrl->cx == 405 && ctrl->cy == 97); + RC_CHECK(en->version && en->version->keyCount == 9); + RC_CHECK(en->version && equals(en->version->keys[2], "FileDescription") && equals(en->version->keys[3], "VolRen DLL")); +} + +} // namespace rctest diff --git a/port/rc/test/cryptool_checks.cpp b/port/rc/test/cryptool_checks.cpp new file mode 100644 index 000000000..5b6541018 --- /dev/null +++ b/port/rc/test/cryptool_checks.cpp @@ -0,0 +1,169 @@ +#include "rc_test.h" + +#include "afxres.h" +#include "../../../CrypTool/resource.h" + +namespace rctest { + +static void checkLanguages(const Module& m) { + static const char* const codes[] = {"pl", "rs", "de", "fr", "de-CH", "en", "es", "el"}; + RC_CHECK(m.languageCount == 8); + for (int i = 0; i < m.languageCount && i < 8; ++i) + RC_CHECK(equals(m.languages[i]->code, codes[i])); + int dialogs = 0, menus = 0, toolbars = 0, accels = 0; + for (int i = 0; i < m.languageCount; ++i) { + const Language& l = *m.languages[i]; + dialogs += l.dialogCount; + menus += l.menuCount; + toolbars += l.toolbarCount; + accels += l.accelCount; + if (!equals(l.code, "de-CH")) { + RC_CHECK(l.dialogCount >= 150); + RC_CHECK(l.stringCount >= 1600); + RC_CHECK(l.version != nullptr); + } + } + RC_CHECK(dialogs >= 1100); + RC_CHECK(menus == 56); + RC_CHECK(toolbars == 7); + RC_CHECK(accels == 7); +} + +static void checkPolish(const Language& pl) { + RC_CHECK(pl.langId == 0x0415); + RC_CHECK(pl.codepage == 1250); + + const Dialog* props = dialog(pl, IDD_FILE_PROPERTIES); + RC_CHECK(props != nullptr); + if (props) { + RC_CHECK(equals(props->caption, "Właściwości dokumentu")); + RC_CHECK(equals(props->fontName, "MS Sans Serif") && props->fontSize == 8); + RC_CHECK(props->style == (DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU)); + RC_CHECK(props->cx == 362 && props->cy == 159); + + const Control* edit = control(*props, IDC_EDIT1); + RC_CHECK(edit && equals(edit->cls, "Edit") && edit->text == nullptr); + RC_CHECK(edit && edit->style == (WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL | ES_READONLY)); + RC_CHECK(edit && !(edit->style & WS_BORDER)); + RC_CHECK(edit && edit->x == 103 && edit->y == 66 && edit->cx == 245 && edit->cy == 12); + + const Control* ok = control(*props, IDOK); + RC_CHECK(ok && equals(ok->cls, "Button") && equals(ok->text, "Zamknij")); + RC_CHECK(ok && ok->style == (WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON)); + + const Control* group = controlByText(*props, "Informacje o aktualnie wybranym dokumencie"); + RC_CHECK(group && group->id == -1 && group->style == (WS_CHILD | WS_VISIBLE | BS_GROUPBOX)); + + const Control* label = controlByText(*props, "Nazwa pliku:"); + RC_CHECK(label && equals(label->cls, "Static") && label->style == (WS_CHILD | WS_VISIBLE | WS_GROUP | SS_RIGHT)); + + const Control* temp = controlByText(*props, "Nazwa pliku tymczasowego:"); + RC_CHECK(temp && temp->style == (WS_CHILD | WS_VISIBLE | WS_GROUP | SS_LEFT) && temp->exStyle == WS_EX_RIGHT); + } + + const Dialog* dh = dialog(pl, IDD_DIFFIEHELLMANVISUALIZATION); + RC_CHECK(dh != nullptr); + if (dh) { + RC_CHECK(equals(dh->caption, "Demonstracja protokołu Diffie'ego - Hellmana: wizualizacja wymiany kluczy.")); + const Control* bmpButton = controlByText(*dh, "IDB_DH_BUTTON1_R_"); + RC_CHECK(bmpButton && bmpButton->style == (WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_OWNERDRAW | BS_BITMAP)); + const Control* bmpStatic = controlByText(*dh, "#550"); + RC_CHECK(bmpStatic && equals(bmpStatic->cls, "Static") && (bmpStatic->style & SS_TYPEMASK) == SS_BITMAP); + } + + const char* texts[8] = {}; + RC_CHECK(dlgInitTexts(pl, IDD_KEYASYM_GENERATION, IDC_COMBO1, texts, 8) == 4); + RC_CHECK(equals(texts[0], "512") && equals(texts[1], "768") && equals(texts[2], "1024") && equals(texts[3], "2048")); + + const Dialog* keyasym = dialog(pl, IDD_KEYASYM_GENERATION); + const Control* combo = keyasym ? control(*keyasym, IDC_COMBO1) : nullptr; + RC_CHECK(combo && equals(combo->cls, "ComboBox")); + RC_CHECK(combo && (combo->style & 3) == CBS_DROPDOWN); +} + +static void checkEnglish(const Language& en) { + RC_CHECK(en.langId == 0x0809); + RC_CHECK(equals(string(en, IDS_CRYPTOOL_RUNTIME_LANGUAGE_STRING), "English")); + + const AccelTable* acc = accelTable(en, IDR_MAINFRAME); + RC_CHECK(acc != nullptr); + if (acc) { + const Accel* copy = accel(*acc, ID_EDIT_COPY, 'C'); + RC_CHECK(copy && copy->flags == (kFVirtKey | kFControl | kFNoInvert)); + const Accel* help = accel(*acc, ID_CONTEXT_HELP, VK_F1); + RC_CHECK(help && help->flags == (kFVirtKey | kFShift | kFNoInvert)); + const Accel* undo = accel(*acc, ID_EDIT_UNDO, VK_BACK); + RC_CHECK(undo && undo->flags == (kFVirtKey | kFAlt | kFNoInvert)); + } + + const Menu* mainMenu = menu(en, IDR_MAINFRAME); + RC_CHECK(mainMenu != nullptr); + if (mainMenu && mainMenu->itemCount > 3) { + RC_CHECK(mainMenu->items[0].depth == 0 && mainMenu->items[0].flags == kMfPopup); + RC_CHECK(equals(mainMenu->items[0].text, "&File")); + RC_CHECK(mainMenu->items[1].depth == 1 && mainMenu->items[1].id == ID_FILE_NEW); + RC_CHECK(equals(mainMenu->items[1].text, "&New\tCtrl+N")); + RC_CHECK(mainMenu->items[3].id == ID_FILE_CLOSE && mainMenu->items[3].flags == kMfGrayed); + } + + const Toolbar* tb = toolbar(en, IDR_MAINFRAME); + RC_CHECK(tb && tb->buttonWidth == 16 && tb->buttonHeight == 15 && tb->buttonCount == 15); + RC_CHECK(tb && tb->buttons[0] == ID_FILE_NEW && tb->buttons[5] == 0); + + const FileResource* bmp = file(en, "BITMAP", IDR_MAINFRAME, nullptr); + RC_CHECK(bmp && equals(bmp->path, "res/mainfram.bmp")); + const FileResource* named = file(en, "BITMAP", 0, "PASTEU"); + RC_CHECK(named && named->id == 0 && equals(named->path, "res/EditPaste.bmp")); + RC_CHECK(file(en, "ICON", IDR_MAINFRAME, nullptr) != nullptr); + + const Dialog* playfair = dialog(en, IDD_PLAYFAIR_ANALYSIS); + const Control* scroll = playfair ? control(*playfair, IDC_SCROLLBAR1) : nullptr; + RC_CHECK(scroll && equals(scroll->cls, "ScrollBar") && scroll->style == (WS_CHILD | WS_VISIBLE | SBS_HORZ)); + + RC_CHECK(en.version && en.version->fileVersion[0] == 1 && en.version->fileVersion[1] == 4 && + en.version->fileVersion[2] == 31 && en.version->fileVersion[3] == 0); + RC_CHECK(en.version && en.version->keyCount >= 1 && equals(en.version->keys[0], "CompanyName") && + equals(en.version->keys[1], "CrypTool Team")); +} + +static void checkGreek(const Language& el) { + RC_CHECK(el.langId == 0x0408); + RC_CHECK(el.codepage == 1253); + RC_CHECK(contains(string(el, IDS_RSA_LOG_FOUND_NO_SOLUTION), "ÎŻ")); +} + +static void checkSwiss(const Language& ch) { + RC_CHECK(ch.langId == 0x0807 && ch.dialogCount == 1); + const Dialog* d = dialog(ch, AFX_IDD_NEWTYPEDLG); + RC_CHECK(d != nullptr); + if (d) { + const Control* list = control(*d, AFX_IDC_LISTBOX); + RC_CHECK(list && equals(list->cls, "ListBox") && + list->style == (WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY | WS_VSCROLL | WS_TABSTOP)); + const Control* label = control(*d, IDC_STATIC); + RC_CHECK(label && label->style == (WS_CHILD | WS_VISIBLE | SS_LEFT)); + } +} + +void runCrypToolChecks() { + const Module& m = g_rcModule_CrypTool; + checkLanguages(m); + if (const Language* pl = language(m, "pl")) + checkPolish(*pl); + else + RC_CHECK(!"Polish language missing"); + if (const Language* en = language(m, "en")) + checkEnglish(*en); + else + RC_CHECK(!"English language missing"); + if (const Language* el = language(m, "el")) + checkGreek(*el); + else + RC_CHECK(!"Greek language missing"); + if (const Language* ch = language(m, "de-CH")) + checkSwiss(*ch); + else + RC_CHECK(!"Swiss German language missing"); +} + +} // namespace rctest diff --git a/port/rc/test/numbershark_checks.cpp b/port/rc/test/numbershark_checks.cpp new file mode 100644 index 000000000..83083872c --- /dev/null +++ b/port/rc/test/numbershark_checks.cpp @@ -0,0 +1,48 @@ +#include "rc_test.h" + +#include "afxres.h" +#include "../../../NumberShark/resource.h" + +namespace rctest { + +void runNumberSharkChecks() { + const Module& m = g_rcModule_NumberShark; + RC_CHECK(m.languageCount == 7); + + const Language* el = language(m, "el"); + RC_CHECK(el && el->codepage == 1253); + if (el) + RC_CHECK(startsWith(string(*el, IDS_RULES), "Περιγραφή:\r\n")); + + const Language* pl = language(m, "pl"); + RC_CHECK(pl != nullptr); + if (!pl) + return; + RC_CHECK(startsWith(string(*pl, IDS_RULES), "Opis gry:\n - Na początku gry Number Shark moĹźesz wybrać rozmiar \"shell square\"")); + + const Dialog* about = dialog(*pl, IDD_ABOUTBOX); + RC_CHECK(about && about->fontWeight == 0 && equals(about->fontName, "MS Shell Dlg")); + const Control* icon = about ? controlByText(*about, "#128") : nullptr; + RC_CHECK(icon && equals(icon->cls, "Static") && icon->id == -1); + RC_CHECK(icon && icon->style == (WS_CHILD | WS_VISIBLE | SS_ICON) && icon->cx == 20 && icon->cy == 20); + + const Dialog* options = dialog(*pl, IDD_DIALOG1); + const Control* hidden = options ? control(*options, IDC_BUTTON_MAX) : nullptr; + RC_CHECK(hidden && hidden->style == (WS_CHILD | WS_TABSTOP | BS_PUSHBUTTON | BS_MULTILINE)); + + const Dialog* main = dialog(*pl, IDD_MFCZAHLENHAI_DIALOG); + RC_CHECK(main && main->exStyle == WS_EX_APPWINDOW && (main->style & WS_VISIBLE)); + const Control* shark = main ? control(*main, IDC_STATIC_HAI_LISTE) : nullptr; + RC_CHECK(shark && equals(shark->text, "#169") && (shark->style & SS_TYPEMASK) == SS_BITMAP); + const Control* group = main ? controlByText(*main, "Kurs gry - [\"prime\" oznacza liczbę pierwszą]") : nullptr; + RC_CHECK(group != nullptr); + + const FileResource* bmp = file(*pl, "BITMAP", IDB_BITMAP_NUMBERSHARK_01, nullptr); + RC_CHECK(bmp && equals(bmp->path, "Bilder/Zahlenhai01.bmp")); + + const AccelTable* acc = accelTable(*pl, IDR_ACCELERATOR1); + const Accel* rest = acc ? accel(*acc, ID_GIVE_REST, 'N') : nullptr; + RC_CHECK(rest && rest->flags == (kFVirtKey | kFShift | kFControl | kFNoInvert)); +} + +} // namespace rctest diff --git a/port/rc/test/rc_test.cpp b/port/rc/test/rc_test.cpp new file mode 100644 index 000000000..2a2ae7fa6 --- /dev/null +++ b/port/rc/test/rc_test.cpp @@ -0,0 +1,186 @@ +#include "rc_test.h" + +#include +#include + +namespace rctest { + +static int g_checks = 0; +static int g_failures = 0; + +void check(bool ok, const char* what, const char* file, int line) { + ++g_checks; + if (!ok) { + ++g_failures; + std::printf("FAIL %s:%d: %s\n", file, line, what); + } +} + +bool equals(const char* a, const char* b) { + return a && b && std::strcmp(a, b) == 0; +} + +bool startsWith(const char* s, const char* prefix) { + return s && prefix && std::strncmp(s, prefix, std::strlen(prefix)) == 0; +} + +bool contains(const char* s, const char* part) { + return s && part && std::strstr(s, part) != nullptr; +} + +const Language* language(const Module& m, const char* code) { + for (int i = 0; i < m.languageCount; ++i) + if (equals(m.languages[i]->code, code)) + return m.languages[i]; + return nullptr; +} + +const Dialog* dialog(const Language& l, int id) { + for (int i = 0; i < l.dialogCount; ++i) + if (l.dialogs[i].id == id && !l.dialogs[i].name) + return &l.dialogs[i]; + return nullptr; +} + +const Control* control(const Dialog& d, int id) { + for (int i = 0; i < d.controlCount; ++i) + if (d.controls[i].id == id) + return &d.controls[i]; + return nullptr; +} + +const Control* controlByText(const Dialog& d, const char* text) { + for (int i = 0; i < d.controlCount; ++i) + if (equals(d.controls[i].text, text)) + return &d.controls[i]; + return nullptr; +} + +const char* string(const Language& l, int id) { + int lo = 0, hi = l.stringCount - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (l.strings[mid].id == id) + return l.strings[mid].text; + if (l.strings[mid].id < id) + lo = mid + 1; + else + hi = mid - 1; + } + return nullptr; +} + +const Menu* menu(const Language& l, int id) { + for (int i = 0; i < l.menuCount; ++i) + if (l.menus[i].id == id && !l.menus[i].name) + return &l.menus[i]; + return nullptr; +} + +const AccelTable* accelTable(const Language& l, int id) { + for (int i = 0; i < l.accelCount; ++i) + if (l.accels[i].id == id && !l.accels[i].name) + return &l.accels[i]; + return nullptr; +} + +const Accel* accel(const AccelTable& t, int command, int key) { + for (int i = 0; i < t.itemCount; ++i) + if (t.items[i].id == command && t.items[i].key == key) + return &t.items[i]; + return nullptr; +} + +const Toolbar* toolbar(const Language& l, int id) { + for (int i = 0; i < l.toolbarCount; ++i) + if (l.toolbars[i].id == id && !l.toolbars[i].name) + return &l.toolbars[i]; + return nullptr; +} + +const FileResource* file(const Language& l, const char* type, int id, const char* name) { + for (int i = 0; i < l.fileCount; ++i) { + const FileResource& f = l.files[i]; + if (!equals(f.type, type)) + continue; + if (name ? equals(f.name, name) : (f.id == id && !f.name)) + return &f; + } + return nullptr; +} + +int dlgInitTexts(const Language& l, int dialogId, int controlId, const char** out, int max) { + int n = 0; + for (int i = 0; i < l.dlgInitCount; ++i) + if (l.dlgInits[i].dialogId == dialogId && l.dlgInits[i].controlId == controlId && n < max) + out[n++] = l.dlgInits[i].text; + return n; +} + +} // namespace rctest + +using namespace rctest; + +static void printStats(const Module& m) { + std::printf("%s: %d language(s)\n", m.name, m.languageCount); + std::printf(" %-7s %-6s %5s %7s %8s %5s %6s %7s %6s %8s %5s %7s %7s\n", "lang", "langid", "cp", "dialogs", + "controls", "menus", "items", "strings", "accels", "toolbars", "files", "dlginit", "version"); + for (int i = 0; i < m.languageCount; ++i) { + const Language& l = *m.languages[i]; + int controls = 0, items = 0; + for (int d = 0; d < l.dialogCount; ++d) + controls += l.dialogs[d].controlCount; + for (int k = 0; k < l.menuCount; ++k) + items += l.menus[k].itemCount; + std::printf(" %-7s 0x%04X %5d %7d %8d %5d %6d %7d %6d %8d %5d %7d %7s\n", l.code, l.langId, l.codepage, + l.dialogCount, controls, l.menuCount, items, l.stringCount, l.accelCount, l.toolbarCount, + l.fileCount, l.dlgInitCount, l.version ? "yes" : "no"); + } +} + +static void structuralChecks(const Module& m) { + RC_CHECK(m.name != nullptr); + RC_CHECK(m.languageCount > 0); + for (int i = 0; i < m.languageCount; ++i) { + const Language& l = *m.languages[i]; + RC_CHECK(l.code != nullptr); + for (int k = 1; k < l.stringCount; ++k) + RC_CHECK(l.strings[k - 1].id < l.strings[k].id); + for (int k = 0; k < l.stringCount; ++k) + RC_CHECK(l.strings[k].text != nullptr); + for (int d = 0; d < l.dialogCount; ++d) { + const Dialog& dlg = l.dialogs[d]; + RC_CHECK((dlg.controls != nullptr) == (dlg.controlCount > 0)); + RC_CHECK((dlg.id != 0) != (dlg.name != nullptr)); + for (int c = 0; c < dlg.controlCount; ++c) + RC_CHECK(dlg.controls[c].cls != nullptr); + } + for (int k = 0; k < l.menuCount; ++k) { + const Menu& mn = l.menus[k]; + RC_CHECK(mn.itemCount > 0 && mn.items[0].depth == 0); + for (int j = 1; j < mn.itemCount; ++j) + RC_CHECK(mn.items[j].depth <= mn.items[j - 1].depth + 1); + for (int j = 0; j < mn.itemCount; ++j) + RC_CHECK((mn.items[j].text == nullptr) == ((mn.items[j].flags & kMfSeparator) != 0)); + } + for (int k = 0; k < l.fileCount; ++k) { + const FileResource& f = l.files[k]; + RC_CHECK(f.type != nullptr && f.path != nullptr); + RC_CHECK((f.id != 0) != (f.name != nullptr)); + RC_CHECK(std::strchr(f.path, '\\') == nullptr); + } + } +} + +int main() { + const Module* modules[] = {&g_rcModule_CrypTool, &g_rcModule_aestool, &g_rcModule_NumberShark, &g_rcModule_VolRen}; + for (const Module* m : modules) { + printStats(*m); + structuralChecks(*m); + } + runCrypToolChecks(); + runNumberSharkChecks(); + runAesToolVolRenChecks(); + std::printf("%d checks, %d failure(s)\n", g_checks, g_failures); + return g_failures ? 1 : 0; +} diff --git a/port/rc/test/rc_test.h b/port/rc/test/rc_test.h new file mode 100644 index 000000000..6f33dcf39 --- /dev/null +++ b/port/rc/test/rc_test.h @@ -0,0 +1,46 @@ +#pragma once + +#include "mfcwx/rcdata.h" + +extern const mfcwx::rc::Module g_rcModule_CrypTool; +extern const mfcwx::rc::Module g_rcModule_aestool; +extern const mfcwx::rc::Module g_rcModule_NumberShark; +extern const mfcwx::rc::Module g_rcModule_VolRen; + +namespace rctest { + +using namespace mfcwx::rc; + +constexpr uint32_t kFVirtKey = 0x01; +constexpr uint32_t kFNoInvert = 0x02; +constexpr uint32_t kFShift = 0x04; +constexpr uint32_t kFControl = 0x08; +constexpr uint32_t kFAlt = 0x10; +constexpr uint32_t kMfGrayed = 0x01; +constexpr uint32_t kMfPopup = 0x10; +constexpr uint32_t kMfSeparator = 0x800; + +void check(bool ok, const char* what, const char* file, int line); +bool equals(const char* a, const char* b); +bool startsWith(const char* s, const char* prefix); +bool contains(const char* s, const char* part); + +const Language* language(const Module& m, const char* code); +const Dialog* dialog(const Language& l, int id); +const Control* control(const Dialog& d, int id); +const Control* controlByText(const Dialog& d, const char* text); +const char* string(const Language& l, int id); +const Menu* menu(const Language& l, int id); +const AccelTable* accelTable(const Language& l, int id); +const Accel* accel(const AccelTable& t, int command, int key); +const Toolbar* toolbar(const Language& l, int id); +const FileResource* file(const Language& l, const char* type, int id, const char* name); +int dlgInitTexts(const Language& l, int dialogId, int controlId, const char** out, int max); + +void runCrypToolChecks(); +void runNumberSharkChecks(); +void runAesToolVolRenChecks(); + +} // namespace rctest + +#define RC_CHECK(cond) ::rctest::check((cond), #cond, __FILE__, __LINE__) diff --git a/port/secude/CMakeLists.txt b/port/secude/CMakeLists.txt new file mode 100644 index 000000000..d2441f777 --- /dev/null +++ b/port/secude/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.16) + +project(secude_compat LANGUAGES C CXX) + +get_filename_component(SECUDE_COMPAT_REPO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) + +if(NOT TARGET OpenSSL::Crypto) + find_package(OpenSSL 3 REQUIRED) +endif() + +add_library(secude_compat STATIC + src/alloc.cpp + src/error.cpp + src/der.cpp + src/oids.cpp + src/data_flags.cpp + src/structs.cpp + src/encode.cpp + src/dname.cpp + src/lnumber.cpp + src/legacy_hash.cpp + src/legacy_cipher.cpp + src/provider.cpp + src/hash.cpp + src/symcipher.cpp + src/asym.cpp + src/crypt_api.cpp + src/pse.cpp + src/cert.cpp + src/cadb.cpp + src/pkcs12.cpp + src/dump.cpp + src/misc.cpp + src/keystore.cpp + src/symbols.cpp +) + +target_compile_features(secude_compat PRIVATE cxx_std_17 PUBLIC cxx_std_11) +set_target_properties(secude_compat PROPERTIES + CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ON) + +target_include_directories(secude_compat + PUBLIC + "${SECUDE_COMPAT_REPO_ROOT}/secude" + "${CMAKE_CURRENT_SOURCE_DIR}/include" + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src") + +target_link_libraries(secude_compat PUBLIC OpenSSL::Crypto) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_options(secude_compat PRIVATE -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers) +endif() + +add_executable(secude_compat_mkpse tools/mkpse.cpp) +target_link_libraries(secude_compat_mkpse PRIVATE secude_compat) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(_secude_compat_standalone ON) +else() + set(_secude_compat_standalone OFF) +endif() +option(SECUDE_COMPAT_TESTS "Build the secude_compat tests" ${_secude_compat_standalone}) + +if(SECUDE_COMPAT_TESTS) + enable_testing() + # CrypTool's SecudeLib.h exactly as the app sees it (quote includes resolve next to the header first) + add_library(secude_compat_test_cryptool_binding OBJECT tests/test_binding.cpp) + target_include_directories(secude_compat_test_cryptool_binding PRIVATE + "${SECUDE_COMPAT_REPO_ROOT}/CrypTool" + "${CMAKE_CURRENT_SOURCE_DIR}/tests") + target_link_libraries(secude_compat_test_cryptool_binding PRIVATE secude_compat) + # the application is compiled as C++14 + set_target_properties(secude_compat_test_cryptool_binding PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_options(secude_compat_test_cryptool_binding PRIVATE -Wno-deprecated-register -Wno-register) + endif() + + add_library(secude_compat_test_libec_binding OBJECT + "${SECUDE_COMPAT_REPO_ROOT}/libec/sources/ECsecude.c" + tests/test_libec_binding.c) + target_include_directories(secude_compat_test_libec_binding PRIVATE + "${SECUDE_COMPAT_REPO_ROOT}/libec/include") + target_link_libraries(secude_compat_test_libec_binding PRIVATE secude_compat) + set_target_properties(secude_compat_test_libec_binding PROPERTIES C_STANDARD 90 C_EXTENSIONS ON) + + add_executable(secude_compat_tests + tests/main.cpp + tests/test_hash.cpp + tests/test_cipher.cpp + tests/test_lnumber.cpp + tests/test_encode.cpp + tests/test_asym.cpp + tests/test_pse.cpp + tests/test_pkcs12.cpp + $ + $) + target_include_directories(secude_compat_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/tests" "${CMAKE_CURRENT_SOURCE_DIR}/src") + target_compile_features(secude_compat_tests PRIVATE cxx_std_17) + target_link_libraries(secude_compat_tests PRIVATE secude_compat) + + add_test(NAME secude_compat_tests COMMAND secude_compat_tests) + add_test(NAME secude_compat_tests_builtin_legacy COMMAND secude_compat_tests) + set_tests_properties(secude_compat_tests_builtin_legacy PROPERTIES ENVIRONMENT "SECUDE_COMPAT_NO_LEGACY_PROVIDER=1") +endif() diff --git a/port/secude/README.md b/port/secude/README.md new file mode 100644 index 000000000..e4c7d074a --- /dev/null +++ b/port/secude/README.md @@ -0,0 +1,162 @@ +# secude_compat — SECUDE replacement for the CrypTool port + +CrypTool 1 on Windows loads the proprietary `SECUDE.DLL`. This static library +implements the subset of the SECUDE SDK 7.4 API that CrypTool and libec use +(every function and data object of the `DoAll` list in +`CrypTool/SecudeLib.h`, plus `global_add_error` and `rabinstest`, which libec +calls directly) on top of OpenSSL 3. The SECUDE headers in `secude/` are used +unchanged apart from small portability guards. + +## Building + +``` +cmake -S port/secude -B build/secude -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl@3 +cmake --build build/secude && ctest --test-dir build/secude +``` + +Targets: `secude_compat` (static library; public include directories `secude/` +and `port/secude/include`, links `OpenSSL::Crypto`), `secude_compat_mkpse` +(key store generator) and, when `SECUDE_COMPAT_TESTS` is on (default for +standalone builds), `secude_compat_tests`. ctest runs the suite twice: with +the OpenSSL legacy provider and with `SECUDE_COMPAT_NO_LEGACY_PROVIDER=1`. + +## Binding + +* `CrypTool/SecudeLib.cpp`: on non-Windows platforms `OpenSecudeLib()` fills + the `CSecudeLib` function/data pointers through `secude_compat_symbol(name)` + (a `GetProcAddress` replacement) instead of loading `SECUDE.DLL`. +* `libec/sources/ECsecude.c`: on non-Windows platforms `ECSecudeLib` is + statically initialised with the library functions, so libec works even + before `CrypToolApp` copies the pointers. + +## Algorithms + +| AlgId | Implementation | +| --- | --- | +| `md2_aid`, `sha_aid` (SHA-0) | built in (not available in OpenSSL 3) | +| `md4_aid`, `ripemd160_aid` | OpenSSL (legacy/default provider), built-in fallback | +| `md5_aid`, `sha1_aid` | OpenSSL | +| `desECB_aid`, `desCBC_pad_aid`, `desEDE_aid`, `desCBC3_aid`, `idea_aid`, `rc2CBC_aid`, `rc4_aid` | OpenSSL legacy provider, built-in fallback | +| `rsa_aid` (2.5.8.1.1, INTEGER keysize), `rsaEncryption_aid` | OpenSSL BIGNUM | +| `dsa_aid` (1.3.14.3.2.12, Dss-Parms) | OpenSSL BIGNUM | + +The legacy provider is loaded into a private `OSSL_LIB_CTX`; whatever it +does not offer (all of it if it is missing, IDEA on Debian) is served by the +built-in implementations, which the tests cross-check against OpenSSL. + +Notes on behaviour that CrypTool relies on: + +* Hash results are always written to freshly allocated `octets`; input and + output may be the same `OctetString`. +* Symmetric output and RSA en/decryption output are written into the caller's + buffer (`bits`/`octets`) when it is non-NULL (appending at `nbits`/`noctets`), + otherwise allocated. +* SECUDE "std" padding (`desECB`, `desCBC`, `desEDE`, `desCBC3`, `idea`): the + last block is filled with zero octets, its last octet holds the number of + data octets in that block. `desCBC_pad`, `desCBC3_pad`, `desEDE3CBC`, + `ideaCBC`, `rc2CBC` and AES use PKCS#5 padding. IVs default to zero; RC2 + uses the key length as effective key bits unless the parameter says + otherwise; `idea_aid` is ECB. +* Bad padding fails with `EDECRYPTION` (1792), which the brute-force analysis + treats as "wrong key". +* RSA encryption is textbook RSA on blocks of (bits-1)/8 octets (the last + block is zero padded on the right), each encrypted into (bits+7)/8 octets; + decryption yields (bits-1)/8 octets per block. This is what the hybrid + encryption and side-channel demos expect. +* RSA signatures are PKCS#1 v1.5 with the DigestInfo encodings listed in + `CrypTool/PSEDemo.cpp`; DSA signatures are DER `SEQUENCE { r, s }`. +* RSA private keys are stored like SECUDE does: `KeyBits { p, q }`. The public + exponent is taken from the PSE certificate, 65537 otherwise. +* `L_NUMBER` is the 32-bit `sec_uint4` of the headers on every platform: + `a[0]` holds the number of words (two's complement for negative values), + `a[1..n]` the magnitude, least significant word first. + +## File formats + +### PSE (`*.pse`, CA: `capse.cse`) + +DER encoded, encrypted with AES-256-GCM under a PBKDF2-HMAC-SHA256 key +(100000 iterations, 16 octet salt) derived from the PIN: + +``` +CompatPSE ::= SEQUENCE { + format UTF8String "SECUDE-compat PSE", + version INTEGER (1), + kdf SEQUENCE { pbkdf2 OID, salt OCTET STRING, iterations INTEGER, hmacWithSHA256 OID }, + cipher SEQUENCE { aes256-GCM OID, nonce OCTET STRING }, + ciphertext OCTET STRING } -- ciphertext || tag, AAD = DER of the fields above +PSEContents ::= SEQUENCE { flags INTEGER (1 = one key pair only), created Time, + objects SEQUENCE OF PSEObject } +PSEObject ::= SEQUENCE { name UTF8String, type OID, created Time, updated Time, + value OCTET STRING } +``` + +A wrong PIN fails with `EPIN`, a file in another format with `EPSEFILE`. +Object types use the private arc `2.206.5.1` (`SKnew` .1, `SKold` .2, +`SignSK` .3, `DecSKnew` .4, `DecSKold` .5, `AuthSK` .6, `Cert` .10, +`SignCert` .11, `EncCert` .12, `AuthCert` .13, `PKRoot` .20, `FCPath` .21, +`SerialNumber` .30, `Name` .31, `Uid` .40). Values: certificates as X.509 +DER, keys as `KeyInfo` (SubjectPublicKeyInfo layout), `PKRoot` and `FCPath` +as below, anything else (e.g. `EcPrivKey` of type `Uid`) as raw octets. + +``` +PKRoot ::= SEQUENCE { ca Name, newkey SerialKey, oldkey [0] SerialKey OPTIONAL, + extensions [3] Extensions OPTIONAL } +SerialKey ::= SEQUENCE { serial INTEGER, version INTEGER, key SubjectPublicKeyInfo, + validity Validity OPTIONAL, + signature [1] SEQUENCE { AlgorithmIdentifier, BIT STRING } OPTIONAL } +FCPath ::= SEQUENCE OF SET OF Certificate +``` + +### CA database (`/cadb.der`) + +``` +CADatabase ::= SEQUENCE { version INTEGER (1), entries SEQUENCE OF + SEQUENCE { keyType INTEGER, issued Time, certificate Certificate } } +``` + +Users are looked up by subject DN (case-insensitive, whitespace-normalised +comparison), certificates by serial number. Name strings are written least +significant RDN first (`CN=..., DC=cryptool, DC=org`) as in SECUDE. + +## Key store + +`secude_compat_mkpse ` (or `secude_compat_create_sample_keystore()`) +creates the files the installer ships, in the layout CrypTool expects: + +``` +/PSE/PSECA/capse.cse CA PSE "CN=CrypTool CA 2, DC=cryptool, DC=org", + RSA-2048, PIN 3.14159265358979323844 +/PSE/PSECA/cadb.der CA database +/PSE/[SideChannelAttack][Bob][RSA-512][1152179494][PIN=1234].pse +/PSE/[HybridEncryption][Bob][EC-prime239v1][1178702474][PIN=1234] public EC data (text) +/PSE/[HybridEncryption][Bob][EC-prime239v1][1178702474][PIN=1234].pse EcPrivKey +``` + +The keys are newly generated (the SECUDE-encrypted originals cannot be read); +names, DNs and PINs match the originals. The EC text file has the format +written by `CKeyFile::CreateEcKeyFiles` (a, b, p, Gx, Gy, cofactor, order, +Qx, Qy as `0X...` hex lines). `secude_compat_create_ca()` creates only the +CA (for a first-run setup). + +## Not supported + +Smart cards (`SC_DATA` is ignored), revocation lists +(`af_pse_get_CrlSet` fails with `ENOCRL`), subject alternative names in +`af_create_Certificate` and PKCS#8 attributes in `aux_create_PrivateKeyInfo` +(both fail with `ENOTSUPPORTED`), and the SQMODN hash (`HashInput` is ignored). + +## Integration notes + +* Do not include OpenSSL headers and SECUDE headers in the same translation + unit: SECUDE's `RSA`, `DSA`, `SHA1`, ... enumerators and its BIO/SSL + declarations clash with OpenSSL (see `src/internal.hpp` for the renaming + this library uses internally). +* `CrypTool/SecudeLib.h` uses `register` in its prototypes: fine in C++14 + (deprecation warning), an error in C++17 unless `-Wno-register` is used. +* Windows style paths (`C:\...\PSE\PSECA\capse.cse`) are accepted: off + Windows every path the library opens goes through `native_path()`, which + turns `\` into `/` and drops a drive prefix. +* `CrypToolApp.cpp`'s `ECSecudeLib.##c = SecudeLib.##c` loop is not valid + outside MSVC and can be dropped there (`ECsecude.c` already initialises the + table). diff --git a/port/secude/include/secude_compat.h b/port/secude/include/secude_compat.h new file mode 100644 index 000000000..eb3bdcf62 --- /dev/null +++ b/port/secude/include/secude_compat.h @@ -0,0 +1,52 @@ +/* + * Open-source replacement for the subset of the SECUDE SDK used by CrypTool, + * implemented on top of OpenSSL 3. All SECUDE functions and data objects are + * exported under their original names (C linkage); this header only declares + * the additional entry points of the compatibility layer. + */ +#ifndef SECUDE_COMPAT_H +#define SECUDE_COMPAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* GetProcAddress()-like lookup of a SECUDE function or data object by its + undecorated name (e.g. "af_open", "rsa_aid"). Returns NULL if unknown. */ +void *secude_compat_symbol(const char *name); + +/* Number of entries in the symbol table and access by index (for tests). */ +int secude_compat_symbol_count(void); +const char *secude_compat_symbol_name(int index); + +/* Human readable identification of this library. */ +const char *secude_compat_version(void); + +/* 1 if the OpenSSL legacy provider is used for MD4/DES/IDEA/RC2/RC4, + 0 if the built-in implementations are used instead. */ +int secude_compat_legacy_provider_active(void); + +/* Default PIN of the CrypTool CA PSE (PSEUDO_MASTER_CA_PINNR). */ +#define SECUDE_COMPAT_CA_PIN "3.14159265358979323844" +#define SECUDE_COMPAT_CA_NAME "CN=CrypTool CA 2, DC=cryptool, DC=org" + +/* Creates a CA PSE (RSA key, self-signed certificate, PKRoot, SerialNo) at + ca_pse_path and an empty CA database in ca_dir. Returns 0 on success. */ +int secude_compat_create_ca(const char *ca_pse_path, const char *ca_dir, + const char *pin, const char *ca_name, + int key_bits, int validity_days); + +/* Creates the complete key store below key_store_root: + /PSE/PSECA/capse.cse CA PSE (PIN SECUDE_COMPAT_CA_PIN) + /PSE/PSECA/cadb.der CA database + /PSE/[SideChannelAttack][Bob][RSA-512][1152179494][PIN=1234].pse + /PSE/[HybridEncryption][Bob][EC-prime239v1][1178702474][PIN=1234](.pse) + Existing files are left untouched unless overwrite is non-zero. + Returns 0 on success. */ +int secude_compat_create_sample_keystore(const char *key_store_root, int overwrite); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/secude/src/alloc.cpp b/port/secude/src/alloc.cpp new file mode 100644 index 000000000..01b1a0c97 --- /dev/null +++ b/port/secude/src/alloc.cpp @@ -0,0 +1,268 @@ +#include "internal.hpp" + +#include +#include + +namespace compat { + +namespace { + +struct Registry { + std::mutex lock; + std::unordered_set live; +}; + +Registry ®istry() +{ + static Registry *r = new Registry; + return *r; +} + +} // namespace + +void *mem_alloc(size_t n) +{ + void *p = std::calloc(1, n ? n : 1); + if (!p) + throw std::bad_alloc(); + Registry &r = registry(); + std::lock_guard g(r.lock); + r.live.insert(p); + return p; +} + +void *mem_realloc(void *p, size_t n) +{ + if (!p) + return mem_alloc(n); + Registry &r = registry(); + std::lock_guard g(r.lock); + if (!r.live.count(p)) + throw Error(EINVALID, "realloc of foreign memory"); + void *q = std::realloc(p, n ? n : 1); + if (!q) + throw std::bad_alloc(); + r.live.erase(p); + r.live.insert(q); + return q; +} + +void mem_free(void *p) +{ + if (!p) + return; + Registry &r = registry(); + { + std::lock_guard g(r.lock); + if (!r.live.erase(p)) + return; + } + std::free(p); +} + +bool mem_owned(const void *p) +{ + if (!p) + return false; + Registry &r = registry(); + std::lock_guard g(r.lock); + return r.live.count(const_cast(p)) != 0; +} + +char *mem_strdup(const char *s) +{ + if (!s) + return nullptr; + size_t n = std::strlen(s); + char *d = static_cast(mem_alloc(n + 1)); + std::memcpy(d, s, n); + return d; +} + +char *mem_strdup(const std::string &s) +{ + char *d = static_cast(mem_alloc(s.size() + 1)); + std::memcpy(d, s.data(), s.size()); + return d; +} + +void fill_ostr(OctetString *o, const uint8_t *data, size_t len) +{ + char *buf = static_cast(mem_alloc(len + 1)); + if (len) + std::memcpy(buf, data, len); + o->octets = buf; + o->noctets = static_cast(len); +} + +OctetString *new_ostr(const uint8_t *data, size_t len) +{ + OctetString *o = mem_new(); + fill_ostr(o, data, len); + return o; +} + +void fill_bstr(BitString *o, const Bytes &b, size_t nbits) +{ + char *buf = static_cast(mem_alloc(b.size() + 1)); + if (!b.empty()) + std::memcpy(buf, b.data(), b.size()); + o->bits = buf; + o->nbits = static_cast(nbits); +} + +BitString *new_bstr(const Bytes &b, size_t nbits) +{ + BitString *o = mem_new(); + fill_bstr(o, b, nbits); + return o; +} + +Bytes bytes_of(const OctetString *o) +{ + if (!o || !o->octets || !o->noctets) + return {}; + const uint8_t *p = reinterpret_cast(o->octets); + return Bytes(p, p + o->noctets); +} + +Bytes bytes_of(const BitString *b) +{ + if (!b || !b->bits || !b->nbits) + return {}; + const uint8_t *p = reinterpret_cast(b->bits); + return Bytes(p, p + (b->nbits + 7) / 8); +} + +Bytes bytes_of(const char *s) +{ + if (!s) + return {}; + return Bytes(s, s + std::strlen(s)); +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +void *aux_malloc(size_t size) +{ + return guarded("aux_malloc", nullptr, [&] { return mem_alloc(size); }); +} + +void *aux_calloc(size_t nr, size_t size) +{ + return guarded("aux_calloc", nullptr, [&]() -> void * { + if (size && nr > SIZE_MAX / size) + throw std::bad_alloc(); + return mem_alloc(nr * size); + }); +} + +void aux_free(void *ptr) +{ + mem_free(ptr); +} + +char *aux_cpy_String(char *str) +{ + return guarded("aux_cpy_String", nullptr, [&] { return mem_strdup(str); }); +} + +void aux_free_String(char **str) +{ + if (!str) + return; + mem_free(*str); + *str = nullptr; +} + +OctetString *aux_alloc_OctetString(void) +{ + return guarded("aux_alloc_OctetString", nullptr, [] { return mem_new(); }); +} + +OctetString *aux_cpy_OctetString(OctetString *ostr) +{ + return guarded("aux_cpy_OctetString", nullptr, [&]() -> OctetString * { + if (!ostr) + return nullptr; + return new_ostr(bytes_of(ostr)); + }); +} + +void aux_free2_OctetString(OctetString *ostr) +{ + if (!ostr) + return; + mem_free(ostr->octets); + ostr->octets = nullptr; + ostr->noctets = 0; +} + +void aux_free_OctetString(OctetString **ostr) +{ + if (!ostr || !*ostr) + return; + if (!mem_owned(*ostr)) { + *ostr = nullptr; + return; + } + aux_free2_OctetString(*ostr); + mem_free(*ostr); + *ostr = nullptr; +} + +int aux_cpy2_BitString(BitString *dup_bstr, BitString *bstr) +{ + return guarded("aux_cpy2_BitString", -1, [&] { + if (!dup_bstr || !bstr) + fail(EINVALID, "missing parameter"); + fill_bstr(dup_bstr, bytes_of(bstr), bstr->nbits); + return 0; + }); +} + +void aux_free2_BitString(BitString *bstr) +{ + if (!bstr) + return; + mem_free(bstr->bits); + bstr->bits = nullptr; + bstr->nbits = 0; +} + +void aux_free_BitString(BitString **bstr) +{ + if (!bstr || !*bstr) + return; + if (!mem_owned(*bstr)) { + *bstr = nullptr; + return; + } + aux_free2_BitString(*bstr); + mem_free(*bstr); + *bstr = nullptr; +} + +OctetString *aux_BString2OString(BitString *bstr) +{ + return guarded("aux_BString2OString", nullptr, [&]() -> OctetString * { + if (!bstr) + fail(EINVALID, "missing BitString"); + return new_ostr(bytes_of(bstr)); + }); +} + +BitString *aux_OString2BString(OctetString *ostr) +{ + return guarded("aux_OString2BString", nullptr, [&]() -> BitString * { + if (!ostr) + fail(EINVALID, "missing OctetString"); + return new_bstr(bytes_of(ostr), size_t(ostr->noctets) * 8); + }); +} + +} // extern "C" diff --git a/port/secude/src/asym.cpp b/port/secude/src/asym.cpp new file mode 100644 index 000000000..91e34d76b --- /dev/null +++ b/port/secude/src/asym.cpp @@ -0,0 +1,409 @@ +// RSA and DSA with SECUDE key representations: +// RSA public KeyInfo: rsa (2.5.8.1.1, INTEGER keysize), KeyBits {n, e} +// RSA private KeyInfo: rsa, KeyBits {p, q} (or {-, -, n, d}); e from the +// PSE certificate, 65537 otherwise +// DSA public/private: dsa (1.3.14.3.2.12, KeyBits {p, q, g}), INTEGER y / x +#include "bn.hpp" +#include "der.hpp" + +namespace compat { + +namespace { + +const unsigned long kF4 = 65537; + +KeyBits *keybits_of(const KeyInfo *k) +{ + if (!k) + fail(EINVALID, "missing key"); + return dec_keybits(bytes_of(&k->subjectkey)); +} + +struct KeyBitsHolder { + KeyBits *k; + explicit KeyBitsHolder(KeyBits *kb) : k(kb) {} + ~KeyBitsHolder() + { + free_keybits_content(k); + mem_free(k); + } + KeyBitsHolder(const KeyBitsHolder &) = delete; + KeyBitsHolder &operator=(const KeyBitsHolder &) = delete; +}; + +AlgEnc enc_of(const AlgId *a) +{ + const AlgInfo *i = a ? alg_by_oid(a->objid) : nullptr; + return i ? i->enc : NoAlgEnc; +} + +AlgId *rsa_algid(int bits) +{ + AlgId *a = mem_new(); + a->objid = copy_objid(rsa_aid.objid); + unsigned int *p = mem_new(); + *p = unsigned(bits); + a->param = p; + return a; +} + +KeyInfo *keyinfo_from_parts(AlgId *alg, std::initializer_list parts) +{ + KeyBits kb{}; + OctetString *dst[] = {&kb.part1, &kb.part2, &kb.part3, &kb.part4, &kb.part5}; + int i = 0; + for (const Bytes *p : parts) + fill_ostr(dst[i++], *p); + kb.choice = i; + Bytes der_bytes; + try { + der_bytes = enc_keybits(&kb); + } catch (...) { + free_keybits_content(&kb); + throw; + } + free_keybits_content(&kb); + KeyInfo *k = mem_new(); + k->subjectAI = alg; + fill_bstr(&k->subjectkey, der_bytes, der_bytes.size() * 8); + return k; +} + +Bn generate_prime(int bits, const BIGNUM *add = nullptr, const BIGNUM *rem = nullptr) +{ + Bn p = bn_new(); + bn_check(BN_generate_prime_ex2(p.get(), bits, 0, add, rem, nullptr, bn_ctx())); + return p; +} + +Bytes digest_info(Hash h, const Bytes &hash) +{ + static const struct { + Hash h; + const Oid *oid; + } map[] = {{Hash::MD2, &oids::md2}, {Hash::MD4, &oids::md4}, {Hash::MD5, &oids::md5}, + {Hash::SHA0, &oids::sha}, {Hash::SHA1, &oids::sha1}, {Hash::RIPEMD160, &oids::ripemd160}, + {Hash::SHA256, &oids::sha256}, {Hash::SHA384, &oids::sha384}, {Hash::SHA512, &oids::sha512}}; + for (const auto &m : map) + if (m.h == h) + return der::seq({der::seq({der::oid(*m.oid), der::null()}), der::octet_string(hash)}); + fail(EUNKNOWNALGID, "no DigestInfo for hash"); +} + +Bytes pkcs1_type1(const Bytes &t, size_t k) +{ + if (t.size() + 11 > k) + fail(EKEYSIZE, "RSA key too short for this signature algorithm"); + Bytes em(k, 0xff); + em[0] = 0x00; + em[1] = 0x01; + em[k - t.size() - 1] = 0x00; + std::memcpy(em.data() + k - t.size(), t.data(), t.size()); + return em; +} + +struct DsaKey { + Bn p, q, g, key; +}; + +DsaKey dsa_key(const KeyInfo *k) +{ + if (!k || !k->subjectAI || !k->subjectAI->param) + fail(EALGNOTFITKEY, "DSA key without domain parameters"); + auto *params = static_cast(k->subjectAI->param); + Bytes key_der = bytes_of(&k->subjectkey); + der::Node n = der::parse_one(key_der); + DsaKey d{bn_from(bytes_of(¶ms->part1)), bn_from(bytes_of(¶ms->part2)), bn_from(bytes_of(¶ms->part3)), + bn_from(der::get_unsigned(n))}; + if (BN_is_zero(d.q.get()) || BN_is_zero(d.p.get())) + fail(EALGNOTFITKEY, "invalid DSA domain parameters"); + return d; +} + +Bn dsa_message(const DsaKey &k, Hash h, const uint8_t *msg, size_t n) +{ + Bytes hv = digest(h, msg, n); + Bn z = bn_from(hv); + int qbits = BN_num_bits(k.q.get()); + int hbits = int(hv.size() * 8); + if (hbits > qbits) + bn_check(BN_rshift(z.get(), z.get(), hbits - qbits)); + return z; +} + +Bn mod_exp(const BIGNUM *b, const BIGNUM *e, const BIGNUM *m) +{ + Bn r = bn_new(); + bn_check(BN_mod_exp(r.get(), b, e, m, bn_ctx())); + return r; +} + +Bn rsa_private_op(const RsaPrivate &k, const BIGNUM *c) +{ + Bn n = bn_from(k.n); + if (BN_cmp(c, n.get()) >= 0) + fail(EDECRYPTION, "ciphertext block out of range"); + if (k.p.empty() || k.q.empty()) + return mod_exp(c, bn_from(k.d).get(), n.get()); + Bn p = bn_from(k.p), q = bn_from(k.q), d = bn_from(k.d); + Bn one = bn_word(1), pm1 = bn_new(), qm1 = bn_new(), dp = bn_new(), dq = bn_new(), qinv = bn_new(); + bn_check(BN_sub(pm1.get(), p.get(), one.get())); + bn_check(BN_sub(qm1.get(), q.get(), one.get())); + bn_check(BN_mod(dp.get(), d.get(), pm1.get(), bn_ctx())); + bn_check(BN_mod(dq.get(), d.get(), qm1.get(), bn_ctx())); + if (!BN_mod_inverse(qinv.get(), q.get(), p.get(), bn_ctx())) + fail(EALGNOTFITKEY, "invalid RSA primes"); + Bn m1 = bn_new(), m2 = bn_new(), h = bn_new(), r = bn_new(); + bn_check(BN_mod_exp_mont_consttime(m1.get(), c, dp.get(), p.get(), bn_ctx(), nullptr)); + bn_check(BN_mod_exp_mont_consttime(m2.get(), c, dq.get(), q.get(), bn_ctx(), nullptr)); + bn_check(BN_mod_sub(h.get(), m1.get(), m2.get(), p.get(), bn_ctx())); + bn_check(BN_mod_mul(h.get(), h.get(), qinv.get(), p.get(), bn_ctx())); + bn_check(BN_mul(r.get(), h.get(), q.get(), bn_ctx())); + bn_check(BN_add(r.get(), r.get(), m2.get())); + return r; +} + +} // namespace + +bool keyinfo_is_rsa(const KeyInfo *k) { return k && enc_of(k->subjectAI) == SECUDE_ALG_RSA; } + +bool keyinfo_is_dsa(const KeyInfo *k) { return k && enc_of(k->subjectAI) == SECUDE_ALG_DSA; } + +int rsa_bits(const Bytes &n) { return BN_num_bits(bn_from(n).get()); } + +RsaPublic rsa_public_from_keyinfo(const KeyInfo *k) +{ + if (!keyinfo_is_rsa(k)) + fail(EALGNOTFITKEY, "not an RSA key"); + KeyBitsHolder kb(keybits_of(k)); + if (!kb.k->part1.noctets || !kb.k->part2.noctets) + fail(EALGNOTFITKEY, "incomplete RSA public key"); + return {bytes_of(&kb.k->part1), bytes_of(&kb.k->part2)}; +} + +RsaPrivate rsa_private_from_keyinfo(const KeyInfo *k, const Bytes &e_hint) +{ + if (!keyinfo_is_rsa(k)) + fail(EALGNOTFITKEY, "not an RSA key"); + KeyBitsHolder kb(keybits_of(k)); + RsaPrivate r; + Bn e = e_hint.empty() ? bn_word(kF4) : bn_from(e_hint); + r.e = bn_bytes(e.get()); + if (kb.k->part1.noctets && kb.k->part2.noctets) { + r.p = bytes_of(&kb.k->part1); + r.q = bytes_of(&kb.k->part2); + Bn p = bn_from(r.p), q = bn_from(r.q), n = bn_new(), one = bn_word(1); + Bn pm1 = bn_new(), qm1 = bn_new(), phi = bn_new(), d = bn_new(); + bn_check(BN_mul(n.get(), p.get(), q.get(), bn_ctx())); + bn_check(BN_sub(pm1.get(), p.get(), one.get())); + bn_check(BN_sub(qm1.get(), q.get(), one.get())); + bn_check(BN_mul(phi.get(), pm1.get(), qm1.get(), bn_ctx())); + if (!BN_mod_inverse(d.get(), e.get(), phi.get(), bn_ctx())) + fail(EALGNOTFITKEY, "public exponent does not fit the RSA primes"); + r.n = bn_bytes(n.get()); + r.d = bn_bytes(d.get()); + } else if (kb.k->part3.noctets && kb.k->part4.noctets) { + r.n = bytes_of(&kb.k->part3); + r.d = bytes_of(&kb.k->part4); + } else { + fail(EALGNOTFITKEY, "incomplete RSA private key"); + } + return r; +} + +void rsa_generate(int bits, KeyInfo **pub, KeyInfo **priv) +{ + if (bits < MIN_ASYM_KEYSIZE || bits > MAXKEYLENGTH) + fail(EKEYSIZE, str_printf("unsupported RSA key size %d", bits)); + Bn e = bn_word(kF4), one = bn_word(1); + int pbits = (bits + 1) / 2, qbits = bits - pbits; + for (;;) { + Bn p = generate_prime(pbits), q = generate_prime(qbits); + Bn pm1 = bn_new(), qm1 = bn_new(), g1 = bn_new(), g2 = bn_new(), n = bn_new(); + bn_check(BN_sub(pm1.get(), p.get(), one.get())); + bn_check(BN_sub(qm1.get(), q.get(), one.get())); + bn_check(BN_gcd(g1.get(), pm1.get(), e.get(), bn_ctx())); + bn_check(BN_gcd(g2.get(), qm1.get(), e.get(), bn_ctx())); + bn_check(BN_mul(n.get(), p.get(), q.get(), bn_ctx())); + if (!BN_is_one(g1.get()) || !BN_is_one(g2.get()) || !BN_cmp(p.get(), q.get()) || BN_num_bits(n.get()) != bits) + continue; + Bytes nb = bn_bytes(n.get()), eb = bn_bytes(e.get()), pb = bn_bytes(p.get()), qb = bn_bytes(q.get()); + *pub = keyinfo_from_parts(rsa_algid(bits), {&nb, &eb}); + try { + *priv = keyinfo_from_parts(rsa_algid(bits), {&pb, &qb}); + } catch (...) { + free_keyinfo(*pub); + *pub = nullptr; + throw; + } + return; + } +} + +void dsa_generate(int bits, KeyInfo **pub, KeyInfo **priv) +{ + if (bits < 320 || bits > MAXKEYLENGTH) + fail(EKEYSIZE, str_printf("unsupported DSA key size %d", bits)); + Bn q = generate_prime(160); + Bn add = bn_new(), rem = bn_word(1); + bn_check(BN_lshift1(add.get(), q.get())); + Bn p = generate_prime(bits, add.get(), rem.get()); + Bn pm1 = bn_new(), e = bn_new(), g = bn_new(), one = bn_word(1); + bn_check(BN_sub(pm1.get(), p.get(), one.get())); + bn_check(BN_div(e.get(), nullptr, pm1.get(), q.get(), bn_ctx())); + for (unsigned long h = 2;; ++h) { + g = mod_exp(bn_word(h).get(), e.get(), p.get()); + if (!BN_is_one(g.get())) + break; + } + Bn x = bn_new(), y; + do { + bn_check(BN_priv_rand_range(x.get(), q.get())); + } while (BN_is_zero(x.get())); + y = mod_exp(g.get(), x.get(), p.get()); + + auto make = [&](const BIGNUM *value) { + KeyBits *params = mem_new(); + fill_ostr(¶ms->part1, bn_bytes(p.get())); + fill_ostr(¶ms->part2, bn_bytes(q.get())); + fill_ostr(¶ms->part3, bn_bytes(g.get())); + params->choice = 3; + KeyInfo *k = mem_new(); + k->subjectAI = mem_new(); + k->subjectAI->objid = copy_objid(dsa_aid.objid); + k->subjectAI->param = params; + Bytes v = der::integer_unsigned(bn_bytes(value)); + fill_bstr(&k->subjectkey, v, v.size() * 8); + return k; + }; + *pub = make(y.get()); + *priv = make(x.get()); +} + +Bytes rsa_encrypt_blocks(const RsaPublic &k, const uint8_t *p, size_t n) +{ + int bits = rsa_bits(k.n); + size_t in_block = size_t(bits - 1) / 8, out_block = size_t(bits + 7) / 8; + if (in_block == 0) + fail(EKEYSIZE, "RSA modulus too small"); + Bn modulus = bn_from(k.n), e = bn_from(k.e); + Bytes out; + for (size_t off = 0; off < n; off += in_block) { + Bytes block(in_block, 0); + std::memcpy(block.data(), p + off, std::min(in_block, n - off)); + Bn c = mod_exp(bn_from(block).get(), e.get(), modulus.get()); + der::append(out, bn_bytes(c.get(), out_block)); + } + return out; +} + +Bytes rsa_decrypt_blocks(const RsaPrivate &k, const uint8_t *p, size_t n) +{ + int bits = rsa_bits(k.n); + size_t out_block = size_t(bits - 1) / 8, in_block = size_t(bits + 7) / 8; + if (n % in_block) + fail(EDECRYPTION, "ciphertext length does not match the RSA modulus"); + Bytes out; + for (size_t off = 0; off < n; off += in_block) { + Bn m = rsa_private_op(k, bn_from(Bytes(p + off, p + off + in_block)).get()); + der::append(out, bn_bytes(m.get(), out_block)); + } + return out; +} + +Bytes rsa_raw_private(const RsaPrivate &k, const Bytes &m) +{ + size_t size = size_t(rsa_bits(k.n) + 7) / 8; + return bn_bytes(rsa_private_op(k, bn_from(m).get()).get(), size); +} + +Bytes rsa_private_key_der(const RsaPrivate &k) +{ + if (k.p.empty() || k.q.empty()) + fail(EALGNOTFITKEY, "RSA private key without primes"); + Bn p = bn_from(k.p), q = bn_from(k.q), d = bn_from(k.d), one = bn_word(1); + Bn pm1 = bn_new(), qm1 = bn_new(), dp = bn_new(), dq = bn_new(), qinv = bn_new(); + bn_check(BN_sub(pm1.get(), p.get(), one.get())); + bn_check(BN_sub(qm1.get(), q.get(), one.get())); + bn_check(BN_mod(dp.get(), d.get(), pm1.get(), bn_ctx())); + bn_check(BN_mod(dq.get(), d.get(), qm1.get(), bn_ctx())); + if (!BN_mod_inverse(qinv.get(), q.get(), p.get(), bn_ctx())) + fail(EALGNOTFITKEY, "invalid RSA primes"); + return der::seq({der::integer(0), der::integer_unsigned(k.n), der::integer_unsigned(k.e), der::integer_unsigned(k.d), + der::integer_unsigned(k.p), der::integer_unsigned(k.q), der::integer_unsigned(bn_bytes(dp.get())), + der::integer_unsigned(bn_bytes(dq.get())), der::integer_unsigned(bn_bytes(qinv.get()))}); +} + +Bytes sign_message(const KeyInfo *priv, const Bytes &e_hint, const AlgId *sig_alg, const uint8_t *msg, size_t n) +{ + const AlgInfo *a = sig_alg ? alg_by_oid(sig_alg->objid) : nullptr; + if (!a || a->type != SIG || a->hash == Hash::None) + fail(EUNKNOWNALGID, "not a signature algorithm"); + if (a->enc == SECUDE_ALG_RSA) { + if (!keyinfo_is_rsa(priv)) + fail(EALGNOTFITKEY, "RSA signature algorithm needs an RSA key"); + RsaPrivate k = rsa_private_from_keyinfo(priv, e_hint); + size_t size = size_t(rsa_bits(k.n) + 7) / 8; + return rsa_raw_private(k, pkcs1_type1(digest_info(a->hash, digest(a->hash, msg, n)), size)); + } + if (!keyinfo_is_dsa(priv)) + fail(EALGNOTFITKEY, "DSA signature algorithm needs a DSA key"); + DsaKey k = dsa_key(priv); + Bn z = dsa_message(k, a->hash, msg, n); + for (;;) { + Bn nonce = bn_new(), kinv = bn_new(), r = bn_new(), s = bn_new(); + bn_check(BN_priv_rand_range(nonce.get(), k.q.get())); + if (BN_is_zero(nonce.get())) + continue; + Bn gk = mod_exp(k.g.get(), nonce.get(), k.p.get()); + bn_check(BN_nnmod(r.get(), gk.get(), k.q.get(), bn_ctx())); + if (BN_is_zero(r.get()) || !BN_mod_inverse(kinv.get(), nonce.get(), k.q.get(), bn_ctx())) + continue; + bn_check(BN_mod_mul(s.get(), k.key.get(), r.get(), k.q.get(), bn_ctx())); + bn_check(BN_mod_add(s.get(), s.get(), z.get(), k.q.get(), bn_ctx())); + bn_check(BN_mod_mul(s.get(), s.get(), kinv.get(), k.q.get(), bn_ctx())); + if (BN_is_zero(s.get())) + continue; + return der::seq({der::integer_unsigned(bn_bytes(r.get())), der::integer_unsigned(bn_bytes(s.get()))}); + } +} + +bool verify_message(const KeyInfo *pub, const AlgId *sig_alg, const uint8_t *msg, size_t n, const Bytes &sig) +{ + const AlgInfo *a = sig_alg ? alg_by_oid(sig_alg->objid) : nullptr; + if (!a || a->type != SIG || a->hash == Hash::None) + fail(EUNKNOWNALGID, "not a signature algorithm"); + if (a->enc == SECUDE_ALG_RSA) { + if (!keyinfo_is_rsa(pub)) + fail(EALGNOTFITKEY, "RSA signature algorithm needs an RSA key"); + RsaPublic k = rsa_public_from_keyinfo(pub); + Bn modulus = bn_from(k.n), s = bn_from(sig); + if (BN_cmp(s.get(), modulus.get()) >= 0) + return false; + size_t size = size_t(rsa_bits(k.n) + 7) / 8; + Bytes em = bn_bytes(mod_exp(s.get(), bn_from(k.e).get(), modulus.get()).get(), size); + return em == pkcs1_type1(digest_info(a->hash, digest(a->hash, msg, n)), size); + } + if (!keyinfo_is_dsa(pub)) + fail(EALGNOTFITKEY, "DSA signature algorithm needs a DSA key"); + DsaKey k = dsa_key(pub); + der::Node node = der::parse_one(sig); + if (node.tag != der::SEQUENCE) + return false; + der::Reader rd(node); + Bn r = bn_from(der::get_unsigned(rd.next(der::INTEGER))), s = bn_from(der::get_unsigned(rd.next(der::INTEGER))); + rd.expect_end(); + if (BN_is_zero(r.get()) || BN_is_zero(s.get()) || BN_cmp(r.get(), k.q.get()) >= 0 || BN_cmp(s.get(), k.q.get()) >= 0) + return false; + Bn z = dsa_message(k, a->hash, msg, n); + Bn w = bn_new(), u1 = bn_new(), u2 = bn_new(), v = bn_new(); + if (!BN_mod_inverse(w.get(), s.get(), k.q.get(), bn_ctx())) + return false; + bn_check(BN_mod_mul(u1.get(), z.get(), w.get(), k.q.get(), bn_ctx())); + bn_check(BN_mod_mul(u2.get(), r.get(), w.get(), k.q.get(), bn_ctx())); + bn_check(BN_mod_exp2_mont(v.get(), k.g.get(), u1.get(), k.key.get(), u2.get(), k.p.get(), bn_ctx(), nullptr)); + bn_check(BN_nnmod(v.get(), v.get(), k.q.get(), bn_ctx())); + return BN_cmp(v.get(), r.get()) == 0; +} + +} // namespace compat diff --git a/port/secude/src/bn.hpp b/port/secude/src/bn.hpp new file mode 100644 index 000000000..708f34a20 --- /dev/null +++ b/port/secude/src/bn.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "internal.hpp" + +namespace compat { + +struct BnDeleter { + void operator()(BIGNUM *b) const { BN_clear_free(b); } +}; +using Bn = std::unique_ptr; + +inline Bn bn_new() +{ + BIGNUM *b = BN_new(); + if (!b) + throw std::bad_alloc(); + return Bn(b); +} + +inline Bn bn_from(const Bytes &be) +{ + Bn b = bn_new(); + if (!be.empty() && !BN_bin2bn(be.data(), int(be.size()), b.get())) + throw std::bad_alloc(); + return b; +} + +inline Bn bn_word(unsigned long w) +{ + Bn b = bn_new(); + if (!BN_set_word(b.get(), w)) + throw std::bad_alloc(); + return b; +} + +// Big-endian magnitude, left-padded with zeros to at least `size` octets. +inline Bytes bn_bytes(const BIGNUM *b, size_t size = 0) +{ + size_t n = size_t(BN_num_bytes(b)); + if (n < size) + n = size; + Bytes out(n); + if (n) + BN_bn2binpad(b, out.data(), int(n)); + return out; +} + +inline BN_CTX *bn_ctx() +{ + struct CtxDeleter { + void operator()(BN_CTX *c) const { BN_CTX_free(c); } + }; + thread_local std::unique_ptr c(BN_CTX_secure_new()); + if (!c) + throw std::bad_alloc(); + return c.get(); +} + +inline void bn_check(int ok) +{ + if (!ok) + fail(EINTERNAL, "big number operation failed"); +} + +} // namespace compat diff --git a/port/secude/src/cadb.cpp b/port/secude/src/cadb.cpp new file mode 100644 index 000000000..f13a04281 --- /dev/null +++ b/port/secude/src/cadb.cpp @@ -0,0 +1,171 @@ +// CA database: /cadb.der +// CADatabase ::= SEQUENCE { version INTEGER (1), entries SEQUENCE OF Entry } +// Entry ::= SEQUENCE { keyType INTEGER, issued Time, certificate Certificate } +#include "der.hpp" + +#include + +namespace compat { + +namespace { + +const char kFileName[] = "cadb.der"; + +struct Entry { + int key_type; + std::string issued; + Bytes cert; +}; + +std::string db_path(PSE pse) +{ + const char *dir = pse_cadir(pse); + if (!dir || !*dir) + fail(ENODIR, "PSE was opened without CA directory"); + std::string p = dir; + if (p.back() != '/' && p.back() != '\\') + p += '/'; + return p + kFileName; +} + +std::vector load(const std::string &path) +{ + bool exists = false; + Bytes file = read_file(path, exists); + std::vector out; + if (!exists) + return out; + der::Reader top(der::parse_one(file)); + if (der::get_integer(top.next(der::INTEGER)) != 1) + fail(EFILECORRUPTED, "unsupported CA database version"); + der::Reader entries(top.next(der::SEQUENCE)); + while (!entries.empty()) { + der::Reader e(entries.next(der::SEQUENCE)); + Entry x; + x.key_type = int(der::get_integer(e.next(der::INTEGER))); + x.issued = der::get_time(e.next()); + x.cert = e.next(der::SEQUENCE).raw(); + out.push_back(std::move(x)); + } + return out; +} + +void save(const std::string &path, const std::vector &entries) +{ + Bytes body; + for (const auto &e : entries) + der::append(body, der::seq({der::integer(e.key_type), der::time(e.issued), e.cert})); + write_file_atomic(path, der::seq({der::integer(1), der::tlv(der::SEQUENCE, body)}), 0644); +} + +Bytes serial_of(const Certificate *c) +{ + Bytes s = bytes_of(c->tbs->serialnumber); + return strip_leading_zeros(s.data(), s.size()); +} + +struct CertHolder { + Certificate *c; + explicit CertHolder(Certificate *cert) : c(cert) {} + ~CertHolder() { free_certificate(c); } + CertHolder(const CertHolder &) = delete; + CertHolder &operator=(const CertHolder &) = delete; +}; + +} // namespace + +} // namespace compat + +using namespace compat; + +extern "C" { + +int af_cadb_add_Certificate(PSE pse_handle, KeyType keytype, Certificate *newcert) +{ + return guarded("af_cadb_add_Certificate", -1, [&] { + if (!newcert || !newcert->tbs) + fail(EINVALID, "missing certificate"); + std::string path = db_path(pse_handle); + std::vector entries = load(path); + Bytes serial = serial_of(newcert); + for (const auto &e : entries) { + CertHolder c(dec_certificate(e.cert)); + if (serial_of(c.c) == serial) + fail(ECADBCERT, "a certificate with this serial number is already registered"); + } + entries.push_back(Entry{int(keytype), utc_now(), enc_certificate(newcert)}); + save(path, entries); + return 0; + }); +} + +Certificate *af_cadb_get_Certificate(PSE pse_handle, OctetString *serial) +{ + return guarded("af_cadb_get_Certificate", nullptr, [&]() -> Certificate * { + if (!serial) + fail(EINVALID, "missing serial number"); + Bytes wanted = bytes_of(serial); + wanted = strip_leading_zeros(wanted.data(), wanted.size()); + for (const auto &e : load(db_path(pse_handle))) { + Certificate *c = dec_certificate(e.cert); + if (serial_of(c) == wanted) + return c; + free_certificate(c); + } + fail(ECADBCERT, "certificate not found in CA database"); + }); +} + +SET_OF_IssuedCertificate *af_cadb_get_user(PSE pse_handle, Name *name) +{ + return guarded("af_cadb_get_user", nullptr, [&] { + DName *wanted = string_to_dname(name); + SET_OF_IssuedCertificate *head = nullptr, **tail = &head; + try { + for (const auto &e : load(db_path(pse_handle))) { + CertHolder c(dec_certificate(e.cert)); + if (!dname_equal(c.c->tbs->subject, wanted)) + continue; + auto *s = mem_new(); + *tail = s; + tail = &s->next; + s->element = mem_new(); + s->element->serial = new_ostr(bytes_of(c.c->tbs->serialnumber)); + s->element->date_of_issue = mem_strdup(e.issued); + } + } catch (...) { + free_dname(wanted); + aux_free_SET_OF_IssuedCertificate(&head); + throw; + } + free_dname(wanted); + if (!head) + fail(ECADBUSER, std::string("no certificate registered for ") + name); + return head; + }); +} + +SET_OF_Name *af_cadb_list_user(PSE pse_handle) +{ + return guarded("af_cadb_list_user", nullptr, [&] { + std::vector names; + for (const auto &e : load(db_path(pse_handle))) { + CertHolder c(dec_certificate(e.cert)); + std::string n = dname_to_string(c.c->tbs->subject); + if (std::find(names.begin(), names.end(), n) == names.end()) + names.push_back(n); + } + SET_OF_Name *head = nullptr, **tail = &head; + for (const auto &n : names) { + auto *s = mem_new(); + s->element = mem_strdup(n); + *tail = s; + tail = &s->next; + } + if (!head) + fail(ECADBUSER, "CA database is empty"); + return head; + }); +} + +} // extern "C" diff --git a/port/secude/src/cert.cpp b/port/secude/src/cert.cpp new file mode 100644 index 000000000..4c2a8df72 --- /dev/null +++ b/port/secude/src/cert.cpp @@ -0,0 +1,581 @@ +// X.509 certificates: prototype creation, certification by the CA PSE, +// PKRoot handling and printing. +#include "bn.hpp" +#include "der.hpp" + +#include +#include + +namespace compat { + +namespace { + +constexpr long kDefaultValiditySeconds = 365L * 24 * 3600; + +const AlgId *default_sig_alg(const KeyInfo *k) +{ + return keyinfo_is_dsa(k) ? &dsaWithSHA1_aid : &sha1WithRSASignature_aid; +} + +void add_extension(CertExtensions *&ext, const Oid &id, bool critical, const Bytes &value) +{ + if (!ext) + ext = mem_new(); + SEQUENCE_OF_Extension **tail = &ext->nonSupported; + int seq = 0; + while (*tail) { + tail = &(*tail)->next; + ++seq; + } + auto *n = mem_new(); + n->element = mem_new(); + n->element->extnId = new_objid(id); + n->element->critical = critical; + n->element->extnDERcode = new_ostr(value); + n->element->seqnum = seq; + *tail = n; +} + +Validity *validity_from_now(long seconds) +{ + Validity *v = mem_new(); + v->notbefore = mem_strdup(utc_now()); + v->notafter = mem_strdup(utc_now(seconds)); + return v; +} + +// Signs t (re-encoded) with priv and returns the finished certificate (takes ownership of t). +Certificate *sign_tbs(ToBeSigned *t, const KeyInfo *priv, const Bytes &e_hint) +{ + Certificate *c = mem_new(); + c->tbs = t; + try { + Bytes tbs = enc_tbs(t); + c->tbs_DERcode = new_ostr(tbs); + Bytes sig = sign_message(priv, e_hint, t->signatureAI, tbs.data(), tbs.size()); + c->sig = mem_new(); + c->sig->signAI = copy_algid(t->signatureAI); + fill_bstr(&c->sig->signature, sig, sig.size() * 8); + return c; + } catch (...) { + free_certificate(c); + throw; + } +} + +Bytes increment(Bytes serial) +{ + for (size_t i = serial.size(); i-- > 0;) + if (++serial[i] != 0) + return serial; + serial.insert(serial.begin(), 1); + return serial; +} + +struct KeyInfoHolder { + KeyInfo *k; + explicit KeyInfoHolder(KeyInfo *ki) : k(ki) {} + ~KeyInfoHolder() { free_keyinfo(k); } + KeyInfoHolder(const KeyInfoHolder &) = delete; + KeyInfoHolder &operator=(const KeyInfoHolder &) = delete; +}; + +struct CertHolder { + Certificate *c; + explicit CertHolder(Certificate *cert) : c(cert) {} + ~CertHolder() { free_certificate(c); } + CertHolder(const CertHolder &) = delete; + CertHolder &operator=(const CertHolder &) = delete; +}; + +bool same_serial(const OctetString *a, const OctetString *b) +{ + Bytes x = bytes_of(a), y = bytes_of(b); + return strip_leading_zeros(x.data(), x.size()) == strip_leading_zeros(y.data(), y.size()); +} + +} // namespace + +std::string format_time(const char *t) +{ + if (!t) + return "(none)"; + std::string s(t); + int year, mon, day, hour, min, sec = 0; + size_t p = 0; + if (s.size() >= 15 && s[14] == 'Z') { + year = std::stoi(s.substr(0, 4)); + p = 4; + } else if (s.size() >= 11) { + year = std::stoi(s.substr(0, 2)); + year += year < 50 ? 2000 : 1900; + p = 2; + } else { + return s; + } + mon = std::stoi(s.substr(p, 2)); + day = std::stoi(s.substr(p + 2, 2)); + hour = std::stoi(s.substr(p + 4, 2)); + min = std::stoi(s.substr(p + 6, 2)); + if (s.size() > p + 9 && std::isdigit(static_cast(s[p + 8]))) + sec = std::stoi(s.substr(p + 8, 2)); + std::tm tm{}; + tm.tm_year = year - 1900; + tm.tm_mon = mon - 1; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + std::time_t tt = timegm(&tm); + std::tm norm{}; + gmtime_r(&tt, &norm); + char buf[64]; + std::strftime(buf, sizeof buf, "%a %b %d %H:%M:%S %Y UTC", &norm); + return std::string(buf) + " (" + s + ")"; +} + +std::string sprint_algid(const AlgId *aid) +{ + if (!aid || !aid->objid) + return "Algorithm (none)"; + std::string s = "Algorithm " + alg_display_name(aid->objid) + " (OID " + oid_to_string(oid_of(aid->objid)) + ")"; + const AlgInfo *a = alg_by_oid(aid->objid); + ParmType pt = a ? a->parm : NoParmType; + if (!aid->param) { + ParmType effective = aid->parmoverride ? *aid->parmoverride : pt; + if (effective == PARM_NULL) + s += ", NULL"; + return s; + } + switch (pt) { + case PARM_INTEGER: + s += ", Keysize = " + std::to_string(*static_cast(aid->param)); + break; + case PARM_KeyBits: { + auto *k = static_cast(aid->param); + Bytes p = bytes_of(&k->part1); + s += ", Keysize = " + std::to_string(BN_num_bits(bn_from(p).get())); + break; + } + case PARM_OctetString: { + Bytes iv = bytes_of(static_cast(aid->param)); + s += ", IV = " + hex(iv.data(), iv.size()); + break; + } + case PARM_RC2CBC: { + auto *p = static_cast(aid->param); + Bytes iv = bytes_of(&p->IV); + s += ", version = " + std::to_string(p->version) + ", IV = " + hex(iv.data(), iv.size()); + break; + } + case PARM_PKCS5: { + auto *p = static_cast(aid->param); + Bytes salt = bytes_of(&p->salt); + s += ", salt = " + hex(salt.data(), salt.size()) + ", iterations = " + std::to_string(p->iterationCount); + break; + } + default: { + Bytes raw = bytes_of(static_cast(aid->param)); + s += ", parameter = " + hex(raw.data(), raw.size()); + break; + } + } + return s; +} + +namespace { + +std::string sprint_number(const char *label, const Bytes &v, const std::string &indent) +{ + int bits = BN_num_bits(bn_from(v).get()); + Bytes minimal = strip_leading_zeros(v.data(), v.size()); + return indent + label + " (" + std::to_string(bits) + " bits):\n" + hexdump(minimal.data(), minimal.size(), indent + " ", false); +} + +std::string sprint_keyinfo(const KeyInfo *k, uint32_t flags, const std::string &indent) +{ + std::string s; + if (!flags || (flags & ALGID)) + s += indent + sprint_algid(k->subjectAI) + "\n"; + if (flags & BITSTRING) { + Bytes b = bytes_of(&k->subjectkey); + s += indent + "Key BIT STRING (" + std::to_string(k->subjectkey.nbits) + " bits):\n" + + hexdump(b.data(), b.size(), indent + " ", false); + } + if (!flags || (flags & KEYBITS)) { + try { + if (keyinfo_is_rsa(k)) { + KeyBits *kb = dec_keybits(bytes_of(&k->subjectkey)); + Bytes p1 = bytes_of(&kb->part1), p2 = bytes_of(&kb->part2); + free_keybits_content(kb); + mem_free(kb); + s += sprint_number("Modulus", p1, indent); + s += sprint_number("Public exponent", p2, indent); + } else if (keyinfo_is_dsa(k)) { + if (k->subjectAI->param) { + auto *params = static_cast(k->subjectAI->param); + s += sprint_number("Prime p", bytes_of(¶ms->part1), indent); + s += sprint_number("Subprime q", bytes_of(¶ms->part2), indent); + s += sprint_number("Base g", bytes_of(¶ms->part3), indent); + } + Bytes y = bytes_of(&k->subjectkey); + s += sprint_number("Public key y", der::get_unsigned(der::parse_one(y)), indent); + } + } catch (const Error &) { + s += indent + "(undecodable key)\n"; + } + } + return s; +} + +std::string sprint_extension(const v3Extension *x, const std::string &indent) +{ + Oid id = oid_of(x->extnId); + Bytes v = bytes_of(x->extnDERcode); + std::string name, value; + try { + if (id == oids::cryptoolPseName) { + name = "CrypToolPSEName"; + value = der::get_string(der::parse_one(v)); + } else if (id == oids::basicConstraints) { + name = "BasicConstraints"; + der::Reader r(der::parse_one(v)); + der::Node n; + bool ca = r.next_optional(der::BOOLEAN, n) && der::get_boolean(n); + value = ca ? "CA:TRUE" : "CA:FALSE"; + if (r.next_optional(der::INTEGER, n)) + value += ", pathlen:" + std::to_string(der::get_integer(n)); + } else if (id == oids::keyUsage) { + name = "KeyUsage"; + size_t nbits = 0; + Bytes bits = der::get_bit_string(der::parse_one(v), nbits); + static const char *names[] = {"digitalSignature", "nonRepudiation", "keyEncipherment", + "dataEncipherment", "keyAgreement", "keyCertSign", + "cRLSign", "encipherOnly", "decipherOnly"}; + for (size_t i = 0; i < nbits && i < 9; ++i) + if (bits[i / 8] & (0x80 >> (i % 8))) + value += (value.empty() ? "" : ", ") + std::string(names[i]); + } else if (id == oids::subjectKeyIdentifier) { + name = "SubjectKeyIdentifier"; + Bytes kid = der::parse_one(v).value(); + value = hex(kid.data(), kid.size()); + } else { + name = oid_to_string(id); + value = hex(v.data(), v.size()); + } + } catch (const Error &) { + name = oid_to_string(id); + value = hex(v.data(), v.size()); + } + return indent + name + (x->critical ? " (critical)" : "") + ": " + value + "\n"; +} + +std::string sprint_certificate(const Certificate *c) +{ + if (!c || !c->tbs) + fail(EINVALID, "missing certificate"); + uint32_t f = print_cert_flags(); + uint32_t kf = print_keyinfo_flags() & 0xff; + const ToBeSigned *t = c->tbs; + std::string s = "Certificate:\n"; + const std::string in = " "; + if (!f || (f & VER)) + s += in + "Version: " + std::to_string(t->version + 1) + "\n"; + if (!f || (f & TBS)) { + Bytes serial = bytes_of(t->serialnumber); + s += in + "SerialNumber: " + hex(serial.data(), serial.size()) + "\n"; + } + if (!f || (f & ALG)) + s += in + "Signature algorithm: " + sprint_algid(t->signatureAI) + "\n"; + if (!f || (f & ISSUER)) + s += in + "Issuer: " + dname_to_string(t->issuer) + "\n"; + if ((!f || (f & VAL)) && t->valid) { + s += in + "Validity:\n"; + s += in + " NotBefore: " + format_time(t->valid->notbefore) + "\n"; + s += in + " NotAfter: " + format_time(t->valid->notafter) + "\n"; + } + if (!f || (f & SUBJECT)) + s += in + "Subject: " + dname_to_string(t->subject) + "\n"; + if ((!f || (f & KEYINFO)) && t->subjectPK) + s += in + "SubjectPublicKeyInfo:\n" + sprint_keyinfo(t->subjectPK, kf, in + " "); + if ((!f || (f & EXTENSIONS)) && t->extensions && t->extensions->nonSupported) { + s += in + "Extensions:\n"; + for (const SEQUENCE_OF_Extension *x = t->extensions->nonSupported; x; x = x->next) + if (x->element) + s += sprint_extension(x->element, in + " "); + } + if ((!f || (f & SIGNAT)) && c->sig) { + Bytes sig = bytes_of(&c->sig->signature); + s += in + "Signature (" + alg_display_name(c->sig->signAI ? c->sig->signAI->objid : nullptr) + "):\n" + + hexdump(sig.data(), sig.size(), in + " ", false); + } + if (f & (HSH | DER)) { + Bytes der_bytes = enc_certificate(c); + if (f & HSH) { + Bytes md5 = digest(Hash::MD5, der_bytes.data(), der_bytes.size()); + Bytes sha1 = digest(Hash::SHA1, der_bytes.data(), der_bytes.size()); + s += in + "Fingerprint (MD5): " + hex(md5.data(), md5.size()) + "\n"; + s += in + "Fingerprint (SHA-1): " + hex(sha1.data(), sha1.size()) + "\n"; + } + if (f & DER) + s += in + "DER code:\n" + hexdump(der_bytes.data(), der_bytes.size(), in + " ", true); + } + return s; +} + +const Certificate *find_in_fcpath(const FCPath *f, const DName *issuer, const OctetString *serial) +{ + for (; f; f = f->next_forwardpath) + for (const SET_OF_Certificate *s = f->liste; s; s = s->next) + if (s->element && s->element->tbs && dname_equal(s->element->tbs->issuer, issuer) && + same_serial(s->element->tbs->serialnumber, serial)) + return s->element; + return nullptr; +} + +} // namespace + +Certificate *make_ca_certificate(PSE pse, const KeyInfo *pub, const AlgId *sig_alg, const DName *subject, + long validity_seconds) +{ + auto store = store_of(pse); + KeyInfoHolder priv(read_private_key(pse, SIGNATURE)); + Bytes e_hint; + if (keyinfo_is_rsa(pub)) + e_hint = rsa_public_from_keyinfo(pub).e; + ToBeSigned *t = mem_new(); + try { + t->version = 2; + t->serialnumber = new_ostr(Bytes{0}); + t->signatureAI = copy_algid(sig_alg); + t->issuer = copy_dname(subject); + t->subject = copy_dname(subject); + t->valid = validity_from_now(validity_seconds); + t->subjectPK = copy_keyinfo(pub); + add_extension(t->extensions, oids::basicConstraints, true, der::seq({der::boolean(true)})); + const uint8_t usage[1] = {0x06}; + add_extension(t->extensions, oids::keyUsage, true, der::bit_string(usage, 7)); + } catch (...) { + free_tbs(t); + throw; + } + return sign_tbs(t, priv.k, e_hint); +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +Certificate *af_create_Certificate(PSE pse_handle, KeyInfo *keyinfo, AlgId *sig_alg, char *obj_name, DName *subject, + OctetString *serial, GeneralNames *subject_names, KeyIdentifier *subjKeyId, + Boolean CA, KeyUsage *key_usage) +{ + return guarded("af_create_Certificate", nullptr, [&] { + auto store = store_of(pse_handle); + if (!keyinfo) + fail(EINVALID, "missing public key"); + if (!subject) + fail(ENONAME, "missing subject name"); + if (subject_names) + fail(ENOTSUPPORTED, "subject alternative names are not supported"); + std::string object = obj_name && *obj_name ? obj_name : private_key_object(pse_handle, SIGNATURE); + const PseObject *o = store_find(store, object); + if (!o) + fail(EPSEOBJECTNOTEXISTING, "PSE object " + object + " does not exist"); + KeyInfoHolder priv(dec_keyinfo(o->value)); + Bytes e_hint; + if (keyinfo_is_rsa(keyinfo)) + e_hint = rsa_public_from_keyinfo(keyinfo).e; + + ToBeSigned *t = mem_new(); + try { + Bytes sn = serial && serial->noctets ? bytes_of(serial) : Bytes{1}; + t->serialnumber = new_ostr(sn); + t->signatureAI = copy_algid(sig_alg ? sig_alg : default_sig_alg(priv.k)); + t->issuer = copy_dname(subject); + t->subject = copy_dname(subject); + t->valid = validity_from_now(kDefaultValiditySeconds); + t->subjectPK = copy_keyinfo(keyinfo); + if (subjKeyId) + add_extension(t->extensions, oids::subjectKeyIdentifier, false, der::octet_string(bytes_of(subjKeyId))); + if (key_usage) { + CertExtensions tmp{}; + Ext_KeyUsage ku{}; + ku.critical = TRUE; + ku.extnValue = key_usage; + tmp.keyUsage = &ku; + CertExtensions *norm = dec_extensions(enc_extensions(&tmp)); + add_extension(t->extensions, oids::keyUsage, true, bytes_of(norm->nonSupported->element->extnDERcode)); + free_extensions(norm); + } + t->version = t->extensions ? 2 : 0; + } catch (...) { + free_tbs(t); + throw; + } + return sign_tbs(t, priv.k, e_hint); + }); +} + +Certificate *af_certify(PSE pse_handle, Certificate *tbc_cert, Validity *validity, AlgId *sig_alg, DName *name) +{ + return guarded("af_certify", nullptr, [&] { + auto store = store_of(pse_handle); + if (!tbc_cert || !tbc_cert->tbs || !tbc_cert->tbs->subjectPK) + fail(EINVALID, "incomplete prototype certificate"); + KeyInfoHolder priv(read_private_key(pse_handle, SIGNATURE)); + const PseObject *own = store_find(store, certificate_object(pse_handle, SIGNATURE)); + if (!own) + fail(EROOTCERT, "the CA PSE holds no certificate"); + CertHolder ca(dec_certificate(own->value)); + + const PseObject *sn = store_find(store, SerialNumber_name); + Bytes serial = sn && !sn->value.empty() ? sn->value : Bytes{1}; + + ToBeSigned *t = mem_new(); + try { + t->serialnumber = new_ostr(serial); + t->signatureAI = copy_algid(sig_alg ? sig_alg : default_sig_alg(priv.k)); + t->issuer = copy_dname(ca.c->tbs->subject); + t->subject = copy_dname(name ? name : tbc_cert->tbs->subject); + t->valid = validity ? copy_validity(validity) : validity_from_now(kDefaultValiditySeconds); + t->subjectPK = copy_keyinfo(tbc_cert->tbs->subjectPK); + Bytes ext = enc_extensions(tbc_cert->tbs->extensions); + if (!ext.empty()) + t->extensions = dec_extensions(ext); + t->version = t->extensions ? 2 : 0; + } catch (...) { + free_tbs(t); + throw; + } + Certificate *c = sign_tbs(t, priv.k, rsa_exponent_hint(pse_handle, priv.k)); + try { + store_put(store, SerialNumber_name, oid_of(&SerialNumber_oid), increment(serial)); + } catch (...) { + free_certificate(c); + throw; + } + return c; + }); +} + +PKRoot *aux_create_PKRoot(Certificate *cert1, Certificate *cert2) +{ + return guarded("aux_create_PKRoot", nullptr, [&] { + if (!cert1 || !cert1->tbs) + fail(EINVALID, "missing root certificate"); + auto make = [](const Certificate *c) { + Serial *s = mem_new(); + s->serial = new_ostr(bytes_of(c->tbs->serialnumber)); + s->version = c->tbs->version; + s->key = copy_keyinfo(c->tbs->subjectPK); + s->valid = copy_validity(c->tbs->valid); + s->sig = copy_signature(c->sig); + return s; + }; + PKRoot *p = mem_new(); + p->ca = copy_dname(cert1->tbs->subject); + p->newkey = make(cert1); + if (cert2 && cert2->tbs) + p->oldkey = make(cert2); + p->extensions = copy_extensions(cert1->tbs->extensions); + return p; + }); +} + +Certificate *af_PKRoot2Protocert(PKRoot *pkroot) +{ + return guarded("af_PKRoot2Protocert", nullptr, [&] { + if (!pkroot || !pkroot->newkey || !pkroot->newkey->key) + fail(EINVALID, "incomplete PKRoot"); + const Serial *k = pkroot->newkey; + Certificate *c = mem_new(); + try { + ToBeSigned *t = mem_new(); + c->tbs = t; + t->version = k->version; + t->serialnumber = new_ostr(bytes_of(k->serial)); + t->signatureAI = copy_algid(k->sig ? k->sig->signAI : &sha1WithRSASignature_aid); + t->issuer = copy_dname(pkroot->ca); + t->subject = copy_dname(pkroot->ca); + t->valid = k->valid ? copy_validity(k->valid) : validity_from_now(kDefaultValiditySeconds); + t->subjectPK = copy_keyinfo(k->key); + t->extensions = copy_extensions(pkroot->extensions); + c->tbs_DERcode = new_ostr(enc_tbs(t)); + c->sig = copy_signature(k->sig); + if (!c->sig) { + c->sig = mem_new(); + c->sig->signAI = copy_algid(t->signatureAI); + } + return c; + } catch (...) { + free_certificate(c); + throw; + } + }); +} + +Certificate *af_pse_get_Certificate(PSE pse_handle, KeyType type, DName *issuer, OctetString *serial) +{ + return guarded("af_pse_get_Certificate", nullptr, [&]() -> Certificate * { + auto store = store_of(pse_handle); + if (!issuer && !serial) { + const PseObject *o = store_find(store, certificate_object(pse_handle, type)); + if (!o) + fail(EPSEOBJECTNOTEXISTING, "PSE holds no certificate"); + return dec_certificate(o->value); + } + for (const char *name : {Cert_name, SignCert_name, EncCert_name}) { + const PseObject *o = store_find(store, name); + if (!o) + continue; + Certificate *c = dec_certificate(o->value); + if ((!issuer || dname_equal(c->tbs->issuer, issuer)) && (!serial || same_serial(c->tbs->serialnumber, serial))) + return c; + free_certificate(c); + } + if (const PseObject *o = store_find(store, FCPath_name)) { + FCPath *f = dec_fcpath(o->value); + const Certificate *found = find_in_fcpath(f, issuer, serial); + Certificate *c = found ? copy_certificate(found) : nullptr; + free_fcpath(f); + if (c) + return c; + } + fail(EPSEOBJECTNOTEXISTING, "certificate not found in PSE"); + }); +} + +Certificates *af_pse_get_Certificates(PSE pse_handle, KeyType type, DName *name) +{ + return guarded("af_pse_get_Certificates", nullptr, [&] { + auto store = store_of(pse_handle); + const PseObject *o = store_find(store, certificate_object(pse_handle, type)); + if (!o) + fail(EPSEOBJECTNOTEXISTING, "PSE holds no certificate"); + Certificates *c = mem_new(); + try { + c->usercertificate = dec_certificate(o->value); + if (const PseObject *f = store_find(store, FCPath_name)) + c->forwardpath = dec_fcpath(f->value); + return c; + } catch (...) { + aux_free_Certificates(&c); + throw; + } + }); +} + +char *aux_sprint_Certificate(PSE pse_handle, char *string, Certificate *cert) +{ + return guarded("aux_sprint_Certificate", nullptr, [&] { return append_string(string, sprint_certificate(cert)); }); +} + +char *aux_sprint_AlgId(char *string, AlgId *aid) +{ + return guarded("aux_sprint_AlgId", nullptr, [&] { return append_string(string, sprint_algid(aid)); }); +} + +} // extern "C" diff --git a/port/secude/src/crypt_api.cpp b/port/secude/src/crypt_api.cpp new file mode 100644 index 000000000..5502035ed --- /dev/null +++ b/port/secude/src/crypt_api.cpp @@ -0,0 +1,307 @@ +// sec_* and af_* encryption, signature and key generation entry points. +// +// RSA encryption (rsa / rsaEncryption keys) is textbook RSA as used by CrypTool: +// the input is split into blocks of (bits-1)/8 octets (the last block is +// padded with zero octets), each block is encrypted into (bits+7)/8 octets. +// Decryption returns (bits-1)/8 octets per block. +#include "internal.hpp" + +namespace compat { + +namespace { + +struct KeyInfoHolder { + KeyInfo *k = nullptr; + ~KeyInfoHolder() { free_keyinfo(k); } +}; + +const KeyInfo *resolve_key(const Key *key, KeyInfoHolder &holder) +{ + if (!key) + fail(EINVALID, "missing key"); + if (key->key) + return key->key; + if (key->pse_sel) { + auto s = store_of(key->pse_sel); + std::string name = key->pse_sel->object ? key->pse_sel->object : SKnew_name; + const PseObject *o = store_find(s, name); + if (!o) + fail(EPSEOBJECTNOTEXISTING, "PSE object " + name + " does not exist"); + holder.k = dec_keyinfo(o->value); + return holder.k; + } + fail(EINVALID, "key has neither a value nor a PSE reference"); +} + +const AlgInfo *algorithm_of(const Key *key, const KeyInfo *k) +{ + const AlgId *a = key->alg && key->alg->objid ? key->alg : k->subjectAI; + const AlgInfo *info = a ? alg_by_oid(a->objid) : nullptr; + if (!info) + fail(EUNKNOWNALGID, "unknown key algorithm"); + return info; +} + +const AlgId *cipher_algid(const Key *key, const KeyInfo *k) +{ + return key->alg && key->alg->objid ? key->alg : k->subjectAI; +} + +void put_bits(BitString *out, const Bytes &data) +{ + if (!out) + fail(EINVALID, "missing output"); + if (!out->bits) { + fill_bstr(out, data, data.size() * 8); + return; + } + size_t off = out->nbits / 8; + if (!data.empty()) + std::memcpy(out->bits + off, data.data(), data.size()); + out->nbits = sec_uint4((off + data.size()) * 8); +} + +void put_octets(OctetString *out, const Bytes &data) +{ + if (!out) + fail(EINVALID, "missing output"); + if (!out->octets) { + fill_ostr(out, data); + return; + } + size_t off = out->noctets; + if (!data.empty()) + std::memcpy(out->octets + off, data.data(), data.size()); + out->noctets = sec_uint4(off + data.size()); +} + +Bytes encrypt(const Key *key, const uint8_t *in, size_t n) +{ + KeyInfoHolder holder; + const KeyInfo *k = resolve_key(key, holder); + const AlgInfo *a = algorithm_of(key, k); + if (a->enc == SECUDE_ALG_RSA) + return rsa_encrypt_blocks(rsa_public_from_keyinfo(k), in, n); + if (a->type != SYM_ENC) + fail(EALGNOTFITKEY, std::string(a->name) + " cannot be used for encryption"); + return sym_encrypt(cipher_algid(key, k), bytes_of(&k->subjectkey), k->subjectkey.nbits, in, n); +} + +Bytes decrypt(const Key *key, const Bytes &e_hint, const uint8_t *in, size_t n) +{ + KeyInfoHolder holder; + const KeyInfo *k = resolve_key(key, holder); + const AlgInfo *a = algorithm_of(key, k); + if (a->enc == SECUDE_ALG_RSA) + return rsa_decrypt_blocks(rsa_private_from_keyinfo(k, e_hint), in, n); + if (a->type != SYM_ENC) + fail(EALGNOTFITKEY, std::string(a->name) + " cannot be used for decryption"); + return sym_decrypt(cipher_algid(key, k), bytes_of(&k->subjectkey), k->subjectkey.nbits, in, n); +} + +const uint8_t *data_of(const OctetString *o) { return o ? reinterpret_cast(o->octets) : nullptr; } + +int key_bits(const KeyInfo *k) +{ + if (keyinfo_is_rsa(k)) { + KeyBits *kb = dec_keybits(bytes_of(&k->subjectkey)); + Bytes a = bytes_of(&kb->part1), b = bytes_of(&kb->part2); + bool pub = kb->choice == 2 && a.size() > b.size() + 4; + free_keybits_content(kb); + mem_free(kb); + if (pub) + return rsa_bits(a); + return rsa_bits(a) + rsa_bits(b); + } + if (keyinfo_is_dsa(k) && k->subjectAI->param) + return rsa_bits(bytes_of(&static_cast(k->subjectAI->param)->part1)); + return int(k->subjectkey.nbits); +} + +} // namespace + +} // namespace compat + +using namespace compat; + +extern "C" { + +int sec_encrypt_all(OctetString *in_octets, BitString *out_bits, Key *key) +{ + return guarded("sec_encrypt_all", -1, [&] { + if (!in_octets) + fail(EINVALID, "missing input"); + put_bits(out_bits, encrypt(key, data_of(in_octets), in_octets->noctets)); + return 0; + }); +} + +int sec_decrypt_all(BitString *in_bits, OctetString *out_octets, Key *key) +{ + return guarded("sec_decrypt_all", -1, [&] { + if (!in_bits) + fail(EINVALID, "missing input"); + Bytes in = bytes_of(in_bits); + put_octets(out_octets, decrypt(key, Bytes(), in.data(), in.size())); + return 0; + }); +} + +RC sec_verify_all(OctetString *in_octets, Signature *signature, Key *key, HashInput *hash_input) +{ + return guarded("sec_verify_all", -1, [&] { + if (!in_octets || !signature) + fail(EINVALID, "missing parameter"); + KeyInfoHolder holder; + const KeyInfo *k = resolve_key(key, holder); + if (!verify_message(k, signature->signAI, data_of(in_octets), in_octets->noctets, bytes_of(&signature->signature))) + fail(EVERIFY, "signature verification failed"); + return 0; + }); +} + +RC rsa_sign_all(OctetString *hash, BitString *sign, KeyBits *key) +{ + return guarded("rsa_sign_all", -1, [&] { + if (!hash || !sign || !key) + fail(EINVALID, "missing parameter"); + KeyInfoHolder holder; + holder.k = mem_new(); + holder.k->subjectAI = copy_algid(&rsa_aid); + Bytes kb = enc_keybits(key); + fill_bstr(&holder.k->subjectkey, kb, kb.size() * 8); + Bytes sig = rsa_raw_private(rsa_private_from_keyinfo(holder.k, Bytes()), bytes_of(hash)); + fill_bstr(sign, sig, sig.size() * 8); + return 0; + }); +} + +int sec_get_key(KeyInfo *keyinfo, Key *key) +{ + return guarded("sec_get_key", -1, [&] { + if (!keyinfo) + fail(EINVALID, "missing output"); + KeyInfoHolder holder; + KeyInfo *copy = copy_keyinfo(resolve_key(key, holder)); + *keyinfo = *copy; + mem_free(copy); + return 0; + }); +} + +OctetString *sec_random_ostr(sec_uint4 noctects, int security) +{ + return guarded("sec_random_ostr", nullptr, [&] { return new_ostr(random_bytes(noctects)); }); +} + +int af_encrypt_all(PSE pse_handle, OctetString *inoctets, BitString *outbits, Key *key, DName *dname) +{ + return guarded("af_encrypt_all", -1, [&] { + if (!inoctets) + fail(EINVALID, "missing input"); + store_of(pse_handle); + if (key && (key->key || key->pse_sel)) { + put_bits(outbits, encrypt(key, data_of(inoctets), inoctets->noctets)); + return 0; + } + Certificate *own = af_pse_get_Certificate(pse_handle, ENCRYPTION, nullptr, nullptr); + if (!own) + fail(EPSEOBJECTNOTEXISTING, "no encryption key available"); + Key k{}; + k.key = own->tbs->subjectPK; + try { + put_bits(outbits, encrypt(&k, data_of(inoctets), inoctets->noctets)); + } catch (...) { + free_certificate(own); + throw; + } + free_certificate(own); + return 0; + }); +} + +int af_decrypt_all(PSE pse_handle, BitString *inbits, OctetString *outoctets, Key *key) +{ + return guarded("af_decrypt_all", -1, [&] { + if (!inbits) + fail(EINVALID, "missing input"); + Bytes in = bytes_of(inbits); + if (key && (key->key || key->pse_sel)) { + KeyInfoHolder holder; + Bytes hint = rsa_exponent_hint(pse_handle, resolve_key(key, holder)); + put_octets(outoctets, decrypt(key, hint, in.data(), in.size())); + return 0; + } + KeyInfoHolder priv; + priv.k = read_private_key(pse_handle, ENCRYPTION); + Key k{}; + k.key = priv.k; + put_octets(outoctets, decrypt(&k, rsa_exponent_hint(pse_handle, priv.k), in.data(), in.size())); + return 0; + }); +} + +RC af_sign_all(PSE pse_handle, OctetString *in_octets, Signature *signature) +{ + return guarded("af_sign_all", -1, [&] { + if (!in_octets || !signature) + fail(EINVALID, "missing parameter"); + KeyInfoHolder priv; + priv.k = read_private_key(pse_handle, SIGNATURE); + if (!signature->signAI) + signature->signAI = keyinfo_is_dsa(priv.k) ? &dsaWithSHA1_aid : &sha1WithRSASignature_aid; + Bytes sig = sign_message(priv.k, rsa_exponent_hint(pse_handle, priv.k), signature->signAI, data_of(in_octets), + in_octets->noctets); + fill_bstr(&signature->signature, sig, sig.size() * 8); + return 0; + }); +} + +RC af_gen_key(PSE pse_handle, Key *key, KeyType ktype, Boolean replace) +{ + return guarded("af_gen_key", -1, [&] { + auto store = store_of(pse_handle); + if (!key || !key->alg || !key->alg->objid) + fail(EINVALID, "missing key algorithm"); + const AlgInfo *a = alg_by_oid(key->alg->objid); + if (!a || (a->enc != SECUDE_ALG_RSA && a->enc != SECUDE_ALG_DSA)) + fail(EUNKNOWNALGID, "key generation supports RSA and DSA only"); + int bits = key->key_size > 0 ? key->key_size : DEF_ASYM_KEYSIZE; + std::string object = store_onekeypaironly(store) ? SKnew_name : (ktype == SIGNATURE ? SignSK_name : DecSKnew_name); + if (!replace && store_find(store, object)) + fail(EPSEALREADYEXISTING, "PSE object " + object + " already exists"); + KeyInfo *pub = nullptr, *priv = nullptr; + if (a->enc == SECUDE_ALG_RSA) + rsa_generate(bits, &pub, &priv); + else + dsa_generate(bits, &pub, &priv); + KeyInfoHolder priv_holder; + priv_holder.k = priv; + try { + store_put(store, object, oid_of(pse_object_oid(object.c_str())), enc_keyinfo(priv)); + } catch (...) { + free_keyinfo(pub); + throw; + } + key->key = pub; + return 0; + }); +} + +RC af_pse_get_keysize(PSE pse_handle, int *sig, int *enc, AlgEnc *sig_type) +{ + return guarded("af_pse_get_keysize", -1, [&] { + KeyInfoHolder s, e; + s.k = read_private_key(pse_handle, SIGNATURE); + e.k = read_private_key(pse_handle, ENCRYPTION); + if (sig) + *sig = key_bits(s.k); + if (enc) + *enc = key_bits(e.k); + if (sig_type) + *sig_type = keyinfo_is_dsa(s.k) ? SECUDE_ALG_DSA : SECUDE_ALG_RSA; + return 0; + }); +} + +} // extern "C" diff --git a/port/secude/src/data_flags.cpp b/port/secude/src/data_flags.cpp new file mode 100644 index 000000000..89fb02e65 --- /dev/null +++ b/port/secude/src/data_flags.cpp @@ -0,0 +1,18 @@ +// Kept free of SECUDE headers: crypt_p.h declares print_keyinfo_flag as +// unsigned char, but CrypTool accesses it through a sec_uint4 pointer, so the +// object must provide four bytes. +#include + +extern "C" { +uint32_t print_cert_flag = 2 | 4 | 8 | 16 | 32 | 64 | 256 | 512 | 1024; +alignas(4) uint32_t print_keyinfo_flag = 1 | 4 | 8; +} + +namespace compat { + +uint32_t print_cert_flags() { return print_cert_flag; } +uint32_t print_keyinfo_flags() { return print_keyinfo_flag; } +void *print_cert_flag_address() { return &print_cert_flag; } +void *print_keyinfo_flag_address() { return &print_keyinfo_flag; } + +} // namespace compat diff --git a/port/secude/src/der.cpp b/port/secude/src/der.cpp new file mode 100644 index 000000000..723e6879e --- /dev/null +++ b/port/secude/src/der.cpp @@ -0,0 +1,353 @@ +#include "der.hpp" + +#include + +namespace compat { +namespace der { + +namespace { + +void put_length(Bytes &out, size_t n) +{ + if (n < 0x80) { + out.push_back(uint8_t(n)); + return; + } + uint8_t buf[sizeof(size_t)]; + int k = 0; + while (n) { + buf[k++] = uint8_t(n & 0xff); + n >>= 8; + } + out.push_back(uint8_t(0x80 | k)); + while (k) + out.push_back(buf[--k]); +} + +[[noreturn]] void bad(const char *what) +{ + fail(EDECODE, std::string("ASN.1 decoding failed: ") + what); +} + +} // namespace + +Bytes tlv(uint8_t tag, const uint8_t *p, size_t n) +{ + Bytes out; + out.reserve(n + 6); + out.push_back(tag); + put_length(out, n); + if (n) + out.insert(out.end(), p, p + n); + return out; +} + +void append(Bytes &out, const Bytes &part) +{ + out.insert(out.end(), part.begin(), part.end()); +} + +Bytes concat(std::initializer_list parts) +{ + Bytes out; + for (const auto &p : parts) + append(out, p); + return out; +} + +Bytes seq(std::initializer_list parts) +{ + return tlv(SEQUENCE, concat(parts)); +} + +Bytes set_of(std::vector parts) +{ + std::sort(parts.begin(), parts.end()); + Bytes body; + for (const auto &p : parts) + append(body, p); + return tlv(SET, body); +} + +Bytes integer(long long v) +{ + Bytes b; + unsigned long long u = static_cast(v); + for (int i = 0; i < 8; ++i) + b.insert(b.begin(), uint8_t(u >> (8 * i))); + size_t i = 0; + while (i + 1 < b.size() && ((b[i] == 0x00 && !(b[i + 1] & 0x80)) || (b[i] == 0xff && (b[i + 1] & 0x80)))) + ++i; + return tlv(INTEGER, Bytes(b.begin() + long(i), b.end())); +} + +Bytes integer_unsigned(const uint8_t *p, size_t n) +{ + while (n > 1 && *p == 0) { + ++p; + --n; + } + Bytes c; + if (n == 0 || (p[0] & 0x80)) + c.push_back(0); + c.insert(c.end(), p, p + n); + return tlv(INTEGER, c); +} + +Bytes oid(const Oid &o) +{ + if (o.size() < 2 || o[0] > 2) + fail(EENCODE, "invalid object identifier"); + Bytes c; + auto put = [&c](unsigned long long v) { + uint8_t tmp[10]; + int k = 0; + do { + tmp[k++] = uint8_t(v & 0x7f); + v >>= 7; + } while (v); + while (k > 1) + c.push_back(uint8_t(tmp[--k] | 0x80)); + c.push_back(tmp[0]); + }; + put(static_cast(o[0]) * 40 + o[1]); + for (size_t i = 2; i < o.size(); ++i) + put(o[i]); + return tlv(OID, c); +} + +Bytes octet_string(const Bytes &b) { return tlv(OCTET_STRING, b); } + +Bytes bit_string(const uint8_t *p, size_t nbits) +{ + size_t n = (nbits + 7) / 8; + Bytes c; + c.push_back(uint8_t((8 - nbits % 8) % 8)); + if (n) + c.insert(c.end(), p, p + n); + if (nbits % 8) + c.back() &= uint8_t(0xff << (8 - nbits % 8)); + return tlv(BIT_STRING, c); +} + +Bytes null() { return Bytes{NULL_, 0}; } + +Bytes boolean(bool v) { return Bytes{BOOLEAN, 1, uint8_t(v ? 0xff : 0)}; } + +Bytes string(uint8_t tag, const std::string &s) +{ + if (tag == UTF8String) { + std::string u; + for (unsigned char ch : s) { + if (ch < 0x80) { + u += char(ch); + } else { + u += char(0xC0 | (ch >> 6)); + u += char(0x80 | (ch & 0x3f)); + } + } + return tlv(tag, reinterpret_cast(u.data()), u.size()); + } + if (tag == BMPString) { + Bytes c; + for (unsigned char ch : s) { + c.push_back(0); + c.push_back(ch); + } + return tlv(tag, c); + } + return tlv(tag, reinterpret_cast(s.data()), s.size()); +} + +Bytes time(const std::string &t) +{ + uint8_t tag = t.size() >= 15 ? GeneralizedTime : UTCTime; + return tlv(tag, reinterpret_cast(t.data()), t.size()); +} + +bool try_parse_tlv(const uint8_t *p, size_t n, Node &out) +{ + if (n < 2) + return false; + const uint8_t *q = p; + uint8_t tag = *q++; + if ((tag & 0x1f) == 0x1f) + return false; + size_t len; + uint8_t l0 = *q++; + if (l0 < 0x80) { + len = l0; + } else { + int k = l0 & 0x7f; + if (k == 0 || k > 4 || size_t(k) > n - 2) + return false; + len = 0; + for (int i = 0; i < k; ++i) + len = (len << 8) | *q++; + } + size_t hdr = size_t(q - p); + if (len > n - hdr) + return false; + out.tag = tag; + out.hdr = p; + out.val = q; + out.len = len; + out.total = hdr + len; + return true; +} + +Node Reader::next() +{ + Node n; + if (!try_parse_tlv(p_, size_t(end_ - p_), n)) + bad("malformed element"); + p_ += n.total; + return n; +} + +Node Reader::next(uint8_t tag) +{ + Node n = next(); + if (n.tag != tag) + bad("unexpected tag"); + return n; +} + +bool Reader::next_optional(uint8_t tag, Node &out) +{ + if (!peek(tag)) + return false; + out = next(); + return true; +} + +void Reader::expect_end() const +{ + if (p_ != end_) + bad("junk at end of element"); +} + +Node parse_one(const Bytes &b) +{ + Reader r(b); + Node n = r.next(); + r.expect_end(); + return n; +} + +long long get_integer(const Node &n) +{ + if (n.tag != INTEGER || n.len == 0 || n.len > 8) + bad("INTEGER expected"); + long long v = (n.val[0] & 0x80) ? -1 : 0; + for (size_t i = 0; i < n.len; ++i) + v = static_cast((static_cast(v) << 8) | n.val[i]); + return v; +} + +Bytes get_unsigned(const Node &n) +{ + if (n.tag != INTEGER || n.len == 0) + bad("INTEGER expected"); + return strip_leading_zeros(n.val, n.len); +} + +Oid get_oid(const Node &n) +{ + if (n.tag != OID || n.len == 0) + bad("OBJECT IDENTIFIER expected"); + Oid o; + unsigned long long v = 0; + bool first = true; + for (size_t i = 0; i < n.len; ++i) { + v = (v << 7) | (n.val[i] & 0x7f); + if (v > 0xffffffffULL) + bad("OBJECT IDENTIFIER component too large"); + if (!(n.val[i] & 0x80)) { + if (first) { + unsigned a = v < 40 ? 0 : v < 80 ? 1 : 2; + o.push_back(a); + o.push_back(unsigned(v - 40ULL * a)); + first = false; + } else { + o.push_back(unsigned(v)); + } + v = 0; + } + } + if (v != 0 || first) + bad("truncated OBJECT IDENTIFIER"); + return o; +} + +Bytes get_bit_string(const Node &n, size_t &nbits) +{ + if (n.tag != BIT_STRING || n.len == 0 || n.val[0] > 7) + bad("BIT STRING expected"); + nbits = (n.len - 1) * 8 - n.val[0]; + return Bytes(n.val + 1, n.val + n.len); +} + +std::string get_string(const Node &n) +{ + std::string s; + if (n.tag == BMPString) { + for (size_t i = 0; i + 1 < n.len; i += 2) { + unsigned c = (unsigned(n.val[i]) << 8) | n.val[i + 1]; + s += c < 0x100 ? char(c) : '?'; + } + return s; + } + if (n.tag == UTF8String) { + for (size_t i = 0; i < n.len; ++i) { + uint8_t c = n.val[i]; + if (c < 0x80) { + s += char(c); + } else if ((c & 0xE0) == 0xC0 && i + 1 < n.len) { + unsigned cp = (unsigned(c & 0x1f) << 6) | (n.val[i + 1] & 0x3f); + s += cp < 0x100 ? char(cp) : '?'; + ++i; + } else { + while (i + 1 < n.len && (n.val[i + 1] & 0xC0) == 0x80) + ++i; + s += '?'; + } + } + return s; + } + if (n.constructed()) + bad("primitive string expected"); + return std::string(reinterpret_cast(n.val), n.len); +} + +std::string get_time(const Node &n) +{ + if (n.tag != UTCTime && n.tag != GeneralizedTime) + bad("time expected"); + return std::string(reinterpret_cast(n.val), n.len); +} + +bool get_boolean(const Node &n) +{ + if (n.tag != BOOLEAN || n.len != 1) + bad("BOOLEAN expected"); + return n.val[0] != 0; +} + +} // namespace der + +Bytes strip_leading_zeros(const uint8_t *p, size_t n) +{ + while (n > 1 && *p == 0) { + ++p; + --n; + } + return Bytes(p, p + n); +} + +Bytes enc_unsigned_integer(const uint8_t *p, size_t n) +{ + return der::integer_unsigned(p, n); +} + +} // namespace compat diff --git a/port/secude/src/der.hpp b/port/secude/src/der.hpp new file mode 100644 index 000000000..3cc7852db --- /dev/null +++ b/port/secude/src/der.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include "internal.hpp" + +#include + +// Minimal DER writer/reader (single-octet tags, definite lengths). +namespace compat { +namespace der { + +enum Tag : uint8_t { + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL_ = 0x05, + OID = 0x06, + UTF8String = 0x0C, + PrintableString = 0x13, + T61String = 0x14, + IA5String = 0x16, + UTCTime = 0x17, + GeneralizedTime = 0x18, + BMPString = 0x1E, + SEQUENCE = 0x30, + SET = 0x31, +}; + +inline constexpr uint8_t ctx(unsigned n, bool constructed = true) +{ + return uint8_t(0x80 | (constructed ? 0x20 : 0) | n); +} + +Bytes tlv(uint8_t tag, const uint8_t *p, size_t n); +inline Bytes tlv(uint8_t tag, const Bytes &content) { return tlv(tag, content.data(), content.size()); } +Bytes seq(std::initializer_list parts); +Bytes set_of(std::vector parts); // sorted, as DER requires +Bytes concat(std::initializer_list parts); +void append(Bytes &out, const Bytes &part); + +Bytes integer(long long v); +Bytes integer_unsigned(const uint8_t *p, size_t n); +inline Bytes integer_unsigned(const Bytes &b) { return integer_unsigned(b.data(), b.size()); } +Bytes oid(const Oid &o); +Bytes octet_string(const Bytes &b); +Bytes bit_string(const uint8_t *p, size_t nbits); +Bytes null(); +Bytes boolean(bool v); +Bytes string(uint8_t tag, const std::string &s); +Bytes time(const std::string &t); // UTCTime (13 chars) or GeneralizedTime (15 chars) + +struct Node { + uint8_t tag = 0; + const uint8_t *hdr = nullptr; // start of TLV + const uint8_t *val = nullptr; // start of contents + size_t len = 0; // contents length + size_t total = 0; // header + contents + bool constructed() const { return tag & 0x20; } + Bytes raw() const { return Bytes(hdr, hdr + total); } + Bytes value() const { return Bytes(val, val + len); } +}; + +class Reader { +public: + Reader(const uint8_t *p, size_t n) : p_(p), end_(p + n) {} + explicit Reader(const Bytes &b) : Reader(b.data(), b.size()) {} + explicit Reader(Bytes &&) = delete; // nodes would point into a destroyed buffer + explicit Reader(const Node &n) : Reader(n.val, n.len) {} + bool empty() const { return p_ == end_; } + bool peek(uint8_t tag) const { return p_ != end_ && *p_ == tag; } + Node next(); + Node next(uint8_t tag); + bool next_optional(uint8_t tag, Node &out); + void expect_end() const; + +private: + const uint8_t *p_; + const uint8_t *end_; +}; + +Node parse_one(const Bytes &b); // exactly one element, nothing trailing +Node parse_one(Bytes &&) = delete; +bool try_parse_tlv(const uint8_t *p, size_t n, Node &out); + +long long get_integer(const Node &n); +Bytes get_unsigned(const Node &n); // INTEGER contents without sign octets +Oid get_oid(const Node &n); +Bytes get_bit_string(const Node &n, size_t &nbits); +std::string get_string(const Node &n); // any string type, converted to Latin-1 where possible +std::string get_time(const Node &n); +bool get_boolean(const Node &n); + +} // namespace der +} // namespace compat diff --git a/port/secude/src/dname.cpp b/port/secude/src/dname.cpp new file mode 100644 index 000000000..f7b866638 --- /dev/null +++ b/port/secude/src/dname.cpp @@ -0,0 +1,333 @@ +// Distinguished names: string form "CN=..., DC=..., DC=..." (least significant +// RDN first, as in RFC 4514) <-> DName list in DER order. +#include "der.hpp" + +#include +#include +#include + +namespace compat { + +namespace { + +struct AttrKeyword { + const char *keyword; + Oid oid; + uint8_t tag; +}; + +const std::vector &keywords() +{ + static const std::vector k = { + {"CN", {2, 5, 4, 3}, der::PrintableString}, + {"C", {2, 5, 4, 6}, der::PrintableString}, + {"L", {2, 5, 4, 7}, der::PrintableString}, + {"ST", {2, 5, 4, 8}, der::PrintableString}, + {"SP", {2, 5, 4, 8}, der::PrintableString}, + {"STREET", {2, 5, 4, 9}, der::PrintableString}, + {"O", {2, 5, 4, 10}, der::PrintableString}, + {"OU", {2, 5, 4, 11}, der::PrintableString}, + {"T", {2, 5, 4, 12}, der::PrintableString}, + {"TITLE", {2, 5, 4, 12}, der::PrintableString}, + {"SN", {2, 5, 4, 4}, der::PrintableString}, + {"SERIALNUMBER", {2, 5, 4, 5}, der::PrintableString}, + {"G", {2, 5, 4, 42}, der::PrintableString}, + {"GN", {2, 5, 4, 42}, der::PrintableString}, + {"DC", {0, 9, 2342, 19200300, 100, 1, 25}, der::IA5String}, + {"UID", {0, 9, 2342, 19200300, 100, 1, 1}, der::UTF8String}, + {"EMAIL", {1, 2, 840, 113549, 1, 9, 1}, der::IA5String}, + {"E", {1, 2, 840, 113549, 1, 9, 1}, der::IA5String}, + }; + return k; +} + +const AttrKeyword *keyword_by_name(const std::string &name) +{ + for (const auto &k : keywords()) + if (!strcasecmp(k.keyword, name.c_str())) + return &k; + return nullptr; +} + +const AttrKeyword *keyword_by_oid(const Oid &o) +{ + for (const auto &k : keywords()) + if (k.oid == o) + return &k; + return nullptr; +} + +bool printable(const std::string &s) +{ + for (unsigned char c : s) + if (!(std::isalnum(c) || std::strchr(" '()+,-./:=?", c)) || c >= 0x80) + return false; + return true; +} + +std::string trim(const std::string &s) +{ + size_t b = s.find_first_not_of(" \t"); + if (b == std::string::npos) + return {}; + size_t e = s.find_last_not_of(" \t"); + return s.substr(b, e - b + 1); +} + +Oid parse_dotted(const std::string &s) +{ + Oid o; + size_t i = 0; + while (i < s.size()) { + if (!std::isdigit(static_cast(s[i]))) + return {}; + unsigned long v = std::strtoul(s.c_str() + i, nullptr, 10); + o.push_back(unsigned(v)); + size_t dot = s.find('.', i); + if (dot == std::string::npos) + break; + i = dot + 1; + } + return o.size() >= 2 ? o : Oid{}; +} + +std::string value_string(const AttrValueAssertion *ava) +{ + Bytes v = bytes_of(ava->element_IF_1); + uint8_t tag = uint8_t(ava->attr_encoding); + Bytes tlv = der::tlv(tag, v); + der::Node n; + der::try_parse_tlv(tlv.data(), tlv.size(), n); + if (tag == der::UTF8String || tag == der::BMPString) + return der::get_string(n); + return std::string(v.begin(), v.end()); +} + +std::string normalize(const std::string &s) +{ + std::string out; + bool space = false; + for (unsigned char c : trim(s)) { + if (c == ' ' || c == '\t') { + space = true; + continue; + } + if (space) + out += ' '; + space = false; + out += char(std::tolower(c)); + } + return out; +} + +struct ParsedAva { + Oid oid; + uint8_t tag; + Bytes value; +}; + +// Splits at unquoted/unescaped separators. +std::vector split(const std::string &s, const char *seps) +{ + std::vector out; + std::string cur; + bool quoted = false; + for (size_t i = 0; i < s.size(); ++i) { + char c = s[i]; + if (c == '\\' && i + 1 < s.size()) { + cur += c; + cur += s[++i]; + continue; + } + if (c == '"') + quoted = !quoted; + if (!quoted && std::strchr(seps, c)) { + out.push_back(cur); + cur.clear(); + continue; + } + cur += c; + } + out.push_back(cur); + return out; +} + +std::string unescape(const std::string &raw) +{ + std::string v = trim(raw); + if (v.size() >= 2 && v.front() == '"' && v.back() == '"') + v = v.substr(1, v.size() - 2); + std::string out; + for (size_t i = 0; i < v.size(); ++i) { + if (v[i] == '\\' && i + 1 < v.size()) + ++i; + out += v[i]; + } + return out; +} + +ParsedAva parse_ava(const std::string &text) +{ + size_t eq = text.find('='); + if (eq == std::string::npos) + fail(EWRONGNAME, "invalid name component '" + trim(text) + "'"); + std::string key = trim(text.substr(0, eq)); + std::string value = unescape(text.substr(eq + 1)); + ParsedAva a; + if (const AttrKeyword *k = keyword_by_name(key)) { + a.oid = k->oid; + a.tag = k->tag; + } else { + a.oid = parse_dotted(key); + if (a.oid.empty()) + fail(EWRONGNAME, "unknown attribute type '" + key + "'"); + a.tag = der::PrintableString; + } + if (a.tag == der::PrintableString && !printable(value)) + a.tag = der::UTF8String; + Bytes tlv = der::string(a.tag, value); + a.value = der::parse_one(tlv).value(); + return a; +} + +} // namespace + +DName *string_to_dname(const char *s) +{ + if (!s) + fail(EWRONGNAME, "missing name"); + std::vector> rdns; + for (const std::string &rdn : split(s, ",;")) { + if (trim(rdn).empty()) + continue; + std::vector avas; + for (const std::string &ava : split(rdn, "+")) + avas.push_back(parse_ava(ava)); + rdns.push_back(std::move(avas)); + } + if (rdns.empty()) + fail(EWRONGNAME, "empty name"); + std::reverse(rdns.begin(), rdns.end()); + DName *head = nullptr, **tail = &head; + for (const auto &avas : rdns) { + DName *d = mem_new(); + *tail = d; + tail = &d->next; + RDName **rtail = &d->element_IF_2; + for (const auto &a : avas) { + RDName *r = mem_new(); + *rtail = r; + rtail = &r->next; + r->member_IF_0 = mem_new(); + r->member_IF_0->element_IF_0 = new_objid(a.oid); + r->member_IF_0->element_IF_1 = new_ostr(a.value); + r->member_IF_0->attr_encoding = static_cast(a.tag); + } + } + return head; +} + +static std::string ava_to_string(const AttrValueAssertion *ava) +{ + Oid o = oid_of(ava->element_IF_0); + const AttrKeyword *k = keyword_by_oid(o); + std::string key = k ? k->keyword : oid_to_string(o); + std::string v = value_string(ava); + bool quote = v.find_first_of(",;+\"") != std::string::npos || (!v.empty() && (v.front() == ' ' || v.back() == ' ')); + if (quote) { + std::string q = "\""; + for (char c : v) { + if (c == '"' || c == '\\') + q += '\\'; + q += c; + } + v = q + "\""; + } + return key + "=" + v; +} + +std::string dname_to_string(const DName *d) +{ + std::vector rdns; + for (; d; d = d->next) { + std::string r; + for (const RDName *rd = d->element_IF_2; rd; rd = rd->next) { + if (!rd->member_IF_0) + continue; + if (!r.empty()) + r += " + "; + r += ava_to_string(rd->member_IF_0); + } + rdns.push_back(r); + } + std::string out; + for (auto it = rdns.rbegin(); it != rdns.rend(); ++it) { + if (!out.empty()) + out += ", "; + out += *it; + } + return out; +} + +bool dname_equal(const DName *a, const DName *b) +{ + for (; a && b; a = a->next, b = b->next) { + const RDName *x = a->element_IF_2, *y = b->element_IF_2; + for (; x && y; x = x->next, y = y->next) { + if (!x->member_IF_0 || !y->member_IF_0) + return false; + if (!oid_equal(x->member_IF_0->element_IF_0, y->member_IF_0->element_IF_0)) + return false; + if (normalize(value_string(x->member_IF_0)) != normalize(value_string(y->member_IF_0))) + return false; + } + if (x || y) + return false; + } + return !a && !b; +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +DName *aux_Name2DName(char *name) +{ + return guarded("aux_Name2DName", nullptr, [&] { return string_to_dname(name); }); +} + +char *aux_DName2Name(DName *name_ae) +{ + return guarded("aux_DName2Name", nullptr, [&]() -> char * { + if (!name_ae) + fail(ENONAME, "missing name"); + return mem_strdup(dname_to_string(name_ae)); + }); +} + +char *aux_DName2Attr(DName *dname, char *attr_key) +{ + return guarded("aux_DName2Attr", nullptr, [&]() -> char * { + if (!attr_key) + fail(EINVALID, "missing attribute keyword"); + Oid wanted; + if (const AttrKeyword *k = keyword_by_name(attr_key)) + wanted = k->oid; + else + wanted = parse_dotted(attr_key); + for (const DName *d = dname; d; d = d->next) + for (const RDName *r = d->element_IF_2; r; r = r->next) + if (r->member_IF_0 && oid_equal(r->member_IF_0->element_IF_0, wanted)) + return mem_strdup(value_string(r->member_IF_0)); + fail(ENONAME, std::string("attribute ") + attr_key + " not present"); + }); +} + +int aux_cmp_DName(DName *a, DName *b) +{ + return dname_equal(a, b) ? 0 : 1; +} + +} // extern "C" diff --git a/port/secude/src/dump.cpp b/port/secude/src/dump.cpp new file mode 100644 index 000000000..fb6465b02 --- /dev/null +++ b/port/secude/src/dump.cpp @@ -0,0 +1,298 @@ +// Text dumps: ASN.1 structure dump (sdumpasn) and hex dumps (aux_sxdump). +#include "der.hpp" + +#include +#include + +namespace compat { + +namespace { + +const char *tag_name(uint8_t tag) +{ + switch (tag & 0x1f) { + case 0x01: return "BOOLEAN"; + case 0x02: return "INTEGER"; + case 0x03: return "BIT STRING"; + case 0x04: return "OCTET STRING"; + case 0x05: return "NULL"; + case 0x06: return "OBJECT IDENTIFIER"; + case 0x0A: return "ENUMERATED"; + case 0x0C: return "UTF8String"; + case 0x10: return "SEQUENCE"; + case 0x11: return "SET"; + case 0x12: return "NumericString"; + case 0x13: return "PrintableString"; + case 0x14: return "T61String"; + case 0x16: return "IA5String"; + case 0x17: return "UTCTime"; + case 0x18: return "GeneralizedTime"; + case 0x1A: return "VisibleString"; + case 0x1E: return "BMPString"; + default: return nullptr; + } +} + +struct Ber { + uint8_t tag; + size_t hdr; + size_t len; + bool indefinite; +}; + +// Parses one BER header at p; returns false if malformed. +bool ber_header(const uint8_t *p, size_t n, Ber &b) +{ + if (n < 2 || (p[0] & 0x1f) == 0x1f) + return false; + b.tag = p[0]; + b.indefinite = false; + if (p[1] < 0x80) { + b.len = p[1]; + b.hdr = 2; + } else if (p[1] == 0x80) { + if (!(b.tag & 0x20)) + return false; + b.indefinite = true; + b.len = 0; + b.hdr = 2; + } else { + size_t k = p[1] & 0x7f; + if (k > 4 || n < 2 + k) + return false; + b.len = 0; + for (size_t i = 0; i < k; ++i) + b.len = (b.len << 8) | p[2 + i]; + b.hdr = 2 + k; + } + return b.indefinite || b.len <= n - b.hdr; +} + +class Dumper { +public: + Dumper(int options, int base) : options_(options), base_(base) {} + + // Dumps all elements in [p, p+n); returns consumed length or SIZE_MAX on error. + size_t elements(const uint8_t *p, size_t n, size_t offset, int depth, bool until_eoc) + { + size_t pos = 0; + while (pos < n) { + if (until_eoc && n - pos >= 2 && p[pos] == 0 && p[pos + 1] == 0) + return pos + 2; + size_t used = element(p + pos, n - pos, offset + pos, depth); + if (used == SIZE_MAX) + return SIZE_MAX; + pos += used; + } + return until_eoc ? SIZE_MAX : pos; + } + + size_t element(const uint8_t *p, size_t n, size_t offset, int depth) + { + Ber b; + if (!ber_header(p, n, b)) + return SIZE_MAX; + std::string indent(size_t(depth) * 2, ' '); + std::string head = str_printf("%6lu %4s: ", static_cast(offset + size_t(base_)), + b.indefinite ? "NDEF" : std::to_string(b.len).c_str()); + std::string name = describe_tag(b.tag); + const uint8_t *v = p + b.hdr; + if (b.tag & 0x20) { + out_ += head + indent + name + " {\n"; + size_t used = b.indefinite ? elements(v, n - b.hdr, offset + b.hdr, depth + 1, true) + : elements(v, b.len, offset + b.hdr, depth + 1, false); + if (used == SIZE_MAX) + return SIZE_MAX; + out_ += std::string(6 + 1 + 4 + 2, ' ') + indent + "}\n"; + return b.hdr + (b.indefinite ? used : b.len); + } + out_ += head + indent + name + primitive(b.tag, v, b.len, offset + b.hdr, depth); + return b.hdr + b.len; + } + + std::string text() const { return out_; } + std::string &text() { return out_; } + +private: + std::string describe_tag(uint8_t tag) const + { + uint8_t cls = tag & 0xc0; + if (cls == 0) { + const char *n = tag_name(tag); + return n ? n : str_printf("[UNIVERSAL %u]", tag & 0x1f); + } + if (cls == 0x80) + return str_printf("[%u]", tag & 0x1f); + return str_printf("[%s %u]", cls == 0x40 ? "APPLICATION" : "PRIVATE", tag & 0x1f); + } + + bool encapsulated(const uint8_t *v, size_t n) const + { + if (n < 2 || (v[0] != 0x30 && v[0] != 0x31)) + return false; + size_t pos = 0; + while (pos < n) { + Ber b; + if (!ber_header(v + pos, n - pos, b) || b.indefinite) + return false; + pos += b.hdr + b.len; + } + return pos == n; + } + + std::string hexlines(const uint8_t *v, size_t n, int depth) const + { + size_t limit = (options_ & ASN1dump_no_length_limit) ? n : std::min(n, 128); + std::string indent(size_t(6 + 1 + 4 + 2 + 2 * depth + 2), ' '); + std::string s = hexdump(v, limit, indent, false); + if (limit < n) + s += indent + str_printf("[ Another %lu bytes skipped ]\n", static_cast(n - limit)); + return s; + } + + std::string primitive(uint8_t tag, const uint8_t *v, size_t n, size_t offset, int depth) + { + if (tag & 0xc0) + return "\n" + hexlines(v, n, depth); + try { + Bytes tlv = der::tlv(tag, v, n); + der::Node node = der::parse_one(tlv); + switch (tag) { + case 0x01: + return std::string(" ") + (der::get_boolean(node) ? "TRUE" : "FALSE") + "\n"; + case 0x02: + case 0x0A: + if (n <= 4) + return " " + std::to_string(der::get_integer(node)) + "\n"; + return "\n" + hexlines(v, n, depth); + case 0x05: + return "\n"; + case 0x06: { + Oid o = der::get_oid(node); + const AlgInfo *a = alg_by_oid(o); + return " " + oid_to_string(o) + (a ? std::string(" (") + a->name + ")" : "") + "\n"; + } + case 0x03: + case 0x04: { + const uint8_t *data = tag == 0x03 ? v + 1 : v; + size_t len = tag == 0x03 ? (n ? n - 1 : 0) : n; + if (tag == 0x03 && (n == 0 || v[0] != 0)) + return "\n" + hexlines(v, n, depth); + if (encapsulated(data, len)) { + Dumper inner(options_, base_); + inner.elements(data, len, offset + (tag == 0x03 ? 1 : 0), depth + 1, false); + return ", encapsulates {\n" + inner.text() + std::string(6 + 1 + 4 + 2, ' ') + + std::string(size_t(depth) * 2, ' ') + "}\n"; + } + return "\n" + hexlines(v, n, depth); + } + case 0x17: + case 0x18: + return " " + format_time(der::get_time(node).c_str()) + "\n"; + default: + if (tag_name(tag)) + return " '" + der::get_string(node) + "'\n"; + return "\n" + hexlines(v, n, depth); + } + } catch (const Error &) { + return "\n" + hexlines(v, n, depth); + } + } + + int options_; + int base_; + std::string out_; +}; + +std::string dump_asn1(const uint8_t *p, size_t n, int options, int base) +{ + Dumper d(options, base); + if (n == 0) + return "FATAL: decoding failed! (empty input)\n"; + if (options & ASN1dump_multiple_PDU) { + if (d.elements(p, n, 0, 0, false) == SIZE_MAX) + d.text() += "FATAL: decoding failed!\n"; + return d.text(); + } + size_t used = d.element(p, n, 0, 0); + if (used == SIZE_MAX) { + d.text() += "FATAL: decoding failed!\n"; + return d.text(); + } + if (used < n) + d.text() += str_printf("junk at end of PDU (%lu octets)\n", static_cast(n - used)); + return d.text(); +} + +} // namespace + +std::string hexdump(const uint8_t *p, size_t n, const std::string &indent, bool ascii) +{ + std::string s; + for (size_t off = 0; off < n; off += 16) { + std::string line = indent + str_printf("%6lX ", static_cast(off)); + std::string text; + for (size_t i = 0; i < 16; ++i) { + if (i && i % 4 == 0) + line += ' '; + if (i == 8) + line += ' '; + if (off + i < n) { + uint8_t c = p[off + i]; + line += str_printf("%02X", c); + text += (c >= 0x20 && c < 0x7f) ? char(c) : '.'; + } else if (ascii) { + line += " "; + } + } + if (ascii) + line += " " + text; + while (!line.empty() && line.back() == ' ') + line.pop_back(); + s += line + "\n"; + } + return s; +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +char *sdumpasn(OctetString *ostr, int options, int displayed_offset) +{ + return guarded("sdumpasn", nullptr, [&] { + Bytes b = bytes_of(ostr); + return mem_strdup(dump_asn1(b.data(), b.size(), options, displayed_offset)); + }); +} + +void aux_adump(char *from, int num, int options, int displayed_offset) +{ + guarded_void("aux_adump", [&] { + if (!from || num < 0) + fail(EINVALID, "missing input"); + std::fputs(dump_asn1(reinterpret_cast(from), size_t(num), options, displayed_offset).c_str(), stdout); + }); +} + +char *aux_sxdump(char *string, char *buffer, sec_int4 len, sec_int4 addr_type) +{ + return guarded("aux_sxdump", nullptr, [&] { + if (!buffer && len > 0) + fail(EINVALID, "missing buffer"); + return append_string(string, hexdump(reinterpret_cast(buffer), len > 0 ? size_t(len) : 0, "", true)); + }); +} + +char *aux_sxdump2(char *string, char *buffer, sec_int4 len, sec_int4 addr_type) +{ + return guarded("aux_sxdump2", nullptr, [&] { + if (!buffer && len > 0) + fail(EINVALID, "missing buffer"); + return append_string(string, hexdump(reinterpret_cast(buffer), len > 0 ? size_t(len) : 0, "", false)); + }); +} + +} // extern "C" diff --git a/port/secude/src/encode.cpp b/port/secude/src/encode.cpp new file mode 100644 index 000000000..4bc9a43d7 --- /dev/null +++ b/port/secude/src/encode.cpp @@ -0,0 +1,861 @@ +// DER encoding/decoding of SECUDE structures (X.509, PKCS#1, PKCS#8, PKRoot, FCPath). +#include "der.hpp" + +#include + +namespace compat { + +namespace { + +ParmType parm_type(const ObjId *o) +{ + const AlgInfo *a = alg_by_oid(o); + return a ? a->parm : NoParmType; +} + +Bytes enc_ostr_value(const OctetString &o) +{ + return der::octet_string(bytes_of(&o)); +} + +Bytes enc_int_part(const OctetString &o) +{ + Bytes b = bytes_of(&o); + return der::integer_unsigned(b); +} + +void fill_part(OctetString &dst, const der::Node &n) +{ + fill_ostr(&dst, der::get_unsigned(n)); +} + +AlgId *dec_algid_node(const der::Node &node); +DName *dec_dname_node(const der::Node &node); +KeyInfo *dec_keyinfo_node(const der::Node &node); +CertExtensions *dec_extensions_node(const der::Node &node); + +} // namespace + +std::string utc_now(long offset_seconds) +{ + std::time_t t = std::time(nullptr) + offset_seconds; + std::tm tm{}; + gmtime_r(&t, &tm); + char buf[32]; + if (tm.tm_year + 1900 >= 2050) + std::strftime(buf, sizeof buf, "%Y%m%d%H%M%SZ", &tm); + else + std::strftime(buf, sizeof buf, "%y%m%d%H%M%SZ", &tm); + return buf; +} + +// ---- AlgorithmIdentifier ---------------------------------------------------- + +Bytes enc_algid(const AlgId *a) +{ + if (!a || !a->objid) + fail(EALGID, "missing algorithm identifier"); + Bytes body = der::oid(oid_of(a->objid)); + ParmType pt = parm_type(a->objid); + if (a->param) { + switch (pt) { + case PARM_INTEGER: + der::append(body, der::integer(*static_cast(a->param))); + break; + case PARM_OctetString: + der::append(body, der::octet_string(bytes_of(static_cast(a->param)))); + break; + case PARM_KeyBits: { + auto *k = static_cast(a->param); + der::append(body, der::seq({enc_int_part(k->part1), enc_int_part(k->part2), enc_int_part(k->part3)})); + break; + } + case PARM_RC2CBC: { + auto *p = static_cast(a->param); + der::append(body, der::seq({der::integer(p->version), enc_ostr_value(p->IV)})); + break; + } + case PARM_PKCS5: { + auto *p = static_cast(a->param); + der::append(body, der::seq({enc_ostr_value(p->salt), der::integer(p->iterationCount)})); + break; + } + case NoParmType: + der::append(body, bytes_of(static_cast(a->param))); + break; + case PARM_NULL: + der::append(body, der::null()); + break; + default: + break; + } + } else { + ParmType effective = a->parmoverride ? *a->parmoverride : pt; + if (effective == PARM_NULL) + der::append(body, der::null()); + } + return der::tlv(der::SEQUENCE, body); +} + +namespace { + +AlgId *dec_algid_node(const der::Node &node) +{ + if (node.tag != der::SEQUENCE) + fail(EDECODE, "AlgorithmIdentifier expected"); + der::Reader r(node); + Oid oid = der::get_oid(r.next()); + AlgId *a = mem_new(); + try { + a->objid = new_objid(oid); + ParmType pt = parm_type(a->objid); + if (r.empty()) { + if (pt == PARM_NULL) { + a->parmoverride = mem_new(); + *a->parmoverride = PARM_ABSENT; + } + return a; + } + der::Node p = r.next(); + r.expect_end(); + if (p.tag == der::NULL_ && pt != NoParmType) { + if (pt != PARM_NULL) { + a->parmoverride = mem_new(); + *a->parmoverride = PARM_NULL; + } + return a; + } + switch (pt) { + case PARM_INTEGER: { + unsigned int *v = mem_new(); + *v = static_cast(der::get_integer(p)); + a->param = v; + break; + } + case PARM_OctetString: + if (p.tag != der::OCTET_STRING) + fail(EDECODE, "OCTET STRING parameter expected"); + a->param = new_ostr(p.value()); + break; + case PARM_KeyBits: { + if (p.tag != der::SEQUENCE) + fail(EDECODE, "domain parameters expected"); + der::Reader pr(p); + KeyBits *k = mem_new(); + a->param = k; + fill_part(k->part1, pr.next(der::INTEGER)); + fill_part(k->part2, pr.next(der::INTEGER)); + fill_part(k->part3, pr.next(der::INTEGER)); + k->choice = 3; + break; + } + case PARM_RC2CBC: { + auto *rp = mem_new(); + a->param = rp; + if (p.tag == der::OCTET_STRING) { + rp->version = 58; + fill_ostr(&rp->IV, p.value()); + } else { + der::Reader pr(p); + der::Node n; + if (pr.next_optional(der::INTEGER, n)) + rp->version = int(der::get_integer(n)); + else + rp->version = 58; + fill_ostr(&rp->IV, pr.next(der::OCTET_STRING).value()); + } + break; + } + case PARM_PKCS5: { + auto *pp = mem_new(); + a->param = pp; + der::Reader pr(p); + fill_ostr(&pp->salt, pr.next(der::OCTET_STRING).value()); + pp->iterationCount = int(der::get_integer(pr.next(der::INTEGER))); + break; + } + case NoParmType: + a->param = new_ostr(p.raw()); + break; + default: + break; + } + return a; + } catch (...) { + free_algid(a); + throw; + } +} + +} // namespace + +AlgId *dec_algid(const Bytes &der_bytes) +{ + return dec_algid_node(der::parse_one(der_bytes)); +} + +// ---- KeyBits / KeyInfo ---------------------------------------------------------- + +Bytes enc_keybits(const KeyBits *k) +{ + if (!k) + fail(EINVALID, "missing KeyBits"); + const OctetString *parts[] = {&k->part1, &k->part2, &k->part3, &k->part4, &k->part5}; + int n = k->choice; + if (n < 1 || n > 5) { + n = 0; + while (n < 5 && parts[n]->noctets) + ++n; + } + if (n == 0) + fail(EINVALID, "empty KeyBits"); + Bytes body; + for (int i = 0; i < n; ++i) + der::append(body, enc_int_part(*parts[i])); + return der::tlv(der::SEQUENCE, body); +} + +KeyBits *dec_keybits(const Bytes &der_bytes) +{ + der::Node node = der::parse_one(der_bytes); + KeyBits *k = mem_new(); + try { + OctetString *parts[] = {&k->part1, &k->part2, &k->part3, &k->part4, &k->part5}; + if (node.tag == der::INTEGER) { + fill_part(k->part1, node); + k->choice = 1; + return k; + } + if (node.tag != der::SEQUENCE) + fail(EDECODE, "KeyBits expected"); + der::Reader r(node); + int n = 0; + while (!r.empty()) { + if (n == 5) + fail(EDECODE, "too many key components"); + fill_part(*parts[n++], r.next(der::INTEGER)); + } + k->choice = n; + return k; + } catch (...) { + free_keybits_content(k); + mem_free(k); + throw; + } +} + +Bytes enc_keyinfo(const KeyInfo *k) +{ + if (!k) + fail(EINVALID, "missing KeyInfo"); + return der::seq({enc_algid(k->subjectAI), + der::bit_string(reinterpret_cast(k->subjectkey.bits), k->subjectkey.nbits)}); +} + +namespace { + +KeyInfo *dec_keyinfo_node(const der::Node &node) +{ + if (node.tag != der::SEQUENCE) + fail(EDECODE, "SubjectPublicKeyInfo expected"); + der::Reader r(node); + KeyInfo *k = mem_new(); + try { + k->subjectAI = dec_algid_node(r.next(der::SEQUENCE)); + size_t nbits = 0; + Bytes bits = der::get_bit_string(r.next(), nbits); + fill_bstr(&k->subjectkey, bits, nbits); + r.expect_end(); + return k; + } catch (...) { + free_keyinfo(k); + throw; + } +} + +} // namespace + +KeyInfo *dec_keyinfo(const Bytes &der_bytes) +{ + return dec_keyinfo_node(der::parse_one(der_bytes)); +} + +// ---- Name ------------------------------------------------------------------- + +Bytes enc_dname(const DName *d) +{ + Bytes body; + for (; d; d = d->next) { + std::vector atvs; + for (const RDName *r = d->element_IF_2; r; r = r->next) { + const AttrValueAssertion *ava = r->member_IF_0; + if (!ava || !ava->element_IF_0) + continue; + int tag = ava->attr_encoding; + if (tag <= 0 || tag > 30) + tag = der::UTF8String; + Bytes value = bytes_of(ava->element_IF_1); + atvs.push_back(der::seq({der::oid(oid_of(ava->element_IF_0)), der::tlv(uint8_t(tag), value)})); + } + der::append(body, der::set_of(atvs)); + } + return der::tlv(der::SEQUENCE, body); +} + +namespace { + +DName *dec_dname_node(const der::Node &node) +{ + if (node.tag != der::SEQUENCE) + fail(EDECODE, "Name expected"); + DName *head = nullptr, **tail = &head; + try { + der::Reader r(node); + while (!r.empty()) { + der::Node set = r.next(der::SET); + DName *dn = mem_new(); + *tail = dn; + tail = &dn->next; + RDName **rtail = &dn->element_IF_2; + der::Reader sr(set); + while (!sr.empty()) { + der::Reader ar(sr.next(der::SEQUENCE)); + RDName *rd = mem_new(); + *rtail = rd; + rtail = &rd->next; + AttrValueAssertion *ava = mem_new(); + rd->member_IF_0 = ava; + ava->element_IF_0 = new_objid(der::get_oid(ar.next())); + der::Node v = ar.next(); + ava->element_IF_1 = new_ostr(v.value()); + ava->attr_encoding = static_cast(v.tag & 0x1f); + ar.expect_end(); + } + } + return head; + } catch (...) { + free_dname(head); + throw; + } +} + +} // namespace + +DName *dec_dname(const Bytes &der_bytes) +{ + return dec_dname_node(der::parse_one(der_bytes)); +} + +// ---- Validity, extensions, certificates -------------------------------------- + +Bytes enc_validity(const Validity *v) +{ + if (!v || !v->notbefore || !v->notafter) + fail(EINVALID, "missing validity"); + return der::seq({der::time(v->notbefore), der::time(v->notafter)}); +} + +static Bytes extension(const Oid &id, bool critical, const Bytes &value) +{ + Bytes body = der::oid(id); + if (critical) + der::append(body, der::boolean(true)); + der::append(body, der::octet_string(value)); + return der::tlv(der::SEQUENCE, body); +} + +Bytes enc_extensions(const CertExtensions *e) +{ + if (!e) + return {}; + Bytes body; + if (e->subjectKeyId && e->subjectKeyId->extnValue) + der::append(body, extension(oids::subjectKeyIdentifier, e->subjectKeyId->critical, + der::octet_string(bytes_of(e->subjectKeyId->extnValue)))); + if (e->authorityKeyId && e->authorityKeyId->extnValue && e->authorityKeyId->extnValue->authorityKeyIdentifier) + der::append(body, extension(oids::authorityKeyIdentifier, e->authorityKeyId->critical, + der::seq({der::tlv(der::ctx(0, false), bytes_of(e->authorityKeyId->extnValue->authorityKeyIdentifier))}))); + if (e->keyUsage && e->keyUsage->extnValue) { + const KeyUsage *ku = e->keyUsage->extnValue; + const Boolean flags[] = {ku->digitalSignature, ku->nonRepudiation, ku->keyEncipherment, ku->dataEncipherment, + ku->keyAgreement, ku->keyCertSign, ku->cRLSign, ku->encipherOnly, ku->decipherOnly}; + uint8_t bits[2] = {0, 0}; + size_t nbits = 0; + for (size_t i = 0; i < 9; ++i) + if (flags[i]) { + bits[i / 8] |= uint8_t(0x80 >> (i % 8)); + nbits = i + 1; + } + der::append(body, extension(oids::keyUsage, e->keyUsage->critical, der::bit_string(bits, nbits))); + } + if (e->basicConstraints && e->basicConstraints->extnValue) { + const BasicConstraints *bc = e->basicConstraints->extnValue; + Bytes v; + if (bc->cA) + der::append(v, der::boolean(true)); + if (bc->pathLenConstraint >= 0) + der::append(v, der::integer(bc->pathLenConstraint)); + der::append(body, extension(oids::basicConstraints, e->basicConstraints->critical, der::tlv(der::SEQUENCE, v))); + } + for (const SEQUENCE_OF_Extension *s = e->nonSupported; s; s = s->next) { + if (!s->element || !s->element->extnId) + continue; + der::append(body, extension(oid_of(s->element->extnId), s->element->critical, bytes_of(s->element->extnDERcode))); + } + if (body.empty()) + return {}; + return der::tlv(der::SEQUENCE, body); +} + +namespace { + +CertExtensions *dec_extensions_node(const der::Node &node) +{ + CertExtensions *e = mem_new(); + try { + der::Reader r(node); + SEQUENCE_OF_Extension **tail = &e->nonSupported; + int seq = 0; + while (!r.empty()) { + der::Reader xr(r.next(der::SEQUENCE)); + auto *n = mem_new(); + *tail = n; + tail = &n->next; + n->element = mem_new(); + n->element->extnId = new_objid(der::get_oid(xr.next())); + der::Node c; + if (xr.next_optional(der::BOOLEAN, c)) + n->element->critical = der::get_boolean(c); + n->element->extnDERcode = new_ostr(xr.next(der::OCTET_STRING).value()); + n->element->seqnum = seq++; + xr.expect_end(); + } + return e; + } catch (...) { + free_extensions(e); + throw; + } +} + +} // namespace + +CertExtensions *dec_extensions(const Bytes &der_bytes) +{ + der::Node n = der::parse_one(der_bytes); + if (n.tag != der::SEQUENCE) + fail(EDECODE, "Extensions expected"); + return dec_extensions_node(n); +} + +Bytes enc_tbs(const ToBeSigned *t) +{ + if (!t) + fail(EINVALID, "missing ToBeSigned"); + Bytes ext = enc_extensions(t->extensions); + int version = t->version; + if (!ext.empty() && version < 2) + version = 2; + Bytes body; + if (version > 0) + der::append(body, der::tlv(der::ctx(0), der::integer(version))); + Bytes serial = bytes_of(t->serialnumber); + if (serial.empty()) + serial.push_back(0); + der::append(body, der::integer_unsigned(serial)); + der::append(body, enc_algid(t->signatureAI)); + der::append(body, enc_dname(t->issuer)); + der::append(body, enc_validity(t->valid)); + der::append(body, enc_dname(t->subject)); + der::append(body, enc_keyinfo(t->subjectPK)); + if (t->issuerUId) { + Bytes bs = der::bit_string(reinterpret_cast(t->issuerUId->bits), t->issuerUId->nbits); + bs[0] = der::ctx(1, false); + der::append(body, bs); + } + if (t->subjectUId) { + Bytes bs = der::bit_string(reinterpret_cast(t->subjectUId->bits), t->subjectUId->nbits); + bs[0] = der::ctx(2, false); + der::append(body, bs); + } + if (!ext.empty()) + der::append(body, der::tlv(der::ctx(3), ext)); + return der::tlv(der::SEQUENCE, body); +} + +Bytes enc_signature_value(const Signature *s) +{ + if (!s) + fail(EINVALID, "missing signature"); + return der::bit_string(reinterpret_cast(s->signature.bits), s->signature.nbits); +} + +Bytes enc_certificate(const Certificate *c) +{ + if (!c || !c->sig) + fail(EINVALID, "incomplete certificate"); + Bytes tbs = c->tbs_DERcode && c->tbs_DERcode->noctets ? bytes_of(c->tbs_DERcode) : enc_tbs(c->tbs); + return der::seq({tbs, enc_algid(c->sig->signAI), enc_signature_value(c->sig)}); +} + +namespace { + +ToBeSigned *dec_tbs_node(const der::Node &node) +{ + if (node.tag != der::SEQUENCE) + fail(EDECODE, "TBSCertificate expected"); + ToBeSigned *t = mem_new(); + try { + der::Reader r(node); + der::Node n; + if (r.next_optional(der::ctx(0), n)) { + der::Reader vr(n); + t->version = int(der::get_integer(vr.next())); + } + t->serialnumber = new_ostr(der::get_unsigned(r.next(der::INTEGER))); + t->signatureAI = dec_algid_node(r.next(der::SEQUENCE)); + t->issuer = dec_dname_node(r.next(der::SEQUENCE)); + der::Reader vr(r.next(der::SEQUENCE)); + t->valid = mem_new(); + t->valid->notbefore = mem_strdup(der::get_time(vr.next())); + t->valid->notafter = mem_strdup(der::get_time(vr.next())); + t->subject = dec_dname_node(r.next(der::SEQUENCE)); + t->subjectPK = dec_keyinfo_node(r.next(der::SEQUENCE)); + while (!r.empty()) { + der::Node x = r.next(); + if (x.tag == der::ctx(1, false) || x.tag == der::ctx(2, false)) { + if (x.len == 0 || x.val[0] > 7) + fail(EDECODE, "invalid unique identifier"); + BitString *b = new_bstr(Bytes(x.val + 1, x.val + x.len), (x.len - 1) * 8 - x.val[0]); + (x.tag == der::ctx(1, false) ? t->issuerUId : t->subjectUId) = b; + } else if (x.tag == der::ctx(3)) { + der::Reader er(x); + t->extensions = dec_extensions_node(er.next(der::SEQUENCE)); + } else { + fail(EDECODE, "unexpected element in TBSCertificate"); + } + } + return t; + } catch (...) { + free_tbs(t); + throw; + } +} + +Certificate *dec_certificate_node(const der::Node &node) +{ + if (node.tag != der::SEQUENCE) + fail(EDECODE, "Certificate expected"); + Certificate *c = mem_new(); + try { + der::Reader r(node); + der::Node tbs = r.next(der::SEQUENCE); + c->tbs_DERcode = new_ostr(tbs.raw()); + c->tbs = dec_tbs_node(tbs); + c->sig = mem_new(); + c->sig->signAI = dec_algid_node(r.next(der::SEQUENCE)); + size_t nbits = 0; + Bytes bits = der::get_bit_string(r.next(), nbits); + fill_bstr(&c->sig->signature, bits, nbits); + r.expect_end(); + return c; + } catch (...) { + free_certificate(c); + throw; + } +} + +} // namespace + +Certificate *dec_certificate(const Bytes &der_bytes) +{ + return dec_certificate_node(der::parse_one(der_bytes)); +} + +// ---- PKRoot / FCPath (formats of this compatibility layer) -------------------- + +static Bytes enc_serial_key(const Serial *s) +{ + if (!s || !s->key) + fail(EINVALID, "incomplete PKRoot key"); + Bytes serial = bytes_of(s->serial); + if (serial.empty()) + serial.push_back(0); + Bytes body = der::concat({der::integer_unsigned(serial), der::integer(s->version), enc_keyinfo(s->key)}); + if (s->valid) + der::append(body, enc_validity(s->valid)); + if (s->sig) + der::append(body, der::tlv(der::ctx(1), der::seq({enc_algid(s->sig->signAI), enc_signature_value(s->sig)}))); + return der::tlv(der::SEQUENCE, body); +} + +static Serial *dec_serial_key(const der::Node &node) +{ + Serial *s = mem_new(); + try { + der::Reader r(node); + s->serial = new_ostr(der::get_unsigned(r.next(der::INTEGER))); + s->version = int(der::get_integer(r.next(der::INTEGER))); + s->key = dec_keyinfo_node(r.next(der::SEQUENCE)); + der::Node n; + if (r.next_optional(der::SEQUENCE, n)) { + der::Reader vr(n); + s->valid = mem_new(); + s->valid->notbefore = mem_strdup(der::get_time(vr.next())); + s->valid->notafter = mem_strdup(der::get_time(vr.next())); + } + if (r.next_optional(der::ctx(1), n)) { + der::Reader sr(der::Reader(n).next(der::SEQUENCE)); + s->sig = mem_new(); + s->sig->signAI = dec_algid_node(sr.next(der::SEQUENCE)); + size_t nbits = 0; + Bytes bits = der::get_bit_string(sr.next(), nbits); + fill_bstr(&s->sig->signature, bits, nbits); + } + r.expect_end(); + return s; + } catch (...) { + free_serial(s); + throw; + } +} + +Bytes enc_pkroot(const PKRoot *p) +{ + if (!p || !p->newkey) + fail(EINVALID, "incomplete PKRoot"); + Bytes body = der::concat({enc_dname(p->ca), enc_serial_key(p->newkey)}); + if (p->oldkey) + der::append(body, der::tlv(der::ctx(0), enc_serial_key(p->oldkey))); + Bytes ext = enc_extensions(p->extensions); + if (!ext.empty()) + der::append(body, der::tlv(der::ctx(3), ext)); + return der::tlv(der::SEQUENCE, body); +} + +PKRoot *dec_pkroot(const Bytes &der_bytes) +{ + der::Node node = der::parse_one(der_bytes); + if (node.tag != der::SEQUENCE) + fail(EDECODE, "PKRoot expected"); + PKRoot *p = mem_new(); + try { + der::Reader r(node); + p->ca = dec_dname_node(r.next(der::SEQUENCE)); + p->newkey = dec_serial_key(r.next(der::SEQUENCE)); + der::Node n; + if (r.next_optional(der::ctx(0), n)) + p->oldkey = dec_serial_key(der::Reader(n).next(der::SEQUENCE)); + if (r.next_optional(der::ctx(3), n)) + p->extensions = dec_extensions_node(der::Reader(n).next(der::SEQUENCE)); + r.expect_end(); + return p; + } catch (...) { + free_pkroot(p); + throw; + } +} + +Bytes enc_fcpath(const FCPath *f) +{ + Bytes body; + for (; f; f = f->next_forwardpath) { + std::vector certs; + for (const SET_OF_Certificate *s = f->liste; s; s = s->next) + if (s->element) + certs.push_back(enc_certificate(s->element)); + der::append(body, der::set_of(certs)); + } + return der::tlv(der::SEQUENCE, body); +} + +FCPath *dec_fcpath(const Bytes &der_bytes) +{ + der::Node node = der::parse_one(der_bytes); + if (node.tag != der::SEQUENCE) + fail(EDECODE, "FCPath expected"); + FCPath *head = nullptr, **tail = &head; + try { + der::Reader r(node); + while (!r.empty()) { + FCPath *f = mem_new(); + *tail = f; + tail = &f->next_forwardpath; + SET_OF_Certificate **ctail = &f->liste; + der::Reader sr(r.next(der::SET)); + while (!sr.empty()) { + auto *e = mem_new(); + *ctail = e; + ctail = &e->next; + e->element = dec_certificate_node(sr.next()); + } + } + return head; + } catch (...) { + free_fcpath(head); + throw; + } +} + +// ---- PKCS#8 ----------------------------------------------------------------- + +Bytes enc_privatekeyinfo(const PrivateKeyInfo *p) +{ + if (!p || !p->privateKeyAlgorithm || !p->privateKey) + fail(EINVALID, "incomplete PrivateKeyInfo"); + return der::seq({der::integer(p->version), enc_algid(p->privateKeyAlgorithm), der::octet_string(bytes_of(p->privateKey))}); +} + +PrivateKeyInfo *dec_privatekeyinfo(const Bytes &der_bytes) +{ + der::Node node = der::parse_one(der_bytes); + if (node.tag != der::SEQUENCE) + fail(EDECODE, "PrivateKeyInfo expected"); + PrivateKeyInfo *p = mem_new(); + try { + der::Reader r(node); + p->version = int(der::get_integer(r.next(der::INTEGER))); + p->privateKeyAlgorithm = dec_algid_node(r.next(der::SEQUENCE)); + p->privateKey = new_ostr(r.next(der::OCTET_STRING).value()); + return p; + } catch (...) { + free_privatekeyinfo(p); + throw; + } +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +OctetString *e_OctetString(OctetString *ostr) +{ + return guarded("e_OctetString", nullptr, [&]() -> OctetString * { + if (!ostr) + fail(EINVALID, "missing OctetString"); + return new_ostr(der::octet_string(bytes_of(ostr))); + }); +} + +OctetString *d_OctetString(OctetString *asn1_string) +{ + return guarded("d_OctetString", nullptr, [&]() -> OctetString * { + Bytes in = bytes_of(asn1_string); + der::Node n = der::parse_one(in); + if (n.tag != der::OCTET_STRING) + fail(EDECODE, "OCTET STRING expected"); + return new_ostr(n.value()); + }); +} + +OctetString *e_PrintableString(char *infostruct) +{ + return guarded("e_PrintableString", nullptr, [&]() -> OctetString * { + if (!infostruct) + fail(EINVALID, "missing string"); + return new_ostr(der::string(der::PrintableString, infostruct)); + }); +} + +char *d_PrintableString(OctetString *asn1string) +{ + return guarded("d_PrintableString", nullptr, [&] { + Bytes in = bytes_of(asn1string); + return mem_strdup(der::get_string(der::parse_one(in))); + }); +} + +OctetString *e_AlgId(AlgId *algid) +{ + return guarded("e_AlgId", nullptr, [&] { return new_ostr(enc_algid(algid)); }); +} + +BitString *e_KeyBits(KeyBits *kb) +{ + return guarded("e_KeyBits", nullptr, [&] { + Bytes b = enc_keybits(kb); + return new_bstr(b, b.size() * 8); + }); +} + +KeyBits *d_KeyBits(BitString *s) +{ + return guarded("d_KeyBits", nullptr, [&] { return dec_keybits(bytes_of(s)); }); +} + +OctetString *e_KeyInfo(KeyInfo *ki) +{ + return guarded("e_KeyInfo", nullptr, [&] { return new_ostr(enc_keyinfo(ki)); }); +} + +KeyInfo *d_KeyInfo(OctetString *asn1_string) +{ + return guarded("d_KeyInfo", nullptr, [&] { return dec_keyinfo(bytes_of(asn1_string)); }); +} + +OctetString *e_Certificate(Certificate *certificate) +{ + return guarded("e_Certificate", nullptr, [&] { return new_ostr(enc_certificate(certificate)); }); +} + +Certificate *d_Certificate(OctetString *asn1_string) +{ + return guarded("d_Certificate", nullptr, [&] { return dec_certificate(bytes_of(asn1_string)); }); +} + +OctetString *e_PKRoot(PKRoot *pkroot) +{ + return guarded("e_PKRoot", nullptr, [&] { return new_ostr(enc_pkroot(pkroot)); }); +} + +OctetString *e_FCPath(FCPath *fcpath) +{ + return guarded("e_FCPath", nullptr, [&] { return new_ostr(enc_fcpath(fcpath)); }); +} + +RSAPrivateKey *d_RSAPrivateKey(OctetString *asn1_string) +{ + return guarded("d_RSAPrivateKey", nullptr, [&] { + Bytes in = bytes_of(asn1_string); + der::Node node = der::parse_one(in); + if (node.tag != der::SEQUENCE) + fail(EDECODE, "RSAPrivateKey expected"); + RSAPrivateKey *k = mem_new(); + try { + der::Reader r(node); + k->version = int(der::get_integer(r.next(der::INTEGER))); + for (OctetString *o : {&k->modulus, &k->pubex, &k->privex, &k->prime1, &k->prime2, &k->exp1, &k->exp2, &k->coeff}) + fill_ostr(o, der::get_unsigned(r.next(der::INTEGER))); + return k; + } catch (...) { + aux_free_RSAPrivateKey(&k); + throw; + } + }); +} + +ContentInfo *d_ContentInfo(OctetString *asn1_string) +{ + return guarded("d_ContentInfo", nullptr, [&] { + Bytes in = bytes_of(asn1_string); + der::Node node = der::parse_one(in); + if (node.tag != der::SEQUENCE) + fail(EDECODE, "ContentInfo expected"); + der::Reader r(node); + Oid type = der::get_oid(r.next()); + OctetString *content = nullptr; + der::Node n; + if (r.next_optional(der::ctx(0), n)) { + der::Node inner = der::Reader(n).next(); + content = new_ostr(type == oids::data && inner.tag == der::OCTET_STRING ? inner.value() : inner.raw()); + } + r.expect_end(); + ContentInfo *ci = mem_new(); + ci->contentType = new_objid(type); + ci->content = content; + return ci; + }); +} + +} // extern "C" diff --git a/port/secude/src/error.cpp b/port/secude/src/error.cpp new file mode 100644 index 000000000..893f2c3cc --- /dev/null +++ b/port/secude/src/error.cpp @@ -0,0 +1,192 @@ +#include "internal.hpp" + +#include +#include + +namespace compat { + +namespace { + +struct Entry { + int number; + std::string text; + std::string proc; +}; + +constexpr size_t kMaxErrors = 32; + +std::deque &stack() +{ + thread_local std::deque s; + return s; +} + +struct NamedError { + int code; + const char *name; + const char *text; +}; + +const NamedError kErrors[] = { + {EALGID, "EALGID", "invalid algorithm identifier"}, + {EOBJ, "EOBJ", "PSE object not found"}, + {EKEYSIZE, "EKEYSIZE", "invalid key size"}, + {EVERIFY, "EVERIFY", "signature verification failed"}, + {ESYSTEM, "ESYSTEM", "system error"}, + {EMALLOC, "EMALLOC", "memory allocation failed"}, + {EENCODE, "EENCODE", "ASN.1 encoding failed"}, + {EDECODE, "EDECODE", "ASN.1 decoding failed"}, + {EREADPSE, "EREADPSE", "cannot read PSE"}, + {EWRITEPSE, "EWRITEPSE", "cannot write PSE"}, + {EROOTCERT, "EROOTCERT", "root certificate missing"}, + {ENODIR, "ENODIR", "no CA directory"}, + {EWRITEFILE, "EWRITEFILE", "cannot write file"}, + {EREADFILE, "EREADFILE", "cannot read file"}, + {EINVALID, "EINVALID", "invalid parameter"}, + {EFILENOTEXISTING, "EFILENOTEXISTING", "file does not exist"}, + {EWRONGPARM, "EWRONGPARM", "wrong parameter"}, + {EINTERNAL, "EINTERNAL", "internal error"}, + {ENOTSUPPORTED, "ENOTSUPPORTED", "function not supported"}, + {EUNKNOWNALGID, "EUNKNOWNALGID", "unknown algorithm"}, + {EALGNOTFITKEY, "EALGNOTFITKEY", "algorithm does not fit the key"}, + {EDECRYPTION, "EDECRYPTION", "decryption failed"}, + {EPIN, "EPIN", "wrong PIN"}, + {EPSEALREADYEXISTING, "EPSEALREADYEXISTING", "PSE already exists"}, + {EPSENOTEXISTING, "EPSENOTEXISTING", "PSE does not exist"}, + {EPSEOBJECTNOTEXISTING, "EPSEOBJECTNOTEXISTING", "PSE object does not exist"}, + {EPSEFILE, "EPSEFILE", "not a valid PSE file"}, + {EPSEFILESTRUCTURE, "EPSEFILESTRUCTURE", "invalid PSE file structure"}, + {ECADBCERT, "ECADBCERT", "certificate not found in CA database"}, + {ECADBUSER, "ECADBUSER", "user not found in CA database"}, + {ENOCRL, "ENOCRL", "no revocation list available"}, + {ENONAME, "ENONAME", "no name available"}, + {EVERIFICATION, "EVERIFICATION", "verification failed"}, + {ERANDOM, "ERANDOM", "random number generation failed"}, +}; + +} // namespace + +const char *error_name(int code) +{ + for (const auto &e : kErrors) + if (e.code == code) + return e.name; + return "ERROR"; +} + +static const char *error_text(int code) +{ + for (const auto &e : kErrors) + if (e.code == code) + return e.text; + return "error"; +} + +void fail(int code, const std::string &text) +{ + throw Error(code, text.empty() ? error_text(code) : text); +} + +void push_error(int code, const char *proc, const std::string &text) +{ + auto &s = stack(); + if (s.size() >= kMaxErrors) + s.pop_front(); + s.push_back(Entry{code, text.empty() ? error_text(code) : text, proc ? proc : ""}); +} + +std::string str_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + va_list ap2; + va_copy(ap2, ap); + int n = std::vsnprintf(nullptr, 0, fmt, ap); + va_end(ap); + std::string out; + if (n > 0) { + out.resize(size_t(n) + 1); + std::vsnprintf(&out[0], out.size(), fmt, ap2); + out.resize(size_t(n)); + } + va_end(ap2); + return out; +} + +char *append_string(char *string, const std::string &text) +{ + if (!string) + return mem_strdup(text); + size_t old = std::strlen(string); + char *r = static_cast(mem_realloc(string, old + text.size() + 1)); + std::memcpy(r + old, text.data(), text.size()); + r[old + text.size()] = 0; + return r; +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +int th_last_error(void) +{ + auto &s = stack(); + return s.empty() ? 0 : s.back().number; +} + +char *th_get_last_error_text(void) +{ + auto &s = stack(); + static char empty[1] = {0}; + return s.empty() ? empty : const_cast(s.back().text.c_str()); +} + +struct ErrStack *th_remove_last_error(void) +{ + return guarded("th_remove_last_error", nullptr, [] { + auto &s = stack(); + ErrStack *e = mem_new(); + e->e_is_error = TRUE; + e->e_addrtype = int_n; + if (!s.empty()) { + e->e_number = s.back().number; + e->e_text = mem_strdup(s.back().text); + e->e_proc = mem_strdup(s.back().proc); + s.pop_back(); + } + return e; + }); +} + +void global_add_error(int number, char *text, char *addr, Struct_No addrtype, char *proc) +{ + push_error(number, proc, text ? text : ""); +} + +void aux_free_error(void) +{ + stack().clear(); +} + +char *aux_sprint_error(PSE pse_handle, char *string, int verbose) +{ + return guarded("aux_sprint_error", nullptr, [&] { + auto &s = stack(); + std::string out; + if (s.empty()) + out = "no error\n"; + for (auto it = s.rbegin(); it != s.rend(); ++it) { + out += str_printf("%s (0x%04X): %s", error_name(it->number), unsigned(it->number), it->text.c_str()); + if (verbose && !it->proc.empty()) + out += " [" + it->proc + "]"; + out += "\n"; + if (!verbose) + break; + } + return append_string(string, out); + }); +} + +} // extern "C" diff --git a/port/secude/src/hash.cpp b/port/secude/src/hash.cpp new file mode 100644 index 000000000..626ecfc69 --- /dev/null +++ b/port/secude/src/hash.cpp @@ -0,0 +1,157 @@ +#include "legacy.hpp" + +namespace compat { + +namespace { + +const char *evp_name(Hash h) +{ + switch (h) { + case Hash::MD4: return "MD4"; + case Hash::MD5: return "MD5"; + case Hash::SHA1: return "SHA1"; + case Hash::RIPEMD160: return "RIPEMD160"; + case Hash::SHA256: return "SHA256"; + case Hash::SHA384: return "SHA384"; + case Hash::SHA512: return "SHA512"; + default: return nullptr; + } +} + +class Hasher { +public: + explicit Hasher(Hash h) + { + if (const char *name = evp_name(h)) { + if (EVP_MD *md = fetch_md(name)) { + evp_ = EVP_MD_CTX_new(); + bool ok = evp_ && EVP_DigestInit_ex2(evp_, md, nullptr); + EVP_MD_free(md); + if (!ok) + fail(EINTERNAL, "digest initialisation failed"); + return; + } + } + own_ = legacy::make_digest(h); + if (!own_) + fail(EUNKNOWNALGID, "hash algorithm not available"); + } + ~Hasher() { EVP_MD_CTX_free(evp_); } + Hasher(const Hasher &) = delete; + Hasher &operator=(const Hasher &) = delete; + + void update(const uint8_t *p, size_t n) + { + if (evp_) { + if (n && !EVP_DigestUpdate(evp_, p, n)) + fail(EINTERNAL, "digest update failed"); + } else if (n) { + own_->update(p, n); + } + } + + Bytes final() + { + if (!evp_) + return own_->final(); + Bytes out(EVP_MAX_MD_SIZE); + unsigned int len = 0; + if (!EVP_DigestFinal_ex(evp_, out.data(), &len)) + fail(EINTERNAL, "digest finalisation failed"); + out.resize(len); + return out; + } + +private: + EVP_MD_CTX *evp_ = nullptr; + std::unique_ptr own_; +}; + +Hash hash_of(const AlgId *aid) +{ + if (!aid || !aid->objid) + fail(EALGID, "missing hash algorithm"); + const AlgInfo *a = alg_by_oid(aid->objid); + if (!a || a->hash == Hash::None) + fail(EUNKNOWNALGID, "not a hash algorithm: " + oid_to_string(oid_of(aid->objid))); + return a->hash; +} + +} // namespace + +Bytes digest(Hash h, const uint8_t *p, size_t n) +{ + Hasher hs(h); + hs.update(p, n); + return hs.final(); +} + +size_t digest_size(Hash h) +{ + switch (h) { + case Hash::MD2: + case Hash::MD4: + case Hash::MD5: return 16; + case Hash::SHA0: + case Hash::SHA1: + case Hash::RIPEMD160: return 20; + case Hash::SHA256: return 32; + case Hash::SHA384: return 48; + case Hash::SHA512: return 64; + default: return 0; + } +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +RC sec_hash_init(void **context, AlgId *alg_id, HashInput *hash_input) +{ + return guarded("sec_hash_init", -1, [&] { + if (!context) + fail(EINVALID, "missing context"); + *context = new Hasher(hash_of(alg_id)); + return 0; + }); +} + +RC sec_hash_more(void **context, OctetString *in_octets) +{ + return guarded("sec_hash_more", -1, [&] { + if (!context || !*context) + fail(ECONTEXTINVALID, "hash context not initialised"); + if (in_octets && in_octets->noctets) + static_cast(*context)->update(reinterpret_cast(in_octets->octets), in_octets->noctets); + return 0; + }); +} + +RC sec_hash_end(void **context, OctetString *hash_result) +{ + return guarded("sec_hash_end", -1, [&] { + if (!context || !*context) + fail(ECONTEXTINVALID, "hash context not initialised"); + std::unique_ptr h(static_cast(*context)); + *context = nullptr; + Bytes d = h->final(); + if (hash_result) + fill_ostr(hash_result, d); + return 0; + }); +} + +RC sec_hash_all(OctetString *in_octets, OctetString *hash_result, AlgId *alg_id, HashInput *hash_input) +{ + return guarded("sec_hash_all", -1, [&] { + if (!in_octets || !hash_result) + fail(EINVALID, "missing parameter"); + Bytes d = digest(hash_of(alg_id), reinterpret_cast(in_octets->octets), in_octets->noctets); + fill_ostr(hash_result, d); + return 0; + }); +} + +} // extern "C" diff --git a/port/secude/src/internal.hpp b/port/secude/src/internal.hpp new file mode 100644 index 000000000..2444b7524 --- /dev/null +++ b/port/secude/src/internal.hpp @@ -0,0 +1,316 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// SECUDE's AlgEnc/AlgHash enumerators (RSA, DSA, SHA1, ...) clash with OpenSSL names, +// and secude/bio.h, secude/ssl.h re-declare OpenSSL's BIO/SSL API. The SSL +// part of SECUDE is not needed, so those headers are suppressed. +#ifndef HEADER_BIO_H +#define HEADER_BIO_H +#endif +#define HEADER_SSL_H +#define HEADER_SSL3_H +#define HEADER_SSL23_H +typedef SSL *H_SSL; +#define RSA SECUDE_ALG_RSA +#define DSA SECUDE_ALG_DSA +#define MD2 SECUDE_HASH_MD2 +#define MD4 SECUDE_HASH_MD4 +#define MD5 SECUDE_HASH_MD5 +#define SHA SECUDE_HASH_SHA +#define SHA1 SECUDE_HASH_SHA1 +#define RIPEMD160 SECUDE_HASH_RIPEMD160 +#include +#include +#include +#include +#undef RSA +#undef DSA +#undef MD2 +#undef MD4 +#undef MD5 +#undef SHA +#undef SHA1 +#undef RIPEMD160 + +// arithmet.h maps short names (div, add, comp, ...) to arithmetic_*; keep them out of C++ code. +#undef div +#undef madd +#undef msub +#undef mmult +#undef mdiv +#undef mexp +#undef mexp2 +#undef cadd +#undef add +#undef sub +#undef mult +#undef dmult +#undef shift +#undef wshift +#undef comp +#undef normalize +#undef trans + +#include "secude_compat.h" + +extern "C" { +// Used by CrypTool but not declared by the headers it includes. +OctetString *aux_alloc_OctetString(void); +extern AlgId md2WithRSASignature_aid; +} + +namespace compat { + +using Bytes = std::vector; + +// ---- memory ------------------------------------------------------------- +// Every block handed out to callers is registered; freeing an unknown +// pointer is ignored (CrypTool occasionally passes stack or foreign memory). +void *mem_alloc(size_t n); +void *mem_realloc(void *p, size_t n); +void mem_free(void *p); +bool mem_owned(const void *p); +char *mem_strdup(const char *s); +char *mem_strdup(const std::string &s); + +template T *mem_new() { return static_cast(mem_alloc(sizeof(T))); } + +OctetString *new_ostr(const uint8_t *data, size_t len); +inline OctetString *new_ostr(const Bytes &b) { return new_ostr(b.data(), b.size()); } +void fill_ostr(OctetString *o, const uint8_t *data, size_t len); +inline void fill_ostr(OctetString *o, const Bytes &b) { fill_ostr(o, b.data(), b.size()); } +BitString *new_bstr(const Bytes &b, size_t nbits); +void fill_bstr(BitString *o, const Bytes &b, size_t nbits); +Bytes bytes_of(const OctetString *o); +Bytes bytes_of(const BitString *b); +Bytes bytes_of(const char *s); + +// ---- errors --------------------------------------------------------------- +struct Error : std::runtime_error { + int code; + Error(int c, const std::string &msg) : std::runtime_error(msg), code(c) {} +}; +[[noreturn]] void fail(int code, const std::string &text = std::string()); +void push_error(int code, const char *proc, const std::string &text); +const char *error_name(int code); + +// Runs f() and converts exceptions into SECUDE errors (returned value: onfail). +template R guarded(const char *proc, R onfail, F &&f) +{ + try { + return f(); + } catch (const Error &e) { + push_error(e.code, proc, e.what()); + } catch (const std::bad_alloc &) { + push_error(EMALLOC, proc, "out of memory"); + } catch (const std::exception &e) { + push_error(EINVALID, proc, e.what()); + } + return onfail; +} + +template void guarded_void(const char *proc, F &&f) +{ + guarded(proc, -1, [&] { f(); return 0; }); +} + +// ---- OIDs and algorithms -------------------------------------------------- +using Oid = std::vector; +Oid oid_of(const ObjId *o); +ObjId *new_objid(const Oid &o); +void fill_objid(ObjId *dst, const Oid &o); +std::string oid_to_string(const Oid &o); +bool oid_equal(const ObjId *a, const ObjId *b); +bool oid_equal(const ObjId *a, const Oid &b); + +enum class Cipher { None, DES, DES3, IDEA, RC2, RC4, AES }; +enum class Pad { None, Std, Pkcs }; +enum class Hash { None, MD2, MD4, MD5, SHA0, SHA1, RIPEMD160, SHA256, SHA384, SHA512 }; + +struct AlgInfo { + const char *name; + Oid oid; + ParmType parm; + AlgType type; + AlgEnc enc; + Hash hash; + Cipher cipher; + AlgMode mode; + Pad pad; + AlgId *global; +}; + +const AlgInfo *alg_by_oid(const Oid &o); +const AlgInfo *alg_by_oid(const ObjId *o); +const AlgInfo *alg_by_name(const char *name); +std::string alg_display_name(const ObjId *o); +ObjId *pse_object_oid(const char *name); +const char *pse_object_name(const ObjId *oid); + +// Well-known OIDs (values are documented in README.md). +namespace oids { +extern const Oid rsa, rsaEncryption, dsa, id_dsa; +extern const Oid md2, md4, md5, sha, sha1, ripemd160, sha256, sha384, sha512; +extern const Oid data, encryptedData; +extern const Oid keyBag, pkcs8ShroudedKeyBag, certBag, x509Certificate; +extern const Oid friendlyName, localKeyId; +extern const Oid pbeSHA1RC4_128, pbeSHA1RC4_40, pbeSHA1DES3, pbeSHA1DES2, pbeSHA1RC2_128, pbeSHA1RC2_40; +extern const Oid pbes2, pbkdf2, hmacSHA1, hmacSHA256, hmacSHA384, hmacSHA512; +extern const Oid aes128CBC, aes192CBC, aes256CBC, desEDE3CBC; +extern const Oid subjectKeyIdentifier, keyUsage, basicConstraints, authorityKeyIdentifier; +extern const Oid cryptoolPseName; +} // namespace oids + +// ---- deep copy / free of SECUDE structures -------------------------------- +ObjId *copy_objid(const ObjId *o); +void free_objid_content(ObjId *o); +AlgId *copy_algid(const AlgId *a); +void free_algid_content(AlgId *a); +void free_algid(AlgId *a); +KeyBits *copy_keybits(const KeyBits *k); +void free_keybits_content(KeyBits *k); +KeyInfo *copy_keyinfo(const KeyInfo *k); +void free_keyinfo_content(KeyInfo *k); +void free_keyinfo(KeyInfo *k); +DName *copy_dname(const DName *d); +void free_dname(DName *d); +Validity *copy_validity(const Validity *v); +void free_validity(Validity *v); +Signature *copy_signature(const Signature *s); +void free_signature(Signature *s); +CertExtensions *copy_extensions(const CertExtensions *e); +void free_extensions(CertExtensions *e); +ToBeSigned *copy_tbs(const ToBeSigned *t); +void free_tbs(ToBeSigned *t); +Certificate *copy_certificate(const Certificate *c); +void free_certificate(Certificate *c); +FCPath *copy_fcpath(const FCPath *f); +void free_fcpath(FCPath *f); +PKRoot *copy_pkroot(const PKRoot *p); +void free_pkroot(PKRoot *p); +void free_serial(Serial *s); +void free_privatekeyinfo(PrivateKeyInfo *p); + +// ---- DER encoding of SECUDE structures (encode.cpp) ----------------------- +Bytes enc_algid(const AlgId *a); +AlgId *dec_algid(const Bytes &der); +Bytes enc_keybits(const KeyBits *k); +KeyBits *dec_keybits(const Bytes &der); +Bytes enc_keyinfo(const KeyInfo *k); +KeyInfo *dec_keyinfo(const Bytes &der); +Bytes enc_dname(const DName *d); +DName *dec_dname(const Bytes &der); +Bytes enc_validity(const Validity *v); +Bytes enc_extensions(const CertExtensions *e); +CertExtensions *dec_extensions(const Bytes &der); +Bytes enc_tbs(const ToBeSigned *t); +Bytes enc_signature_value(const Signature *s); +Bytes enc_certificate(const Certificate *c); +Certificate *dec_certificate(const Bytes &der); +Bytes enc_pkroot(const PKRoot *p); +PKRoot *dec_pkroot(const Bytes &der); +Bytes enc_fcpath(const FCPath *f); +FCPath *dec_fcpath(const Bytes &der); +Bytes enc_privatekeyinfo(const PrivateKeyInfo *p); +PrivateKeyInfo *dec_privatekeyinfo(const Bytes &der); +Bytes enc_unsigned_integer(const uint8_t *p, size_t n); +Bytes strip_leading_zeros(const uint8_t *p, size_t n); +std::string utc_now(long offset_seconds = 0); + +// ---- names ------------------------------------------------------------------ +std::string dname_to_string(const DName *d); +DName *string_to_dname(const char *s); +bool dname_equal(const DName *a, const DName *b); + +// ---- digests (hash.cpp) ---------------------------------------------------- +Bytes digest(Hash h, const uint8_t *p, size_t n); +size_t digest_size(Hash h); + +// ---- asymmetric (asym.cpp) ------------------------------------------------ +struct RsaPublic { Bytes n, e; }; +struct RsaPrivate { Bytes n, e, d, p, q; }; +struct DsaParams { Bytes p, q, g; }; + +bool keyinfo_is_rsa(const KeyInfo *k); +bool keyinfo_is_dsa(const KeyInfo *k); +RsaPublic rsa_public_from_keyinfo(const KeyInfo *k); +RsaPrivate rsa_private_from_keyinfo(const KeyInfo *k, const Bytes &e_hint); +int rsa_bits(const Bytes &n); + +void rsa_generate(int bits, KeyInfo **pub, KeyInfo **priv); +void dsa_generate(int bits, KeyInfo **pub, KeyInfo **priv); +Bytes rsa_encrypt_blocks(const RsaPublic &k, const uint8_t *p, size_t n); +Bytes rsa_decrypt_blocks(const RsaPrivate &k, const uint8_t *p, size_t n); +Bytes rsa_raw_private(const RsaPrivate &k, const Bytes &m); +Bytes rsa_private_key_der(const RsaPrivate &k); + +// Sign/verify the message (hashing included) with the signature algorithm sig_alg. +Bytes sign_message(const KeyInfo *priv, const Bytes &e_hint, const AlgId *sig_alg, const uint8_t *msg, size_t n); +bool verify_message(const KeyInfo *pub, const AlgId *sig_alg, const uint8_t *msg, size_t n, const Bytes &sig); + +// ---- symmetric (symcipher.cpp) ---------------------------------------------- +Bytes sym_encrypt(const AlgId *alg, const Bytes &key, size_t keybits, const uint8_t *in, size_t n); +Bytes sym_decrypt(const AlgId *alg, const Bytes &key, size_t keybits, const uint8_t *in, size_t n); + +// ---- providers (provider.cpp) --------------------------------------------- +OSSL_LIB_CTX *libctx(); +bool legacy_enabled(); +EVP_MD *fetch_md(const char *name); // nullptr if unavailable +EVP_CIPHER *fetch_cipher(const char *name); // nullptr if unavailable (or legacy disabled) + +// ---- PSE internals (pse.cpp) ---------------------------------------------- +struct PseStore; +struct PseObject { + std::string name; + Oid type; + std::string created, updated; + Bytes value; +}; + +std::shared_ptr store_of(PSE pse); +std::shared_ptr store_of(PSESel *sel); +const PseObject *store_find(const std::shared_ptr &s, const std::string &name); +void store_put(const std::shared_ptr &s, const std::string &name, const Oid &type, const Bytes &value); +bool store_onekeypaironly(const std::shared_ptr &s); +const char *pse_cadir(PSE pse); +std::string private_key_object(PSE pse, KeyType type); +std::string certificate_object(PSE pse, KeyType type); +KeyInfo *read_private_key(PSE pse, KeyType type); +Bytes rsa_exponent_hint(PSE pse, const KeyInfo *priv); +Certificate *make_ca_certificate(PSE pse, const KeyInfo *pub, const AlgId *sig_alg, const DName *subject, + long validity_seconds); + +// ---- print flags (data_flags.cpp) ----------------------------------------- +uint32_t print_cert_flags(); +uint32_t print_keyinfo_flags(); +void *print_cert_flag_address(); +void *print_keyinfo_flag_address(); + +// ---- misc ------------------------------------------------------------------- +Bytes random_bytes(size_t n); +// CrypTool passes Windows style paths ("C:\\dir\\file"); off Windows every path +// used for file access goes through this: '\\' becomes '/', a drive prefix is dropped. +std::string native_path(const std::string &path); +Bytes read_file(const std::string &path, bool &exists); +void write_file_atomic(const std::string &path, const Bytes &data, int mode = 0600); +std::string hex(const uint8_t *p, size_t n, bool upper = true); +std::string hexdump(const uint8_t *p, size_t n, const std::string &indent, bool ascii); +std::string format_time(const char *t); +std::string str_printf(const char *fmt, ...); +char *append_string(char *string, const std::string &text); + +} // namespace compat diff --git a/port/secude/src/keystore.cpp b/port/secude/src/keystore.cpp new file mode 100644 index 000000000..bcb36334c --- /dev/null +++ b/port/secude/src/keystore.cpp @@ -0,0 +1,266 @@ +// Creation of the CrypTool key store (CA PSE, CA database, sample keys). +#include +#include + +#include "bn.hpp" +#include "der.hpp" + +#include +#include + +namespace compat { + +namespace { + +constexpr long kDay = 24L * 3600; + +std::string join(const std::string &dir, const std::string &name) +{ + if (dir.empty() || dir.back() == '/') + return dir + name; + return dir + "/" + name; +} + +void make_dirs(const std::string &path) +{ + std::string cur; + for (size_t i = 0; i <= path.size(); ++i) { + if (i == path.size() || path[i] == '/') { + if (!cur.empty() && ::mkdir(cur.c_str(), 0755) != 0 && errno != EEXIST) + fail(EWRITEFILE, "cannot create directory " + cur + ": " + std::strerror(errno)); + } + if (i < path.size()) + cur += path[i]; + } +} + +bool exists(const std::string &path) +{ + struct stat st; + return ::stat(path.c_str(), &st) == 0; +} + +// Raises the most recent SECUDE error as exception (for chaining API calls). +[[noreturn]] void rethrow(const char *what) +{ + int code = th_last_error(); + std::string text = th_get_last_error_text(); + fail(code ? code : EINTERNAL, std::string(what) + ": " + text); +} + +struct PseGuard { + PSE pse; + explicit PseGuard(PSE p) : pse(p) {} + ~PseGuard() + { + if (pse) + af_close(pse); + } + PseGuard(const PseGuard &) = delete; + PseGuard &operator=(const PseGuard &) = delete; +}; + +void create_ca(const std::string &pse_path, const std::string &ca_dir, const char *pin, const char *name, int bits, + int days) +{ + make_dirs(ca_dir); + std::remove(join(ca_dir, "cadb.der").c_str()); + std::remove(pse_path.c_str()); + PseGuard ca(af_create(const_cast(pse_path.c_str()), const_cast(ca_dir.c_str()), + const_cast(pin), nullptr, TRUE)); + if (!ca.pse) + rethrow("af_create"); + Key key{}; + key.alg = &rsa_aid; + key.key_size = bits; + if (af_gen_key(ca.pse, &key, SIGNATURE, TRUE) != 0) + rethrow("af_gen_key"); + DName *dn = string_to_dname(name); + Certificate *cert = nullptr; + try { + cert = make_ca_certificate(ca.pse, key.key, &sha1WithRsaEncryption_aid, dn, long(days) * kDay); + } catch (...) { + free_dname(dn); + free_keyinfo(key.key); + throw; + } + free_dname(dn); + free_keyinfo(key.key); + PKRoot *root = aux_create_PKRoot(cert, nullptr); + Bytes one{1}; + OctetString serial{1, reinterpret_cast(one.data())}; + bool ok = root && af_pse_update(ca.pse, const_cast(Cert_name), cert, Cert_OID) == 0 && + af_pse_update_PKRoot(ca.pse, root) == 0 && af_pse_update_SerialNumber(ca.pse, &serial) == 0 && + af_cadb_add_Certificate(ca.pse, SIGNATURE, cert) == 0; + free_pkroot(root); + free_certificate(cert); + if (!ok) + rethrow("CA initialisation"); +} + +// Mirrors CDlgKeyAsymGeneration::CreateAsymKeys for an RSA key. +void create_rsa_user(const std::string &pse_dir, const std::string &ca_pse, const std::string &ca_dir, + const std::string &name, const std::string &first_name, int bits, const std::string &time, + const std::string &info, const char *pin) +{ + std::string key_id = "[" + name + "][" + first_name + "][RSA-" + std::to_string(bits) + "][" + time + "][" + info + "]"; + std::string path = join(pse_dir, key_id + ".pse"); + std::remove(path.c_str()); + PseGuard user(af_create(const_cast(path.c_str()), nullptr, const_cast(pin), nullptr, TRUE)); + if (!user.pse) + rethrow("af_create"); + Key key{}; + key.alg = &rsa_aid; + key.key_size = bits; + if (af_gen_key(user.pse, &key, SIGNATURE, TRUE) != 0) + rethrow("af_gen_key"); + std::string dn_text = "CN=" + first_name + " " + name + " [" + time + "], DC=cryptool, DC=org"; + DName *dn = string_to_dname(dn_text.c_str()); + char serial_text[] = "000001"; + OctetString proto_serial{6, serial_text}; + Certificate *proto = af_create_Certificate(user.pse, key.key, &sha1WithRSASignature_aid, const_cast(SKnew_name), + dn, &proto_serial, nullptr, nullptr, TRUE, nullptr); + free_dname(dn); + free_keyinfo(key.key); + if (!proto) + rethrow("af_create_Certificate"); + + OctetString *ext_value = e_PrintableString(const_cast(key_id.c_str())); + v3Extension ext{}; + ObjId ext_oid{}; + fill_objid(&ext_oid, oids::cryptoolPseName); + ext.extnId = &ext_oid; + ext.extnDERcode = ext_value; + SEQUENCE_OF_Extension list{&ext, nullptr}; + CertExtensions cert_ext{}; + cert_ext.nonSupported = &list; + CertExtensions *own_ext = proto->tbs->extensions; + proto->tbs->extensions = &cert_ext; + + PseGuard ca(af_open(const_cast(ca_pse.c_str()), const_cast(ca_dir.c_str()), + const_cast(SECUDE_COMPAT_CA_PIN), nullptr)); + Certificate *cert = nullptr; + if (ca.pse) { + OctetString *serial = sec_random_ostr(8, 1); + if (serial && af_pse_update_SerialNumber(ca.pse, serial) == 0) { + Validity v{}; + std::string from = utc_now(), to = utc_now(7305 * kDay); + v.notbefore = const_cast(from.c_str()); + v.notafter = const_cast(to.c_str()); + cert = af_certify(ca.pse, proto, &v, &sha1WithRSASignature_aid, nullptr); + } + aux_free_OctetString(&serial); + } + proto->tbs->extensions = own_ext; + free_certificate(proto); + aux_free_OctetString(&ext_value); + free_objid_content(&ext_oid); + if (!cert) + rethrow("af_certify"); + PKRoot *root = af_pse_get_PKRoot(ca.pse); + bool ok = root && af_cadb_add_Certificate(ca.pse, SIGNATURE, cert) == 0 && af_pse_update_PKRoot(user.pse, root) == 0 && + af_pse_update(user.pse, const_cast(Cert_name), cert, Cert_OID) == 0; + free_pkroot(root); + free_certificate(cert); + if (!ok) + rethrow("registering the certificate"); +} + +std::string hex_number(const BIGNUM *b) +{ + Bytes v = bn_bytes(b); + std::string h = hex(v.data(), v.size()); + size_t nz = h.find_first_not_of('0'); + return "0X" + (nz == std::string::npos ? std::string("0") : h.substr(nz)); +} + +// Mirrors CKeyFile::CreateEcKeyFiles: public data as text file, private key in a PSE. +void create_ec_user(const std::string &pse_dir, const std::string &key_id, const char *curve, int nid, const char *pin) +{ + EC_GROUP *group = EC_GROUP_new_by_curve_name_ex(libctx(), nullptr, nid); + if (!group) + fail(EINTERNAL, std::string("curve ") + curve + " not available"); + Bn p = bn_new(), a = bn_new(), b = bn_new(), gx = bn_new(), gy = bn_new(), order = bn_new(), cofactor = bn_new(); + Bn d = bn_new(), qx = bn_new(), qy = bn_new(); + EC_POINT *q = EC_POINT_new(group); + bool ok = q && EC_GROUP_get_curve(group, p.get(), a.get(), b.get(), bn_ctx()) && + EC_POINT_get_affine_coordinates(group, EC_GROUP_get0_generator(group), gx.get(), gy.get(), bn_ctx()) && + EC_GROUP_get_order(group, order.get(), bn_ctx()) && EC_GROUP_get_cofactor(group, cofactor.get(), bn_ctx()); + while (ok) { + ok = BN_priv_rand_range(d.get(), order.get()); + if (ok && !BN_is_zero(d.get())) + break; + } + ok = ok && EC_POINT_mul(group, q, d.get(), nullptr, nullptr, bn_ctx()) && + EC_POINT_get_affine_coordinates(group, q, qx.get(), qy.get(), bn_ctx()); + EC_POINT_free(q); + EC_GROUP_free(group); + if (!ok) + fail(EINTERNAL, "EC key generation failed"); + + std::string text; + for (const BIGNUM *v : {a.get(), b.get(), p.get(), gx.get(), gy.get(), cofactor.get(), order.get(), qx.get(), qy.get()}) + text += hex_number(v) + "\n"; + std::string pub_path = join(pse_dir, key_id); + write_file_atomic(pub_path, Bytes(text.begin(), text.end()), 0644); + + std::string pse_path = pub_path + ".pse"; + std::remove(pse_path.c_str()); + PseGuard pse(af_create(const_cast(pse_path.c_str()), nullptr, const_cast(pin), nullptr, FALSE)); + if (!pse.pse) + rethrow("af_create"); + Bytes priv = bn_bytes(d.get()); + OctetString raw{sec_uint4(priv.size()), reinterpret_cast(priv.data())}; + OctetString *encoded = e_OctetString(&raw); + int rc = encoded ? af_pse_update(pse.pse, const_cast("EcPrivKey"), encoded, Uid_OID) : -1; + aux_free_OctetString(&encoded); + if (rc != 0) + rethrow("af_pse_update"); +} + +} // namespace + +} // namespace compat + +using namespace compat; + +extern "C" { + +int secude_compat_create_ca(const char *ca_pse_path, const char *ca_dir, const char *pin, const char *ca_name, + int key_bits, int validity_days) +{ + return guarded("secude_compat_create_ca", -1, [&] { + if (!ca_pse_path || !ca_dir) + fail(EINVALID, "missing path"); + create_ca(native_path(ca_pse_path), native_path(ca_dir), pin ? pin : SECUDE_COMPAT_CA_PIN, ca_name ? ca_name : SECUDE_COMPAT_CA_NAME, + key_bits > 0 ? key_bits : 2048, validity_days > 0 ? validity_days : 7305); + return 0; + }); +} + +int secude_compat_create_sample_keystore(const char *key_store_root, int overwrite) +{ + return guarded("secude_compat_create_sample_keystore", -1, [&] { + if (!key_store_root) + fail(EINVALID, "missing key store directory"); + std::string pse_dir = join(native_path(key_store_root), "PSE"); + std::string ca_dir = join(pse_dir, "PSECA"); + std::string ca_pse = join(ca_dir, "capse.cse"); + make_dirs(ca_dir); + + bool new_ca = overwrite || !exists(ca_pse); + if (new_ca) + create_ca(ca_pse, ca_dir, SECUDE_COMPAT_CA_PIN, SECUDE_COMPAT_CA_NAME, 2048, 7305); + + const char *rsa_id = "[SideChannelAttack][Bob][RSA-512][1152179494][PIN=1234]"; + if (new_ca || !exists(join(pse_dir, std::string(rsa_id) + ".pse"))) + create_rsa_user(pse_dir, ca_pse, ca_dir, "SideChannelAttack", "Bob", 512, "1152179494", "PIN=1234", "1234"); + + const char *ec_id = "[HybridEncryption][Bob][EC-prime239v1][1178702474][PIN=1234]"; + if (overwrite || !exists(join(pse_dir, std::string(ec_id) + ".pse")) || !exists(join(pse_dir, ec_id))) + create_ec_user(pse_dir, ec_id, "prime239v1", NID_X9_62_prime239v1, "1234"); + return 0; + }); +} + +} // extern "C" diff --git a/port/secude/src/legacy.hpp b/port/secude/src/legacy.hpp new file mode 100644 index 000000000..db47c0b8e --- /dev/null +++ b/port/secude/src/legacy.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "internal.hpp" + +// Built-in implementations of algorithms that OpenSSL 3 lacks (MD2, SHA-0) or +// only offers through the optional legacy provider. +namespace compat { +namespace legacy { + +class Digest { +public: + virtual ~Digest() = default; + virtual void update(const uint8_t *p, size_t n) = 0; + virtual Bytes final() = 0; +}; + +// MD2, MD4, MD5, SHA0, SHA1, RIPEMD160; nullptr for other algorithms. +std::unique_ptr make_digest(Hash h); + +class BlockCipher { +public: + virtual ~BlockCipher() = default; + virtual size_t block_size() const = 0; + virtual void encrypt(const uint8_t *in, uint8_t *out) const = 0; + virtual void decrypt(const uint8_t *in, uint8_t *out) const = 0; +}; + +std::unique_ptr make_des(const uint8_t key[8]); +std::unique_ptr make_des3(const uint8_t *key, size_t keylen); // 16 or 24 bytes +std::unique_ptr make_idea(const uint8_t key[16]); +std::unique_ptr make_rc2(const uint8_t *key, size_t keylen, unsigned effective_bits); + +void rc4(const uint8_t *key, size_t keylen, const uint8_t *in, uint8_t *out, size_t n); + +} // namespace legacy +} // namespace compat diff --git a/port/secude/src/legacy_cipher.cpp b/port/secude/src/legacy_cipher.cpp new file mode 100644 index 000000000..19c933f5d --- /dev/null +++ b/port/secude/src/legacy_cipher.cpp @@ -0,0 +1,395 @@ +// DES/3DES (FIPS 46-3), IDEA, RC2 (RFC 2268) and RC4. +#include "legacy.hpp" + +#include + +namespace compat { +namespace legacy { + +namespace { + +// ---- DES ---------------------------------------------------------------------------- + +const uint8_t kIP[64] = {58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7}; +const uint8_t kFP[64] = {40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25}; +const uint8_t kE[48] = {32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, + 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, + 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1}; +const uint8_t kP[32] = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25}; +const uint8_t kPC1[56] = {57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, + 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, + 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4}; +const uint8_t kPC2[48] = {14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, + 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, + 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32}; +const uint8_t kShifts[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}; +const uint8_t kS[8][64] = { + {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, + 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, + 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}, + {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, + 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, + 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}, + {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, + 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, + 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}, + {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, + 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, + 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}, + {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, + 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, + 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}, + {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, + 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, + 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}, + {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, + 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, + 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, + {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, + 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, + 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}, +}; + +uint64_t permute(uint64_t in, const uint8_t *table, int n, int inbits) +{ + uint64_t out = 0; + for (int i = 0; i < n; ++i) + out = (out << 1) | ((in >> (inbits - table[i])) & 1); + return out; +} + +struct SpTables { + uint32_t sp[8][64]; + SpTables() + { + for (int box = 0; box < 8; ++box) + for (int six = 0; six < 64; ++six) { + int row = ((six >> 4) & 2) | (six & 1); + int col = (six >> 1) & 0xf; + uint64_t s = uint64_t(kS[box][row * 16 + col]) << (28 - 4 * box); + sp[box][six] = uint32_t(permute(s, kP, 32, 32)); + } + } +}; + +const SpTables &sp_tables() +{ + static const SpTables t; + return t; +} + +uint64_t load64(const uint8_t *p) +{ + uint64_t v = 0; + for (int i = 0; i < 8; ++i) + v = (v << 8) | p[i]; + return v; +} + +void store64(uint8_t *p, uint64_t v) +{ + for (int i = 7; i >= 0; --i) { + p[i] = uint8_t(v); + v >>= 8; + } +} + +class DesKey { +public: + explicit DesKey(const uint8_t key[8]) + { + uint64_t cd = permute(load64(key), kPC1, 56, 64); + uint32_t c = uint32_t(cd >> 28) & 0x0fffffff, d = uint32_t(cd) & 0x0fffffff; + for (int i = 0; i < 16; ++i) { + for (int s = 0; s < kShifts[i]; ++s) { + c = ((c << 1) | (c >> 27)) & 0x0fffffff; + d = ((d << 1) | (d >> 27)) & 0x0fffffff; + } + sub_[i] = permute((uint64_t(c) << 28) | d, kPC2, 48, 56); + } + } + + uint64_t crypt(uint64_t block, bool decrypt) const + { + const SpTables &t = sp_tables(); + uint64_t ip = permute(block, kIP, 64, 64); + uint32_t l = uint32_t(ip >> 32), r = uint32_t(ip); + for (int i = 0; i < 16; ++i) { + uint64_t e = permute(r, kE, 48, 32) ^ sub_[decrypt ? 15 - i : i]; + uint32_t f = 0; + for (int box = 0; box < 8; ++box) + f |= t.sp[box][(e >> (42 - 6 * box)) & 0x3f]; + uint32_t nl = r; + r = l ^ f; + l = nl; + } + return permute((uint64_t(r) << 32) | l, kFP, 64, 64); + } + +private: + uint64_t sub_[16]; +}; + +class Des : public BlockCipher { +public: + explicit Des(const uint8_t key[8]) : k_(key) {} + size_t block_size() const override { return 8; } + void encrypt(const uint8_t *in, uint8_t *out) const override { store64(out, k_.crypt(load64(in), false)); } + void decrypt(const uint8_t *in, uint8_t *out) const override { store64(out, k_.crypt(load64(in), true)); } + +private: + DesKey k_; +}; + +class Des3 : public BlockCipher { +public: + Des3(const uint8_t *key, size_t keylen) : k1_(key), k2_(key + 8), k3_(keylen >= 24 ? key + 16 : key) {} + size_t block_size() const override { return 8; } + void encrypt(const uint8_t *in, uint8_t *out) const override + { + store64(out, k3_.crypt(k2_.crypt(k1_.crypt(load64(in), false), true), false)); + } + void decrypt(const uint8_t *in, uint8_t *out) const override + { + store64(out, k1_.crypt(k2_.crypt(k3_.crypt(load64(in), true), false), true)); + } + +private: + DesKey k1_, k2_, k3_; +}; + +// ---- IDEA --------------------------------------------------------------------------- + +uint16_t idea_mul(uint32_t a, uint32_t b) +{ + if (!a) + a = 0x10000; + if (!b) + b = 0x10000; + uint32_t p = uint32_t((uint64_t(a) * b) % 0x10001); + return uint16_t(p & 0xffff); +} + +uint16_t idea_inv(uint16_t x) +{ + if (x <= 1) + return x; + // Fermat: x^(p-2) mod p for the prime p = 65537 + uint64_t result = 1, base = x, e = 0x10001 - 2; + while (e) { + if (e & 1) + result = (result * base) % 0x10001; + base = (base * base) % 0x10001; + e >>= 1; + } + return uint16_t(result); +} + +class Idea : public BlockCipher { +public: + explicit Idea(const uint8_t key[16]) + { + uint16_t k[8]; + for (int i = 0; i < 8; ++i) + k[i] = uint16_t((key[2 * i] << 8) | key[2 * i + 1]); + for (int i = 0; i < 52; ++i) { + if (i && i % 8 == 0) { + uint16_t r[8]; + for (int j = 0; j < 8; ++j) + r[j] = uint16_t((k[(j + 1) % 8] << 9) | (k[(j + 2) % 8] >> 7)); + std::memcpy(k, r, sizeof k); + } + ek_[i] = k[i % 8]; + } + dk_[0] = idea_inv(ek_[48]); + dk_[1] = uint16_t(-ek_[49]); + dk_[2] = uint16_t(-ek_[50]); + dk_[3] = idea_inv(ek_[51]); + for (int r = 1; r < 8; ++r) { + int e = 48 - 6 * r; + dk_[6 * r - 2] = ek_[e + 4]; + dk_[6 * r - 1] = ek_[e + 5]; + dk_[6 * r] = idea_inv(ek_[e]); + dk_[6 * r + 1] = uint16_t(-ek_[e + 2]); + dk_[6 * r + 2] = uint16_t(-ek_[e + 1]); + dk_[6 * r + 3] = idea_inv(ek_[e + 3]); + } + dk_[46] = ek_[4]; + dk_[47] = ek_[5]; + dk_[48] = idea_inv(ek_[0]); + dk_[49] = uint16_t(-ek_[1]); + dk_[50] = uint16_t(-ek_[2]); + dk_[51] = idea_inv(ek_[3]); + } + size_t block_size() const override { return 8; } + void encrypt(const uint8_t *in, uint8_t *out) const override { crypt(ek_, in, out); } + void decrypt(const uint8_t *in, uint8_t *out) const override { crypt(dk_, in, out); } + +private: + static void crypt(const uint16_t *k, const uint8_t *in, uint8_t *out) + { + uint16_t x1 = uint16_t((in[0] << 8) | in[1]), x2 = uint16_t((in[2] << 8) | in[3]); + uint16_t x3 = uint16_t((in[4] << 8) | in[5]), x4 = uint16_t((in[6] << 8) | in[7]); + for (int r = 0; r < 8; ++r, k += 6) { + x1 = idea_mul(x1, k[0]); + x2 = uint16_t(x2 + k[1]); + x3 = uint16_t(x3 + k[2]); + x4 = idea_mul(x4, k[3]); + uint16_t t0 = idea_mul(uint16_t(x1 ^ x3), k[4]); + uint16_t t1 = idea_mul(uint16_t(t0 + (x2 ^ x4)), k[5]); + t0 = uint16_t(t0 + t1); + x1 ^= t1; + x4 ^= t0; + uint16_t t = uint16_t(x2 ^ t0); + x2 = uint16_t(x3 ^ t1); + x3 = t; + } + uint16_t y1 = idea_mul(x1, k[0]), y2 = uint16_t(x3 + k[1]), y3 = uint16_t(x2 + k[2]), y4 = idea_mul(x4, k[3]); + const uint16_t y[4] = {y1, y2, y3, y4}; + for (int i = 0; i < 4; ++i) { + out[2 * i] = uint8_t(y[i] >> 8); + out[2 * i + 1] = uint8_t(y[i]); + } + } + + uint16_t ek_[52]; + uint16_t dk_[52]; +}; + +// ---- RC2 ---------------------------------------------------------------------------- + +const uint8_t kPiTable[256] = { + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, + 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, + 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, + 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, + 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, + 0x26, 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, + 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde, 0x80, + 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, + 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, + 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, + 0x97, 0x31, 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, 0xd3, + 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b, + 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, + 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad, +}; + +class Rc2 : public BlockCipher { +public: + Rc2(const uint8_t *key, size_t keylen, unsigned bits) + { + uint8_t l[128] = {0}; + size_t t = std::min(keylen, 128); + std::memcpy(l, key, t); + for (size_t i = t; i < 128; ++i) + l[i] = kPiTable[uint8_t(l[i - 1] + l[i - t])]; + if (bits == 0 || bits > 1024) + bits = 1024; + size_t t8 = (bits + 7) / 8; + uint8_t tm = uint8_t(0xff >> (8 * t8 - bits)); + l[128 - t8] = kPiTable[l[128 - t8] & tm]; + for (size_t i = 128 - t8; i-- > 0;) + l[i] = kPiTable[l[i + 1] ^ l[i + t8]]; + for (int i = 0; i < 64; ++i) + k_[i] = uint16_t(l[2 * i] | (l[2 * i + 1] << 8)); + } + size_t block_size() const override { return 8; } + + void encrypt(const uint8_t *in, uint8_t *out) const override + { + uint16_t r[4]; + load(in, r); + int j = 0; + for (int round = 0; round < 16; ++round) { + for (int i = 0; i < 4; ++i) { + r[i] = uint16_t(r[i] + k_[j++] + (r[(i + 3) % 4] & r[(i + 2) % 4]) + (~r[(i + 3) % 4] & r[(i + 1) % 4])); + r[i] = rol16(r[i], kRot[i]); + } + if (round == 4 || round == 10) + for (int i = 0; i < 4; ++i) + r[i] = uint16_t(r[i] + k_[r[(i + 3) % 4] & 63]); + } + store(out, r); + } + + void decrypt(const uint8_t *in, uint8_t *out) const override + { + uint16_t r[4]; + load(in, r); + int j = 63; + for (int round = 15; round >= 0; --round) { + for (int i = 3; i >= 0; --i) { + r[i] = ror16(r[i], kRot[i]); + r[i] = uint16_t(r[i] - k_[j--] - (r[(i + 3) % 4] & r[(i + 2) % 4]) - (~r[(i + 3) % 4] & r[(i + 1) % 4])); + } + if (round == 5 || round == 11) + for (int i = 3; i >= 0; --i) + r[i] = uint16_t(r[i] - k_[r[(i + 3) % 4] & 63]); + } + store(out, r); + } + +private: + static constexpr int kRot[4] = {1, 2, 3, 5}; + static uint16_t rol16(uint16_t x, int n) { return uint16_t((x << n) | (x >> (16 - n))); } + static uint16_t ror16(uint16_t x, int n) { return uint16_t((x >> n) | (x << (16 - n))); } + static void load(const uint8_t *in, uint16_t r[4]) + { + for (int i = 0; i < 4; ++i) + r[i] = uint16_t(in[2 * i] | (in[2 * i + 1] << 8)); + } + static void store(uint8_t *out, const uint16_t r[4]) + { + for (int i = 0; i < 4; ++i) { + out[2 * i] = uint8_t(r[i]); + out[2 * i + 1] = uint8_t(r[i] >> 8); + } + } + uint16_t k_[64]; +}; + +} // namespace + +std::unique_ptr make_des(const uint8_t key[8]) { return std::make_unique(key); } + +std::unique_ptr make_des3(const uint8_t *key, size_t keylen) +{ + return std::make_unique(key, keylen); +} + +std::unique_ptr make_idea(const uint8_t key[16]) { return std::make_unique(key); } + +std::unique_ptr make_rc2(const uint8_t *key, size_t keylen, unsigned effective_bits) +{ + return std::make_unique(key, keylen, effective_bits); +} + +void rc4(const uint8_t *key, size_t keylen, const uint8_t *in, uint8_t *out, size_t n) +{ + uint8_t s[256]; + for (int i = 0; i < 256; ++i) + s[i] = uint8_t(i); + uint8_t j = 0; + for (int i = 0; i < 256; ++i) { + j = uint8_t(j + s[i] + key[size_t(i) % keylen]); + std::swap(s[i], s[j]); + } + uint8_t x = 0, y = 0; + for (size_t k = 0; k < n; ++k) { + x = uint8_t(x + 1); + y = uint8_t(y + s[x]); + std::swap(s[x], s[y]); + out[k] = in[k] ^ s[uint8_t(s[x] + s[y])]; + } +} + +} // namespace legacy +} // namespace compat diff --git a/port/secude/src/legacy_hash.cpp b/port/secude/src/legacy_hash.cpp new file mode 100644 index 000000000..bd60fcce0 --- /dev/null +++ b/port/secude/src/legacy_hash.cpp @@ -0,0 +1,540 @@ +// MD2 (RFC 1319), MD4 (RFC 1320), MD5 (RFC 1321), SHA-0/SHA-1 (FIPS 180/180-1) +// and RIPEMD-160, operating on the SECUDE context structures. +#include "legacy.hpp" + +#include + +namespace compat { +namespace legacy { + +namespace { + +inline uint32_t rol(uint32_t x, int n) { return (x << n) | (x >> (32 - n)); } + +inline uint32_t load_le(const uint8_t *p) +{ + return uint32_t(p[0]) | (uint32_t(p[1]) << 8) | (uint32_t(p[2]) << 16) | (uint32_t(p[3]) << 24); +} + +inline uint32_t load_be(const uint8_t *p) +{ + return (uint32_t(p[0]) << 24) | (uint32_t(p[1]) << 16) | (uint32_t(p[2]) << 8) | uint32_t(p[3]); +} + +inline void store_le(uint8_t *p, uint32_t v) +{ + for (int i = 0; i < 4; ++i) + p[i] = uint8_t(v >> (8 * i)); +} + +inline void store_be(uint8_t *p, uint32_t v) +{ + for (int i = 0; i < 4; ++i) + p[i] = uint8_t(v >> (24 - 8 * i)); +} + +// ---- MD2 ---------------------------------------------------------------------- + +const uint8_t kPiSubst[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, + 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, + 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, + 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, + 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, + 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, + 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, + 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, + 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, + 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, + 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20, +}; + +void md2_transform(SEC_MD2_CTX *c, const uint8_t *block) +{ + uint8_t x[48]; + for (int i = 0; i < 16; ++i) { + x[i] = c->state[i]; + x[i + 16] = block[i]; + x[i + 32] = uint8_t(c->state[i] ^ block[i]); + } + unsigned t = 0; + for (unsigned round = 0; round < 18; ++round) { + for (int k = 0; k < 48; ++k) + t = x[k] ^= kPiSubst[t]; + t = (t + round) & 0xff; + } + for (int i = 0; i < 16; ++i) + c->state[i] = x[i]; + t = c->checksum[15]; + for (int i = 0; i < 16; ++i) + t = c->checksum[i] ^= kPiSubst[block[i] ^ t]; +} + +// ---- MD4 / MD5 ------------------------------------------------------------------ + +#define MD_F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define MD4_G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define MD5_G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define MD_H(x, y, z) ((x) ^ (y) ^ (z)) +#define MD5_I(x, y, z) ((y) ^ ((x) | ~(z))) + +void md4_transform(uint32_t state[4], const uint8_t *block) +{ + uint32_t x[16]; + for (int i = 0; i < 16; ++i) + x[i] = load_le(block + 4 * i); + uint32_t a = state[0], b = state[1], c = state[2], d = state[3]; + static const int r1[4] = {3, 7, 11, 19}, r2[4] = {3, 5, 9, 13}, r3[4] = {3, 9, 11, 15}; + for (int i = 0; i < 16; ++i) { + uint32_t t = rol(a + MD_F(b, c, d) + x[i], r1[i % 4]); + a = d; d = c; c = b; b = t; + } + static const int o2[16] = {0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}; + for (int i = 0; i < 16; ++i) { + uint32_t t = rol(a + MD4_G(b, c, d) + x[o2[i]] + 0x5a827999u, r2[i % 4]); + a = d; d = c; c = b; b = t; + } + static const int o3[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; + for (int i = 0; i < 16; ++i) { + uint32_t t = rol(a + MD_H(b, c, d) + x[o3[i]] + 0x6ed9eba1u, r3[i % 4]); + a = d; d = c; c = b; b = t; + } + state[0] += a; state[1] += b; state[2] += c; state[3] += d; +} + +void md5_transform(uint32_t state[4], const uint8_t *block) +{ + static const uint32_t K[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, + }; + static const int S[64] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + uint32_t x[16]; + for (int i = 0; i < 16; ++i) + x[i] = load_le(block + 4 * i); + uint32_t a = state[0], b = state[1], c = state[2], d = state[3]; + for (int i = 0; i < 64; ++i) { + uint32_t f; + int g; + if (i < 16) { + f = MD_F(b, c, d); + g = i; + } else if (i < 32) { + f = MD5_G(b, c, d); + g = (5 * i + 1) % 16; + } else if (i < 48) { + f = MD_H(b, c, d); + g = (3 * i + 5) % 16; + } else { + f = MD5_I(b, c, d); + g = (7 * i) % 16; + } + uint32_t t = d; + d = c; + c = b; + b = b + rol(a + f + K[i] + x[g], S[i]); + a = t; + } + state[0] += a; state[1] += b; state[2] += c; state[3] += d; +} + +// Shared Merkle-Damgard bookkeeping of the RFC 1320/1321 contexts. +template +void md_update(Ctx *c, const uint8_t *p, size_t n) +{ + if (n == 0) + return; + size_t index = (c->count[0] >> 3) & 0x3f; + uint64_t bits = (uint64_t(c->count[1]) << 32 | c->count[0]) + (uint64_t(n) << 3); + c->count[0] = uint32_t(bits); + c->count[1] = uint32_t(bits >> 32); + size_t part = 64 - index; + size_t i = 0; + if (n >= part) { + std::memcpy(c->buffer + index, p, part); + Transform(c->state, c->buffer); + for (i = part; i + 63 < n; i += 64) + Transform(c->state, p + i); + index = 0; + } + std::memcpy(c->buffer + index, p + i, n - i); +} + +template +void md_final(uint8_t digest[16], Ctx *c) +{ + uint8_t bits[8]; + store_le(bits, c->count[0]); + store_le(bits + 4, c->count[1]); + size_t index = (c->count[0] >> 3) & 0x3f; + size_t padlen = index < 56 ? 56 - index : 120 - index; + static const uint8_t pad[64] = {0x80}; + md_update(c, pad, padlen); + md_update(c, bits, 8); + for (int i = 0; i < 4; ++i) + store_le(digest + 4 * i, c->state[i]); + std::memset(c, 0, sizeof *c); +} + +template void md_init(Ctx *c) +{ + std::memset(c, 0, sizeof *c); + c->state[0] = 0x67452301; + c->state[1] = 0xefcdab89; + c->state[2] = 0x98badcfe; + c->state[3] = 0x10325476; +} + +// ---- SHA-0 / SHA-1 on SHS_INFO (countLo/countHi count bits) --------------------- + +void shs_transform(SHS_INFO *s, const uint8_t *block, bool sha1) +{ + uint32_t w[80]; + for (int i = 0; i < 16; ++i) + w[i] = load_be(block + 4 * i); + for (int i = 16; i < 80; ++i) { + uint32_t t = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; + w[i] = sha1 ? rol(t, 1) : t; + } + uint32_t a = s->digest[0], b = s->digest[1], c = s->digest[2], d = s->digest[3], e = s->digest[4]; + for (int i = 0; i < 80; ++i) { + uint32_t f, k; + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5a827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ed9eba1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8f1bbcdc; + } else { + f = b ^ c ^ d; + k = 0xca62c1d6; + } + uint32_t t = rol(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + s->digest[0] += a; s->digest[1] += b; s->digest[2] += c; s->digest[3] += d; s->digest[4] += e; +} + +void shs_init(SHS_INFO *s) +{ + std::memset(s, 0, sizeof *s); + s->digest[0] = 0x67452301; + s->digest[1] = 0xefcdab89; + s->digest[2] = 0x98badcfe; + s->digest[3] = 0x10325476; + s->digest[4] = 0xc3d2e1f0; +} + +void shs_update(SHS_INFO *s, const uint8_t *p, size_t n, bool sha1) +{ + uint8_t *buf = reinterpret_cast(s->data); + size_t index = (s->countLo >> 3) & 0x3f; + uint64_t bits = (uint64_t(s->countHi) << 32 | s->countLo) + (uint64_t(n) << 3); + s->countLo = uint32_t(bits); + s->countHi = uint32_t(bits >> 32); + while (n) { + size_t take = std::min(n, size_t(64) - index); + std::memcpy(buf + index, p, take); + index += take; + p += take; + n -= take; + if (index == 64) { + uint8_t block[64]; + std::memcpy(block, buf, 64); + shs_transform(s, block, sha1); + index = 0; + } + } +} + +void shs_final(SHS_INFO *s, bool sha1) +{ + uint8_t len[8]; + store_be(len, s->countHi); + store_be(len + 4, s->countLo); + size_t index = (s->countLo >> 3) & 0x3f; + size_t padlen = index < 56 ? 56 - index : 120 - index; + static const uint8_t pad[64] = {0x80}; + shs_update(s, pad, padlen, sha1); + shs_update(s, len, 8, sha1); +} + +// ---- RIPEMD-160 ------------------------------------------------------------------- + +struct Rmd160 { + uint32_t h[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + uint8_t buf[64]; + size_t used = 0; + uint64_t total = 0; + + static uint32_t f(int j, uint32_t x, uint32_t y, uint32_t z) + { + switch (j / 16) { + case 0: return x ^ y ^ z; + case 1: return (x & y) | (~x & z); + case 2: return (x | ~y) ^ z; + case 3: return (x & z) | (y & ~z); + default: return x ^ (y | ~z); + } + } + + void transform(const uint8_t *block) + { + static const int r[80] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, + 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, + 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, + 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13}; + static const int rp[80] = {5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, + 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, + 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, + 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11}; + static const int s[80] = {11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, + 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, + 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, + 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6}; + static const int sp[80] = {8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, + 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, + 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, + 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11}; + static const uint32_t K[5] = {0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e}; + static const uint32_t KP[5] = {0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000}; + uint32_t x[16]; + for (int i = 0; i < 16; ++i) + x[i] = load_le(block + 4 * i); + uint32_t al = h[0], bl = h[1], cl = h[2], dl = h[3], el = h[4]; + uint32_t ar = al, br = bl, cr = cl, dr = dl, er = el; + for (int j = 0; j < 80; ++j) { + uint32_t t = rol(al + f(j, bl, cl, dl) + x[r[j]] + K[j / 16], s[j]) + el; + al = el; el = dl; dl = rol(cl, 10); cl = bl; bl = t; + t = rol(ar + f(79 - j, br, cr, dr) + x[rp[j]] + KP[j / 16], sp[j]) + er; + ar = er; er = dr; dr = rol(cr, 10); cr = br; br = t; + } + uint32_t t = h[1] + cl + dr; + h[1] = h[2] + dl + er; + h[2] = h[3] + el + ar; + h[3] = h[4] + al + br; + h[4] = h[0] + bl + cr; + h[0] = t; + } + + void update(const uint8_t *p, size_t n) + { + total += n; + while (n) { + size_t take = std::min(n, sizeof buf - used); + std::memcpy(buf + used, p, take); + used += take; + p += take; + n -= take; + if (used == 64) { + transform(buf); + used = 0; + } + } + } + + Bytes final() + { + uint64_t bits = total * 8; + uint8_t pad = 0x80; + update(&pad, 1); + uint8_t zero = 0; + while (used != 56) + update(&zero, 1); + uint8_t len[8]; + store_le(len, uint32_t(bits)); + store_le(len + 4, uint32_t(bits >> 32)); + update(len, 8); + Bytes out(20); + for (int i = 0; i < 5; ++i) + store_le(out.data() + 4 * i, h[i]); + return out; + } +}; + +// ---- Digest adapters ------------------------------------------------------------- + +class Md2Digest : public Digest { + SEC_MD2_CTX c; +public: + Md2Digest() { sec_MD2Init(&c); } + void update(const uint8_t *p, size_t n) override { sec_MD2Update(&c, const_cast(p), sec_uint4(n)); } + Bytes final() override + { + Bytes d(16); + sec_MD2Final(d.data(), &c); + return d; + } +}; + +class Md4Digest : public Digest { + SEC_MD4_CTX c; +public: + Md4Digest() { md_init(&c); } + void update(const uint8_t *p, size_t n) override { md_update(&c, p, n); } + Bytes final() override + { + Bytes d(16); + md_final(d.data(), &c); + return d; + } +}; + +class Md5Digest : public Digest { + SEC_MD5_CTX c; +public: + Md5Digest() { md_init(&c); } + void update(const uint8_t *p, size_t n) override { md_update(&c, p, n); } + Bytes final() override + { + Bytes d(16); + md_final(d.data(), &c); + return d; + } +}; + +class ShsDigest : public Digest { + SHS_INFO s; + bool sha1; +public: + explicit ShsDigest(bool is_sha1) : sha1(is_sha1) { shs_init(&s); } + void update(const uint8_t *p, size_t n) override { shs_update(&s, p, n, sha1); } + Bytes final() override + { + shs_final(&s, sha1); + Bytes d(20); + for (int i = 0; i < 5; ++i) + store_be(d.data() + 4 * i, s.digest[i]); + return d; + } +}; + +class RmdDigest : public Digest { + Rmd160 r; +public: + void update(const uint8_t *p, size_t n) override { r.update(p, n); } + Bytes final() override { return r.final(); } +}; + +} // namespace + +std::unique_ptr make_digest(Hash h) +{ + switch (h) { + case Hash::MD2: return std::make_unique(); + case Hash::MD4: return std::make_unique(); + case Hash::MD5: return std::make_unique(); + case Hash::SHA0: return std::make_unique(false); + case Hash::SHA1: return std::make_unique(true); + case Hash::RIPEMD160: return std::make_unique(); + default: return nullptr; + } +} + +} // namespace legacy +} // namespace compat + +using namespace compat::legacy; + +extern "C" { + +void sec_MD2Init(SEC_MD2_CTX *context) +{ + std::memset(context, 0, sizeof *context); +} + +void sec_MD2Update(SEC_MD2_CTX *context, unsigned char *input, sec_uint4 inputLen) +{ + if (inputLen == 0) + return; + unsigned index = context->count; + context->count = (index + inputLen) & 0xf; + unsigned part = 16 - index; + unsigned i = 0; + if (inputLen >= part) { + std::memcpy(context->buffer + index, input, part); + md2_transform(context, context->buffer); + for (i = part; i + 15 < inputLen; i += 16) + md2_transform(context, input + i); + index = 0; + } + std::memcpy(context->buffer + index, input + i, inputLen - i); +} + +void sec_MD2Final(unsigned char *digest, SEC_MD2_CTX *context) +{ + unsigned char padding[16]; + unsigned padlen = 16 - context->count; + std::memset(padding, int(padlen), padlen); + sec_MD2Update(context, padding, padlen); + unsigned char checksum[16]; + std::memcpy(checksum, context->checksum, 16); + sec_MD2Update(context, checksum, 16); + std::memcpy(digest, context->state, 16); + std::memset(context, 0, sizeof *context); +} + +void sec_MD4Init(SEC_MD4_CTX *context) { md_init(context); } + +void sec_MD4Update(SEC_MD4_CTX *context, unsigned char *input, sec_uint4 inputLen) +{ + md_update(context, input, inputLen); +} + +void sec_MD4Final(unsigned char *digest, SEC_MD4_CTX *context) +{ + md_final(digest, context); +} + +void sec_MD5Init(SEC_MD5_CTX *context) { md_init(context); } + +void sec_MD5Update(SEC_MD5_CTX *context, unsigned char *input, sec_uint4 inputLen) +{ + md_update(context, input, inputLen); +} + +void sec_MD5Final(unsigned char *digest, SEC_MD5_CTX *context) +{ + md_final(digest, context); +} + +// After shsFinal()/shs1Final() the message digest is in shsInfo->digest[0..4] +// as host-order words (big-endian when serialised). +void shsInit(SHS_INFO *shsInfo) { shs_init(shsInfo); } + +void shsUpdate(SHS_INFO *shsInfo, unsigned char *buffer, sec_int4 count) +{ + if (count > 0) + shs_update(shsInfo, buffer, size_t(count), false); +} + +void shsFinal(SHS_INFO *shsInfo) { shs_final(shsInfo, false); } + +void shs1Init(SHS_INFO *shsInfo) { shs_init(shsInfo); } + +void shs1Update(SHS_INFO *shsInfo, unsigned char *buffer, sec_int4 count) +{ + if (count > 0) + shs_update(shsInfo, buffer, size_t(count), true); +} + +void shs1Final(SHS_INFO *shsInfo) { shs_final(shsInfo, true); } + +} // extern "C" diff --git a/port/secude/src/lnumber.cpp b/port/secude/src/lnumber.cpp new file mode 100644 index 000000000..e8abfd364 --- /dev/null +++ b/port/secude/src/lnumber.cpp @@ -0,0 +1,266 @@ +// SECUDE long-number arithmetic on L_NUMBER arrays: +// a[0] number of 32-bit words (two's complement of it for negative values) +// a[1..n] magnitude, least significant word first +#include "bn.hpp" + +namespace compat { + +namespace { + +BN_CTX *ctx() { return bn_ctx(); } + +constexpr L_NUMBER kSign = 0x80000000u; +constexpr size_t kMaxWords = MAXGENL * 4; + +Bn from_ln(const L_NUMBER *a) +{ + if (!a) + fail(EINVALID, "missing L_NUMBER"); + L_NUMBER head = a[0]; + bool negative = head & kSign; + size_t n = negative ? size_t(L_NUMBER(~head + 1)) : size_t(head); + if (n > kMaxWords) + fail(EINVALID, "L_NUMBER too long"); + std::vector be(n * 4); + for (size_t i = 0; i < n; ++i) { + L_NUMBER w = a[n - i]; + be[4 * i] = uint8_t(w >> 24); + be[4 * i + 1] = uint8_t(w >> 16); + be[4 * i + 2] = uint8_t(w >> 8); + be[4 * i + 3] = uint8_t(w); + } + Bn b = bn_new(); + if (!BN_bin2bn(be.data(), int(be.size()), b.get())) + throw std::bad_alloc(); + BN_set_negative(b.get(), negative && !BN_is_zero(b.get())); + return b; +} + +void to_ln(const BIGNUM *b, L_NUMBER *out) +{ + int nbytes = BN_num_bytes(b); + size_t n = size_t(nbytes + 3) / 4; + std::vector be(n * 4); + if (n && BN_bn2binpad(b, be.data(), int(be.size())) < 0) + fail(EINTERNAL, "BN_bn2binpad failed"); + for (size_t i = 0; i < n; ++i) { + size_t off = (n - 1 - i) * 4; + out[i + 1] = (L_NUMBER(be[off]) << 24) | (L_NUMBER(be[off + 1]) << 16) | (L_NUMBER(be[off + 2]) << 8) | be[off + 3]; + } + out[0] = BN_is_negative(b) ? L_NUMBER(~L_NUMBER(n) + 1) : L_NUMBER(n); + // libec reads x[1] of a zero result (e.g. the remainder in ln_to_string) + if (n == 0) + out[1] = 0; +} + +void check(int ok) { bn_check(ok); } + +} // namespace + +} // namespace compat + +using namespace compat; + +extern "C" { + +int lngtouse(L_NUMBER_ARRAY modul) +{ + return guarded("lngtouse", -1, [&] { return BN_num_bits(from_ln(modul).get()) - 1; }); +} + +int arithmetic_comp(L_NUMBER *Ap, L_NUMBER *Bp) +{ + return guarded("arithmetic_comp", 0, [&] { + int c = BN_cmp(from_ln(Ap).get(), from_ln(Bp).get()); + return c < 0 ? -1 : c > 0 ? 1 : 0; + }); +} + +void arithmetic_add(L_NUMBER_ARRAY Ap, L_NUMBER_ARRAY Bp, L_NUMBER_ARRAY Sum) +{ + guarded_void("arithmetic_add", [&] { + Bn a = from_ln(Ap), b = from_ln(Bp), r = bn_new(); + check(BN_add(r.get(), a.get(), b.get())); + to_ln(r.get(), Sum); + }); +} + +void arithmetic_sub(L_NUMBER_ARRAY Ap, L_NUMBER_ARRAY Bp, L_NUMBER_ARRAY Diff) +{ + guarded_void("arithmetic_sub", [&] { + Bn a = from_ln(Ap), b = from_ln(Bp), r = bn_new(); + check(BN_sub(r.get(), a.get(), b.get())); + to_ln(r.get(), Diff); + }); +} + +void arithmetic_mult(L_NUMBER_ARRAY A, L_NUMBER_ARRAY B, L_NUMBER_ARRAY erg) +{ + guarded_void("arithmetic_mult", [&] { + Bn a = from_ln(A), b = from_ln(B), r = bn_new(); + check(BN_mul(r.get(), a.get(), b.get(), ctx())); + to_ln(r.get(), erg); + }); +} + +void arithmetic_div(L_NUMBER_ARRAY A, L_NUMBER_ARRAY B, L_NUMBER_ARRAY Q, L_NUMBER_ARRAY R) +{ + guarded_void("arithmetic_div", [&] { + Bn a = from_ln(A), b = from_ln(B), q = bn_new(), r = bn_new(); + if (BN_is_zero(b.get())) + fail(EINVALID, "division by zero"); + check(BN_div(q.get(), r.get(), a.get(), b.get(), ctx())); + if (Q) + to_ln(q.get(), Q); + if (R) + to_ln(r.get(), R); + }); +} + +void arithmetic_shift(L_NUMBER_ARRAY A, int exp2b, L_NUMBER_ARRAY S) +{ + guarded_void("arithmetic_shift", [&] { + Bn a = from_ln(A), r = bn_new(); + bool negative = BN_is_negative(a.get()); + BN_set_negative(a.get(), 0); + if (exp2b >= 0) + check(BN_lshift(r.get(), a.get(), exp2b)); + else + check(BN_rshift(r.get(), a.get(), -exp2b)); + BN_set_negative(r.get(), negative && !BN_is_zero(r.get())); + to_ln(r.get(), S); + }); +} + +static int modular(const char *proc, L_NUMBER *op1, L_NUMBER *op2, L_NUMBER *erg, L_NUMBER *modul, + int (*fn)(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *)) +{ + return guarded(proc, -1, [&] { + Bn a = from_ln(op1), b = from_ln(op2), m = from_ln(modul), r = bn_new(); + if (BN_is_zero(m.get())) + fail(EINVALID, "modulus is zero"); + BN_set_negative(m.get(), 0); + check(fn(r.get(), a.get(), b.get(), m.get(), ctx())); + to_ln(r.get(), erg); + return 0; + }); +} + +int arithmetic_madd(L_NUMBER_ARRAY op1, L_NUMBER_ARRAY op2, L_NUMBER_ARRAY erg, L_NUMBER_ARRAY modul) +{ + return modular("arithmetic_madd", op1, op2, erg, modul, BN_mod_add); +} + +int arithmetic_msub(L_NUMBER_ARRAY op1, L_NUMBER_ARRAY op2, L_NUMBER_ARRAY erg, L_NUMBER_ARRAY modul) +{ + return modular("arithmetic_msub", op1, op2, erg, modul, BN_mod_sub); +} + +int arithmetic_mmult(L_NUMBER_ARRAY op1, L_NUMBER_ARRAY op2, L_NUMBER_ARRAY erg, L_NUMBER_ARRAY modul) +{ + return modular("arithmetic_mmult", op1, op2, erg, modul, BN_mod_mul); +} + +int arithmetic_mdiv(L_NUMBER_ARRAY op1, L_NUMBER_ARRAY op2, L_NUMBER_ARRAY erg, L_NUMBER_ARRAY modul) +{ + return guarded("arithmetic_mdiv", -1, [&] { + Bn a = from_ln(op1), b = from_ln(op2), m = from_ln(modul), inv = bn_new(), r = bn_new(); + if (BN_is_zero(m.get())) + fail(EINVALID, "modulus is zero"); + BN_set_negative(m.get(), 0); + if (!BN_mod_inverse(inv.get(), b.get(), m.get(), ctx())) + fail(EINVALID, "divisor not invertible"); + check(BN_mod_mul(r.get(), a.get(), inv.get(), m.get(), ctx())); + to_ln(r.get(), erg); + return 0; + }); +} + +int arithmetic_mexp(L_NUMBER_ARRAY bas, L_NUMBER_ARRAY exp, L_NUMBER_ARRAY erg, L_NUMBER_ARRAY modul) +{ + return guarded("arithmetic_mexp", -1, [&] { + Bn b = from_ln(bas), e = from_ln(exp), m = from_ln(modul), r = bn_new(); + if (BN_is_zero(m.get())) + fail(EINVALID, "modulus is zero"); + if (BN_is_negative(e.get())) + fail(EINVALID, "negative exponent"); + BN_set_negative(m.get(), 0); + check(BN_nnmod(b.get(), b.get(), m.get(), ctx())); + check(BN_mod_exp(r.get(), b.get(), e.get(), m.get(), ctx())); + to_ln(r.get(), erg); + return 0; + }); +} + +// 0 for a probable prime, -1 otherwise (libec's curve validation) +int rabinstest(L_NUMBER_ARRAY zahl) +{ + return guarded("rabinstest", -1, [&] { + Bn n = from_ln(zahl); + if (BN_is_negative(n.get())) + return -1; + int r = BN_check_prime(n.get(), ctx(), nullptr); + if (r < 0) + fail(EINTERNAL, "primality test failed"); + return r == 1 ? 0 : -1; + }); +} + +int rndm(int lgth, L_NUMBER_ARRAY zahl, int version) +{ + return guarded("rndm", -1, [&] { + Bn r = bn_new(); + if (lgth <= 0) + BN_zero(r.get()); + else + check(BN_rand(r.get(), lgth, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY)); + to_ln(r.get(), zahl); + return 0; + }); +} + +RC aux_OctetString2LN2(L_NUMBER *lnum, OctetString *ostr) +{ + return guarded("aux_OctetString2LN2", -1, [&] { + if (!lnum || !ostr) + fail(EINVALID, "missing parameter"); + Bytes b = bytes_of(ostr); + Bn r = bn_new(); + if (!b.empty() && !BN_bin2bn(b.data(), int(b.size()), r.get())) + throw std::bad_alloc(); + to_ln(r.get(), lnum); + return 0; + }); +} + +RC aux_BitString2LN2(L_NUMBER *lnum, BitString *bstr) +{ + return guarded("aux_BitString2LN2", -1, [&] { + if (!lnum || !bstr) + fail(EINVALID, "missing parameter"); + Bytes b = bytes_of(bstr); + Bn r = bn_new(); + if (!b.empty()) { + if (!BN_bin2bn(b.data(), int(b.size()), r.get())) + throw std::bad_alloc(); + check(BN_rshift(r.get(), r.get(), int(b.size() * 8 - bstr->nbits))); + } + to_ln(r.get(), lnum); + return 0; + }); +} + +OctetString *aux_LN2OctetString(L_NUMBER_ARRAY lnum, int size) +{ + return guarded("aux_LN2OctetString", nullptr, [&] { + Bn a = from_ln(lnum); + size_t minimal = size_t(BN_num_bytes(a.get())); + size_t n = size > 0 && size_t(size) > minimal ? size_t(size) : minimal; + Bytes out(n); + if (n) + BN_bn2binpad(a.get(), out.data(), int(n)); + return new_ostr(out); + }); +} + +} // extern "C" diff --git a/port/secude/src/misc.cpp b/port/secude/src/misc.cpp new file mode 100644 index 000000000..4040d1611 --- /dev/null +++ b/port/secude/src/misc.cpp @@ -0,0 +1,187 @@ +// Files, randomness, licensing and version information. +#include "internal.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace compat { + +Bytes random_bytes(size_t n) +{ + Bytes b(n); + if (n && RAND_bytes_ex(libctx(), b.data(), n, 0) != 1) + fail(ERANDOM, "random number generator failed"); + return b; +} + +std::string native_path(const std::string &path) +{ +#ifdef _WIN32 + return path; +#else + std::string p = path; + if (p.size() >= 2 && p[1] == ':' && std::isalpha(static_cast(p[0]))) + p.erase(0, 2); + for (char &c : p) + if (c == '\\') + c = '/'; + return p; +#endif +} + +Bytes read_file(const std::string &win_path, bool &exists) +{ + std::string path = native_path(win_path); + exists = false; + FILE *f = std::fopen(path.c_str(), "rb"); + if (!f) { + if (errno == ENOENT || errno == ENOTDIR) + return {}; + fail(EREADFILE, "cannot open " + path + ": " + std::strerror(errno)); + } + exists = true; + Bytes data; + uint8_t buf[65536]; + size_t n; + while ((n = std::fread(buf, 1, sizeof buf, f)) > 0) + data.insert(data.end(), buf, buf + n); + bool error = std::ferror(f); + std::fclose(f); + if (error) + fail(EREADFILE, "cannot read " + path); + return data; +} + +void write_file_atomic(const std::string &win_path, const Bytes &data, int mode) +{ + std::string path = native_path(win_path); + std::string tmp = path + ".tmp" + std::to_string(::getpid()); + int fd = ::open(tmp.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd < 0) + fail(EWRITEFILE, "cannot create " + tmp + ": " + std::strerror(errno)); + size_t done = 0; + while (done < data.size()) { + ssize_t w = ::write(fd, data.data() + done, data.size() - done); + if (w < 0) { + if (errno == EINTR) + continue; + ::close(fd); + ::unlink(tmp.c_str()); + fail(EWRITEFILE, "cannot write " + tmp); + } + done += size_t(w); + } + if (::fsync(fd) != 0 || ::close(fd) != 0) { + ::unlink(tmp.c_str()); + fail(EWRITEFILE, "cannot write " + tmp); + } + if (std::rename(tmp.c_str(), path.c_str()) != 0) { + ::unlink(tmp.c_str()); + fail(EWRITEFILE, "cannot replace " + path + ": " + std::strerror(errno)); + } +} + +std::string hex(const uint8_t *p, size_t n, bool upper) +{ + static const char *digits[2] = {"0123456789abcdef", "0123456789ABCDEF"}; + std::string s; + s.reserve(n * 2); + for (size_t i = 0; i < n; ++i) { + s += digits[upper][p[i] >> 4]; + s += digits[upper][p[i] & 0xf]; + } + return s; +} + +} // namespace compat + +using namespace compat; + +namespace { + +const char *version_string() +{ + static const std::string v = std::string("SECUDE compatibility layer 1.0 for CrypTool (") + OPENSSL_VERSION_TEXT + ")"; + return v.c_str(); +} + +} // namespace + +extern "C" { + +const char *secude_compat_version(void) { return version_string(); } + +RC SECUDE_HasValidTicket(char **rcIdOrError) +{ + static char text[] = "no license ticket required"; + if (rcIdOrError) + *rcIdOrError = text; + return 0; +} + +int light_version(void) +{ + return 0; +} + +char *aux_sprint_version(char *string) +{ + return guarded("aux_sprint_version", nullptr, [&] { return append_string(string, version_string()); }); +} + +OctetString *aux_file2OctetString(char *fn) +{ + return guarded("aux_file2OctetString", nullptr, [&] { + if (!fn) + fail(EINVALID, "missing file name"); + bool exists = false; + Bytes data = read_file(fn, exists); + if (!exists) + fail(EFILENOTEXISTING, std::string("file ") + fn + " does not exist"); + return new_ostr(data); + }); +} + +// flag 3 appends to the file, every other value creates or truncates it. +int aux_OctetString2file(OctetString *ostr, char *fn, int flag) +{ + return guarded("aux_OctetString2file", -1, [&] { + if (!ostr || !fn) + fail(EINVALID, "missing parameter"); + FILE *f = std::fopen(native_path(fn).c_str(), flag == 3 ? "ab" : "wb"); + if (!f) + fail(EWRITEFILE, std::string("cannot open ") + fn + ": " + std::strerror(errno)); + size_t n = ostr->noctets ? std::fwrite(ostr->octets, 1, ostr->noctets, f) : 0; + bool ok = n == ostr->noctets; + ok = std::fclose(f) == 0 && ok; + if (!ok) + fail(EWRITEFILE, std::string("cannot write ") + fn); + return 0; + }); +} + +OctetString *aux_latin1_to_unicode(char *latin_string, Boolean termination) +{ + return guarded("aux_latin1_to_unicode", nullptr, [&] { + if (!latin_string) + fail(EINVALID, "missing string"); + Bytes b; + for (const unsigned char *p = reinterpret_cast(latin_string); *p; ++p) { + b.push_back(0); + b.push_back(*p); + } + if (termination) { + b.push_back(0); + b.push_back(0); + } + return new_ostr(b); + }); +} + +} // extern "C" diff --git a/port/secude/src/oids.cpp b/port/secude/src/oids.cpp new file mode 100644 index 000000000..0014ff2bf --- /dev/null +++ b/port/secude/src/oids.cpp @@ -0,0 +1,491 @@ +#include "internal.hpp" + +#include + +namespace compat { + +namespace oids { +const Oid rsa{2, 5, 8, 1, 1}; +const Oid rsaEncryption{1, 2, 840, 113549, 1, 1, 1}; +const Oid dsa{1, 3, 14, 3, 2, 12}; +const Oid id_dsa{1, 2, 840, 10040, 4, 1}; +const Oid md2{1, 2, 840, 113549, 2, 2}; +const Oid md4{1, 2, 840, 113549, 2, 4}; +const Oid md5{1, 2, 840, 113549, 2, 5}; +const Oid sha{1, 3, 14, 3, 2, 18}; +const Oid sha1{1, 3, 14, 3, 2, 26}; +const Oid ripemd160{1, 3, 36, 3, 2, 1}; +const Oid sha256{2, 16, 840, 1, 101, 3, 4, 2, 1}; +const Oid sha384{2, 16, 840, 1, 101, 3, 4, 2, 2}; +const Oid sha512{2, 16, 840, 1, 101, 3, 4, 2, 3}; +const Oid data{1, 2, 840, 113549, 1, 7, 1}; +const Oid encryptedData{1, 2, 840, 113549, 1, 7, 6}; +const Oid keyBag{1, 2, 840, 113549, 1, 12, 10, 1, 1}; +const Oid pkcs8ShroudedKeyBag{1, 2, 840, 113549, 1, 12, 10, 1, 2}; +const Oid certBag{1, 2, 840, 113549, 1, 12, 10, 1, 3}; +const Oid x509Certificate{1, 2, 840, 113549, 1, 9, 22, 1}; +const Oid friendlyName{1, 2, 840, 113549, 1, 9, 20}; +const Oid localKeyId{1, 2, 840, 113549, 1, 9, 21}; +const Oid pbeSHA1RC4_128{1, 2, 840, 113549, 1, 12, 1, 1}; +const Oid pbeSHA1RC4_40{1, 2, 840, 113549, 1, 12, 1, 2}; +const Oid pbeSHA1DES3{1, 2, 840, 113549, 1, 12, 1, 3}; +const Oid pbeSHA1DES2{1, 2, 840, 113549, 1, 12, 1, 4}; +const Oid pbeSHA1RC2_128{1, 2, 840, 113549, 1, 12, 1, 5}; +const Oid pbeSHA1RC2_40{1, 2, 840, 113549, 1, 12, 1, 6}; +const Oid pbes2{1, 2, 840, 113549, 1, 5, 13}; +const Oid pbkdf2{1, 2, 840, 113549, 1, 5, 12}; +const Oid hmacSHA1{1, 2, 840, 113549, 2, 7}; +const Oid hmacSHA256{1, 2, 840, 113549, 2, 9}; +const Oid hmacSHA384{1, 2, 840, 113549, 2, 10}; +const Oid hmacSHA512{1, 2, 840, 113549, 2, 11}; +const Oid aes128CBC{2, 16, 840, 1, 101, 3, 4, 1, 2}; +const Oid aes192CBC{2, 16, 840, 1, 101, 3, 4, 1, 22}; +const Oid aes256CBC{2, 16, 840, 1, 101, 3, 4, 1, 42}; +const Oid desEDE3CBC{1, 2, 840, 113549, 3, 7}; +const Oid subjectKeyIdentifier{2, 5, 29, 14}; +const Oid keyUsage{2, 5, 29, 15}; +const Oid basicConstraints{2, 5, 29, 19}; +const Oid authorityKeyIdentifier{2, 5, 29, 35}; +const Oid cryptoolPseName{2, 206, 5, 4, 3, 2}; +} // namespace oids + +} // namespace compat + +using namespace compat; + +#define OID_ELEMS(name, ...) static unsigned int name##_elems[] = {__VA_ARGS__} +#define OID_OBJ(name) {int(sizeof(name##_elems) / sizeof(unsigned int)), name##_elems} + +// Object identifiers of algorithms +OID_ELEMS(rsa, 2, 5, 8, 1, 1); +OID_ELEMS(rsaEncryption, 1, 2, 840, 113549, 1, 1, 1); +OID_ELEMS(dsa, 1, 3, 14, 3, 2, 12); +OID_ELEMS(md2, 1, 2, 840, 113549, 2, 2); +OID_ELEMS(md4, 1, 2, 840, 113549, 2, 4); +OID_ELEMS(md5, 1, 2, 840, 113549, 2, 5); +OID_ELEMS(sha, 1, 3, 14, 3, 2, 18); +OID_ELEMS(sha1, 1, 3, 14, 3, 2, 26); +OID_ELEMS(ripemd160, 1, 3, 36, 3, 2, 1); +OID_ELEMS(md2WithRsaEncryption, 1, 2, 840, 113549, 1, 1, 2); +OID_ELEMS(md4WithRsaEncryption, 1, 2, 840, 113549, 1, 1, 3); +OID_ELEMS(md5WithRsaEncryption, 1, 2, 840, 113549, 1, 1, 4); +OID_ELEMS(sha1WithRsaEncryption, 1, 2, 840, 113549, 1, 1, 5); +OID_ELEMS(md2WithRSASignature, 1, 3, 14, 3, 2, 24); +OID_ELEMS(shaWithRSASignature, 1, 3, 14, 3, 2, 15); +OID_ELEMS(sha1WithRSASignature, 1, 3, 14, 3, 2, 29); +OID_ELEMS(ripemd160WithRSASignature, 1, 3, 36, 3, 3, 1, 2); +OID_ELEMS(dsaWithSHA, 1, 3, 14, 3, 2, 13); +OID_ELEMS(dsaWithSHA1, 1, 3, 14, 3, 2, 27); +OID_ELEMS(desECB, 1, 3, 14, 3, 2, 6); +OID_ELEMS(desCBC, 1, 3, 14, 3, 2, 7); +OID_ELEMS(desCBC_pad, 1, 3, 36, 3, 1, 1, 2, 1); +OID_ELEMS(desEDE, 1, 3, 14, 3, 2, 17); +OID_ELEMS(desCBC3, 1, 3, 36, 3, 1, 3, 2); +OID_ELEMS(desCBC3_pad, 1, 3, 36, 3, 1, 3, 2, 1); +OID_ELEMS(desEDE3CBC, 1, 2, 840, 113549, 3, 7); +OID_ELEMS(idea, 1, 3, 36, 3, 1, 2); +OID_ELEMS(ideaCBC, 1, 3, 6, 1, 4, 1, 188, 7, 1, 1, 2); +OID_ELEMS(rc2CBC, 1, 2, 840, 113549, 3, 2); +OID_ELEMS(rc4, 1, 2, 840, 113549, 3, 4); +OID_ELEMS(aes128ECB, 2, 16, 840, 1, 101, 3, 4, 1, 1); +OID_ELEMS(aes128CBC, 2, 16, 840, 1, 101, 3, 4, 1, 2); +OID_ELEMS(aes192ECB, 2, 16, 840, 1, 101, 3, 4, 1, 21); +OID_ELEMS(aes192CBC, 2, 16, 840, 1, 101, 3, 4, 1, 22); +OID_ELEMS(aes256ECB, 2, 16, 840, 1, 101, 3, 4, 1, 41); +OID_ELEMS(aes256CBC, 2, 16, 840, 1, 101, 3, 4, 1, 42); +OID_ELEMS(pbeWithSHA1And128BitRC4, 1, 2, 840, 113549, 1, 12, 1, 1); +OID_ELEMS(pbeWithSHA1And40BitRC4, 1, 2, 840, 113549, 1, 12, 1, 2); +OID_ELEMS(pbeWithSHA1AndDES3xCBC, 1, 2, 840, 113549, 1, 12, 1, 3); +OID_ELEMS(pbeWithSHA1AndDES3CBC, 1, 2, 840, 113549, 1, 12, 1, 4); +OID_ELEMS(pbeWithSHA1And128BitRC2CBC, 1, 2, 840, 113549, 1, 12, 1, 5); +OID_ELEMS(pbeWithSHA1And40BitRC2CBC, 1, 2, 840, 113549, 1, 12, 1, 6); + +// Object identifiers of PSE object types (private arc 2.206.5.1, see README.md) +OID_ELEMS(SKnew, 2, 206, 5, 1, 1); +OID_ELEMS(SKold, 2, 206, 5, 1, 2); +OID_ELEMS(SignSK, 2, 206, 5, 1, 3); +OID_ELEMS(DecSKnew, 2, 206, 5, 1, 4); +OID_ELEMS(DecSKold, 2, 206, 5, 1, 5); +OID_ELEMS(AuthSK, 2, 206, 5, 1, 6); +OID_ELEMS(Cert, 2, 206, 5, 1, 10); +OID_ELEMS(SignCert, 2, 206, 5, 1, 11); +OID_ELEMS(EncCert, 2, 206, 5, 1, 12); +OID_ELEMS(AuthCert, 2, 206, 5, 1, 13); +OID_ELEMS(PKRoot, 2, 206, 5, 1, 20); +OID_ELEMS(FCPath, 2, 206, 5, 1, 21); +OID_ELEMS(SerialNumber, 2, 206, 5, 1, 30); +OID_ELEMS(Name, 2, 206, 5, 1, 31); +OID_ELEMS(Uid, 2, 206, 5, 1, 40); + +static unsigned int rsa_default_keysize = DEF_ASYM_KEYSIZE; +static ObjId md2WithRSASignature_oid_obj = OID_OBJ(md2WithRSASignature); + +extern "C" { + +ObjId rsa_oid = OID_OBJ(rsa); +ObjId rsaEncryption_oid = OID_OBJ(rsaEncryption); +ObjId dsa_oid = OID_OBJ(dsa); +ObjId md2_oid = OID_OBJ(md2); +ObjId md4_oid = OID_OBJ(md4); +ObjId md5_oid = OID_OBJ(md5); +ObjId sha_oid = OID_OBJ(sha); +ObjId sha1_oid = OID_OBJ(sha1); +ObjId ripemd160_oid = OID_OBJ(ripemd160); +ObjId md2WithRsaEncryption_oid = OID_OBJ(md2WithRsaEncryption); +ObjId md4WithRsaEncryption_oid = OID_OBJ(md4WithRsaEncryption); +ObjId md5WithRsaEncryption_oid = OID_OBJ(md5WithRsaEncryption); +ObjId sha1WithRsaEncryption_oid = OID_OBJ(sha1WithRsaEncryption); +ObjId shaWithRSASignature_oid = OID_OBJ(shaWithRSASignature); +ObjId sha1WithRSASignature_oid = OID_OBJ(sha1WithRSASignature); +ObjId ripemd160WithRSASignature_oid = OID_OBJ(ripemd160WithRSASignature); +ObjId dsaWithSHA_oid = OID_OBJ(dsaWithSHA); +ObjId dsaWithSHA1_oid = OID_OBJ(dsaWithSHA1); +ObjId desECB_oid = OID_OBJ(desECB); +ObjId desCBC_oid = OID_OBJ(desCBC); +ObjId desCBC_pad_oid = OID_OBJ(desCBC_pad); +ObjId desEDE_oid = OID_OBJ(desEDE); +ObjId desCBC3_oid = OID_OBJ(desCBC3); +ObjId desCBC3_pad_oid = OID_OBJ(desCBC3_pad); +ObjId desEDE3CBC_oid = OID_OBJ(desEDE3CBC); +ObjId idea_oid = OID_OBJ(idea); +ObjId ideaCBC_oid = OID_OBJ(ideaCBC); +ObjId rc2CBC_oid = OID_OBJ(rc2CBC); +ObjId rc4_oid = OID_OBJ(rc4); +ObjId aes128ECB_oid = OID_OBJ(aes128ECB); +ObjId aes128CBC_oid = OID_OBJ(aes128CBC); +ObjId aes192ECB_oid = OID_OBJ(aes192ECB); +ObjId aes192CBC_oid = OID_OBJ(aes192CBC); +ObjId aes256ECB_oid = OID_OBJ(aes256ECB); +ObjId aes256CBC_oid = OID_OBJ(aes256CBC); +ObjId pbeWithSHA1And128BitRC4_oid = OID_OBJ(pbeWithSHA1And128BitRC4); +ObjId pbeWithSHA1And40BitRC4_oid = OID_OBJ(pbeWithSHA1And40BitRC4); +ObjId pbeWithSHA1AndDES3xCBC_oid = OID_OBJ(pbeWithSHA1AndDES3xCBC); +ObjId pbeWithSHA1AndDES3CBC_oid = OID_OBJ(pbeWithSHA1AndDES3CBC); +ObjId pbeWithSHA1And128BitRC2CBC_oid = OID_OBJ(pbeWithSHA1And128BitRC2CBC); +ObjId pbeWithSHA1And40BitRC2CBC_oid = OID_OBJ(pbeWithSHA1And40BitRC2CBC); + +ObjId SKnew_oid = OID_OBJ(SKnew); +ObjId SKold_oid = OID_OBJ(SKold); +ObjId SignSK_oid = OID_OBJ(SignSK); +ObjId DecSKnew_oid = OID_OBJ(DecSKnew); +ObjId DecSKold_oid = OID_OBJ(DecSKold); +ObjId AuthSK_oid = OID_OBJ(AuthSK); +ObjId Cert_oid = OID_OBJ(Cert); +ObjId SignCert_oid = OID_OBJ(SignCert); +ObjId EncCert_oid = OID_OBJ(EncCert); +ObjId AuthCert_oid = OID_OBJ(AuthCert); +ObjId PKRoot_oid = OID_OBJ(PKRoot); +ObjId FCPath_oid = OID_OBJ(FCPath); +ObjId SerialNumber_oid = OID_OBJ(SerialNumber); +ObjId Name_oid = OID_OBJ(Name); +ObjId Uid_oid = OID_OBJ(Uid); + +ObjId *Uid_OID = &Uid_oid; +ObjId *Cert_OID = &Cert_oid; + +AlgId rsa_aid = {&rsa_oid, &rsa_default_keysize, nullptr}; +AlgId rsaEncryption_aid = {&rsaEncryption_oid, nullptr, nullptr}; +AlgId dsa_aid = {&dsa_oid, nullptr, nullptr}; +AlgId md2_aid = {&md2_oid, nullptr, nullptr}; +AlgId md4_aid = {&md4_oid, nullptr, nullptr}; +AlgId md5_aid = {&md5_oid, nullptr, nullptr}; +AlgId sha_aid = {&sha_oid, nullptr, nullptr}; +AlgId sha1_aid = {&sha1_oid, nullptr, nullptr}; +AlgId ripemd160_aid = {&ripemd160_oid, nullptr, nullptr}; +AlgId md2WithRsaEncryption_aid = {&md2WithRsaEncryption_oid, nullptr, nullptr}; +AlgId md4WithRsaEncryption_aid = {&md4WithRsaEncryption_oid, nullptr, nullptr}; +AlgId md5WithRsaEncryption_aid = {&md5WithRsaEncryption_oid, nullptr, nullptr}; +AlgId sha1WithRsaEncryption_aid = {&sha1WithRsaEncryption_oid, nullptr, nullptr}; +AlgId md2WithRSASignature_aid = {&md2WithRSASignature_oid_obj, nullptr, nullptr}; +AlgId shaWithRSASignature_aid = {&shaWithRSASignature_oid, nullptr, nullptr}; +AlgId sha1WithRSASignature_aid = {&sha1WithRSASignature_oid, nullptr, nullptr}; +AlgId ripemd160WithRSASignature_aid = {&ripemd160WithRSASignature_oid, nullptr, nullptr}; +AlgId dsaWithSHA_aid = {&dsaWithSHA_oid, nullptr, nullptr}; +AlgId dsaWithSHA1_aid = {&dsaWithSHA1_oid, nullptr, nullptr}; +AlgId desECB_aid = {&desECB_oid, nullptr, nullptr}; +AlgId desCBC_aid = {&desCBC_oid, nullptr, nullptr}; +AlgId desCBC_pad_aid = {&desCBC_pad_oid, nullptr, nullptr}; +AlgId desEDE_aid = {&desEDE_oid, nullptr, nullptr}; +AlgId desCBC3_aid = {&desCBC3_oid, nullptr, nullptr}; +AlgId desCBC3_pad_aid = {&desCBC3_pad_oid, nullptr, nullptr}; +AlgId desEDE3CBC_aid = {&desEDE3CBC_oid, nullptr, nullptr}; +AlgId idea_aid = {&idea_oid, nullptr, nullptr}; +AlgId ideaCBC_aid = {&ideaCBC_oid, nullptr, nullptr}; +AlgId rc2CBC_aid = {&rc2CBC_oid, nullptr, nullptr}; +AlgId rc4_aid = {&rc4_oid, nullptr, nullptr}; +AlgId aes128ECB_aid = {&aes128ECB_oid, nullptr, nullptr}; +AlgId aes128CBC_aid = {&aes128CBC_oid, nullptr, nullptr}; +AlgId aes192ECB_aid = {&aes192ECB_oid, nullptr, nullptr}; +AlgId aes192CBC_aid = {&aes192CBC_oid, nullptr, nullptr}; +AlgId aes256ECB_aid = {&aes256ECB_oid, nullptr, nullptr}; +AlgId aes256CBC_aid = {&aes256CBC_oid, nullptr, nullptr}; + +} // extern "C" + +namespace compat { + +namespace { + +using H = Hash; +using C = Cipher; + +const std::vector &alg_table() +{ + static const std::vector table = { + {"md2", oids::md2, PARM_NULL, HASH, NoAlgEnc, H::MD2, C::None, NoAlgMode, Pad::None, &md2_aid}, + {"md4", oids::md4, PARM_NULL, HASH, NoAlgEnc, H::MD4, C::None, NoAlgMode, Pad::None, &md4_aid}, + {"md5", oids::md5, PARM_NULL, HASH, NoAlgEnc, H::MD5, C::None, NoAlgMode, Pad::None, &md5_aid}, + {"sha", oids::sha, PARM_NULL, HASH, NoAlgEnc, H::SHA0, C::None, NoAlgMode, Pad::None, &sha_aid}, + {"sha1", oids::sha1, PARM_NULL, HASH, NoAlgEnc, H::SHA1, C::None, NoAlgMode, Pad::None, &sha1_aid}, + {"ripemd160", oids::ripemd160, PARM_NULL, HASH, NoAlgEnc, H::RIPEMD160, C::None, NoAlgMode, Pad::None, &ripemd160_aid}, + {"sha256", oids::sha256, PARM_NULL, HASH, NoAlgEnc, H::SHA256, C::None, NoAlgMode, Pad::None, nullptr}, + {"sha384", oids::sha384, PARM_NULL, HASH, NoAlgEnc, H::SHA384, C::None, NoAlgMode, Pad::None, nullptr}, + {"sha512", oids::sha512, PARM_NULL, HASH, NoAlgEnc, H::SHA512, C::None, NoAlgMode, Pad::None, nullptr}, + + {"RSA", oids::rsa, PARM_INTEGER, ASYM_ENC, SECUDE_ALG_RSA, H::None, C::None, NoAlgMode, Pad::None, &rsa_aid}, + {"rsaEncryption", oids::rsaEncryption, PARM_NULL, ASYM_ENC, SECUDE_ALG_RSA, H::None, C::None, NoAlgMode, Pad::None, &rsaEncryption_aid}, + {"DSA", oids::dsa, PARM_KeyBits, SIG, SECUDE_ALG_DSA, H::None, C::None, NoAlgMode, Pad::None, &dsa_aid}, + {"id-dsa", oids::id_dsa, PARM_KeyBits, SIG, SECUDE_ALG_DSA, H::None, C::None, NoAlgMode, Pad::None, nullptr}, + + {"md2WithRsaEncryption", {1, 2, 840, 113549, 1, 1, 2}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::MD2, C::None, NoAlgMode, Pad::None, &md2WithRsaEncryption_aid}, + {"md4WithRsaEncryption", {1, 2, 840, 113549, 1, 1, 3}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::MD4, C::None, NoAlgMode, Pad::None, &md4WithRsaEncryption_aid}, + {"md5WithRsaEncryption", {1, 2, 840, 113549, 1, 1, 4}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::MD5, C::None, NoAlgMode, Pad::None, &md5WithRsaEncryption_aid}, + {"sha1WithRsaEncryption", {1, 2, 840, 113549, 1, 1, 5}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::SHA1, C::None, NoAlgMode, Pad::None, &sha1WithRsaEncryption_aid}, + {"sha256WithRsaEncryption", {1, 2, 840, 113549, 1, 1, 11}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::SHA256, C::None, NoAlgMode, Pad::None, nullptr}, + {"md2WithRSASignature", {1, 3, 14, 3, 2, 24}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::MD2, C::None, NoAlgMode, Pad::None, &md2WithRSASignature_aid}, + {"md5WithRSASignature", {1, 3, 14, 3, 2, 25}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::MD5, C::None, NoAlgMode, Pad::None, nullptr}, + {"shaWithRSASignature", {1, 3, 14, 3, 2, 15}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::SHA0, C::None, NoAlgMode, Pad::None, &shaWithRSASignature_aid}, + {"sha1WithRSASignature", {1, 3, 14, 3, 2, 29}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::SHA1, C::None, NoAlgMode, Pad::None, &sha1WithRSASignature_aid}, + {"ripemd160WithRSASignature", {1, 3, 36, 3, 3, 1, 2}, PARM_NULL, SIG, SECUDE_ALG_RSA, H::RIPEMD160, C::None, NoAlgMode, Pad::None, &ripemd160WithRSASignature_aid}, + {"dsaWithSHA", {1, 3, 14, 3, 2, 13}, PARM_ABSENT, SIG, SECUDE_ALG_DSA, H::SHA0, C::None, NoAlgMode, Pad::None, &dsaWithSHA_aid}, + {"dsaWithSHA1", {1, 3, 14, 3, 2, 27}, PARM_ABSENT, SIG, SECUDE_ALG_DSA, H::SHA1, C::None, NoAlgMode, Pad::None, &dsaWithSHA1_aid}, + {"id-dsa-with-sha1", {1, 2, 840, 10040, 4, 3}, PARM_ABSENT, SIG, SECUDE_ALG_DSA, H::SHA1, C::None, NoAlgMode, Pad::None, nullptr}, + + {"desECB", {1, 3, 14, 3, 2, 6}, PARM_ABSENT, SYM_ENC, DES, H::None, C::DES, ECB, Pad::Std, &desECB_aid}, + {"desCBC", {1, 3, 14, 3, 2, 7}, PARM_OctetString, SYM_ENC, DES, H::None, C::DES, CBC, Pad::Std, &desCBC_aid}, + {"desCBC_pad", {1, 3, 36, 3, 1, 1, 2, 1}, PARM_OctetString, SYM_ENC, DES, H::None, C::DES, CBC, Pad::Pkcs, &desCBC_pad_aid}, + {"desEDE", {1, 3, 14, 3, 2, 17}, PARM_ABSENT, SYM_ENC, DES3, H::None, C::DES3, ECB, Pad::Std, &desEDE_aid}, + {"desCBC3", {1, 3, 36, 3, 1, 3, 2}, PARM_OctetString, SYM_ENC, DES3, H::None, C::DES3, CBC, Pad::Std, &desCBC3_aid}, + {"desCBC3_pad", {1, 3, 36, 3, 1, 3, 2, 1}, PARM_OctetString, SYM_ENC, DES3, H::None, C::DES3, CBC, Pad::Pkcs, &desCBC3_pad_aid}, + {"desEDE3CBC", oids::desEDE3CBC, PARM_OctetString, SYM_ENC, DES3, H::None, C::DES3, CBC, Pad::Pkcs, &desEDE3CBC_aid}, + {"idea", {1, 3, 36, 3, 1, 2}, PARM_ABSENT, SYM_ENC, IDEA, H::None, C::IDEA, ECB, Pad::Std, &idea_aid}, + {"ideaCBC", {1, 3, 6, 1, 4, 1, 188, 7, 1, 1, 2}, PARM_OctetString, SYM_ENC, IDEA, H::None, C::IDEA, CBC, Pad::Pkcs, &ideaCBC_aid}, + {"rc2CBC", {1, 2, 840, 113549, 3, 2}, PARM_RC2CBC, SYM_ENC, RC2, H::None, C::RC2, CBC, Pad::Pkcs, &rc2CBC_aid}, + {"rc4", {1, 2, 840, 113549, 3, 4}, PARM_ABSENT, SYM_ENC, RC4, H::None, C::RC4, NoAlgMode, Pad::None, &rc4_aid}, + {"aes128ECB", {2, 16, 840, 1, 101, 3, 4, 1, 1}, PARM_ABSENT, SYM_ENC, AES128, H::None, C::AES, ECB, Pad::Pkcs, &aes128ECB_aid}, + {"aes128CBC", oids::aes128CBC, PARM_OctetString, SYM_ENC, AES128, H::None, C::AES, CBC, Pad::Pkcs, &aes128CBC_aid}, + {"aes192ECB", {2, 16, 840, 1, 101, 3, 4, 1, 21}, PARM_ABSENT, SYM_ENC, AES192, H::None, C::AES, ECB, Pad::Pkcs, &aes192ECB_aid}, + {"aes192CBC", oids::aes192CBC, PARM_OctetString, SYM_ENC, AES192, H::None, C::AES, CBC, Pad::Pkcs, &aes192CBC_aid}, + {"aes256ECB", {2, 16, 840, 1, 101, 3, 4, 1, 41}, PARM_ABSENT, SYM_ENC, AES256, H::None, C::AES, ECB, Pad::Pkcs, &aes256ECB_aid}, + {"aes256CBC", oids::aes256CBC, PARM_OctetString, SYM_ENC, AES256, H::None, C::AES, CBC, Pad::Pkcs, &aes256CBC_aid}, + + {"pbeWithSHA1And128BitRC4", oids::pbeSHA1RC4_128, PARM_PKCS5, PBE, RC4, H::SHA1, C::RC4, NoAlgMode, Pad::None, nullptr}, + {"pbeWithSHA1And40BitRC4", oids::pbeSHA1RC4_40, PARM_PKCS5, PBE, RC4, H::SHA1, C::RC4, NoAlgMode, Pad::None, nullptr}, + {"pbeWithSHA1AndDES3xCBC", oids::pbeSHA1DES3, PARM_PKCS5, PBE, DES3, H::SHA1, C::DES3, CBC, Pad::Pkcs, nullptr}, + {"pbeWithSHA1AndDES3CBC", oids::pbeSHA1DES2, PARM_PKCS5, PBE, DES3, H::SHA1, C::DES3, CBC, Pad::Pkcs, nullptr}, + {"pbeWithSHA1And128BitRC2CBC", oids::pbeSHA1RC2_128, PARM_PKCS5, PBE, RC2, H::SHA1, C::RC2, CBC, Pad::Pkcs, nullptr}, + {"pbeWithSHA1And40BitRC2CBC", oids::pbeSHA1RC2_40, PARM_PKCS5, PBE, RC2, H::SHA1, C::RC2, CBC, Pad::Pkcs, nullptr}, + }; + return table; +} + +struct PseObjectName { + const char *name; + ObjId *oid; +}; + +const PseObjectName kPseObjects[] = { + {SKnew_name, &SKnew_oid}, + {SKold_name, &SKold_oid}, + {SignSK_name, &SignSK_oid}, + {DecSKnew_name, &DecSKnew_oid}, + {DecSKold_name, &DecSKold_oid}, + {AuthSK_name, &AuthSK_oid}, + {Cert_name, &Cert_oid}, + {SignCert_name, &SignCert_oid}, + {EncCert_name, &EncCert_oid}, + {AuthCert_name, &AuthCert_oid}, + {PKRoot_name, &PKRoot_oid}, + {FCPath_name, &FCPath_oid}, + {SerialNumber_name, &SerialNumber_oid}, + {"Name", &Name_oid}, +}; + +} // namespace + +Oid oid_of(const ObjId *o) +{ + if (!o || o->oid_nelem <= 0 || !o->oid_elements) + return {}; + return Oid(o->oid_elements, o->oid_elements + o->oid_nelem); +} + +void fill_objid(ObjId *dst, const Oid &o) +{ + unsigned int *e = static_cast(mem_alloc(sizeof(unsigned int) * (o.size() ? o.size() : 1))); + for (size_t i = 0; i < o.size(); ++i) + e[i] = o[i]; + dst->oid_nelem = int(o.size()); + dst->oid_elements = e; +} + +ObjId *new_objid(const Oid &o) +{ + ObjId *r = mem_new(); + fill_objid(r, o); + return r; +} + +std::string oid_to_string(const Oid &o) +{ + std::string s; + for (size_t i = 0; i < o.size(); ++i) { + if (i) + s += '.'; + s += std::to_string(o[i]); + } + return s; +} + +bool oid_equal(const ObjId *a, const Oid &b) +{ + if (!a) + return false; + if (size_t(a->oid_nelem) != b.size()) + return false; + for (size_t i = 0; i < b.size(); ++i) + if (a->oid_elements[i] != b[i]) + return false; + return true; +} + +bool oid_equal(const ObjId *a, const ObjId *b) +{ + return a && b && oid_equal(a, oid_of(b)); +} + +const AlgInfo *alg_by_oid(const Oid &o) +{ + for (const auto &a : alg_table()) + if (a.oid == o) + return &a; + return nullptr; +} + +const AlgInfo *alg_by_oid(const ObjId *o) +{ + return o ? alg_by_oid(oid_of(o)) : nullptr; +} + +const AlgInfo *alg_by_name(const char *name) +{ + if (!name) + return nullptr; + for (const auto &a : alg_table()) + if (!strcasecmp(a.name, name)) + return &a; + return nullptr; +} + +std::string alg_display_name(const ObjId *o) +{ + const AlgInfo *a = alg_by_oid(o); + return a ? a->name : "unknown"; +} + +ObjId *pse_object_oid(const char *name) +{ + if (!name) + return nullptr; + for (const auto &p : kPseObjects) + if (!std::strcmp(p.name, name)) + return p.oid; + return nullptr; +} + +const char *pse_object_name(const ObjId *oid) +{ + for (const auto &p : kPseObjects) + if (oid_equal(oid, p.oid)) + return p.name; + return nullptr; +} + +ObjId *copy_objid(const ObjId *o) +{ + return o ? new_objid(oid_of(o)) : nullptr; +} + +void free_objid_content(ObjId *o) +{ + if (!o) + return; + mem_free(o->oid_elements); + o->oid_elements = nullptr; + o->oid_nelem = 0; +} + +} // namespace compat + +extern "C" { + +int aux_cmp_ObjId(ObjId *oid1, ObjId *oid2) +{ + if (!oid1 || !oid2) + return oid1 == oid2 ? 0 : 1; + return oid_equal(oid1, oid2) ? 0 : 1; +} + +ObjId *aux_cpy_ObjId(ObjId *oid) +{ + return guarded("aux_cpy_ObjId", nullptr, [&] { return copy_objid(oid); }); +} + +int aux_cpy2_ObjId(ObjId *dup_oid, ObjId *oid) +{ + return guarded("aux_cpy2_ObjId", -1, [&] { + if (!dup_oid || !oid) + fail(EINVALID, "missing object identifier"); + fill_objid(dup_oid, oid_of(oid)); + return 0; + }); +} + +void aux_free_ObjId(ObjId **oid) +{ + if (!oid || !*oid) + return; + if (!mem_owned(*oid)) { + *oid = nullptr; + return; + } + free_objid_content(*oid); + mem_free(*oid); + *oid = nullptr; +} + +AlgEnc aux_ObjId2AlgEnc(ObjId *given_objid) +{ + const AlgInfo *a = alg_by_oid(given_objid); + return a ? a->enc : NoAlgEnc; +} + +AlgId *aux_Name2AlgId(char *name) +{ + const AlgInfo *a = alg_by_name(name); + if (!a || !a->global) { + push_error(EUNKNOWNALGID, "aux_Name2AlgId", std::string("unknown algorithm name ") + (name ? name : "(null)")); + return nullptr; + } + return a->global; +} + +ObjId *af_get_objoid(char *objname) +{ + ObjId *o = pse_object_oid(objname); + if (!o) + push_error(EOBJNAME, "af_get_objoid", std::string("unknown PSE object ") + (objname ? objname : "(null)")); + return o; +} + +} // extern "C" diff --git a/port/secude/src/pkcs12.cpp b/port/secude/src/pkcs12.cpp new file mode 100644 index 000000000..6f29b5eb5 --- /dev/null +++ b/port/secude/src/pkcs12.cpp @@ -0,0 +1,498 @@ +// PKCS#12 (RFC 7292) encoding and decoding of P12_Safe structures and +// PKCS#8 PrivateKeyInfo creation. Supports the password-integrity mode with +// pkcs-12PbeIds (3DES, RC2, RC4) and PBES2 (PBKDF2 with AES/3DES). +#include "bn.hpp" +#include "der.hpp" +#include "symcipher.hpp" + +#include + +namespace compat { + +namespace { + +constexpr int kDefaultIterations = 2048; + +struct PbeInfo { + const Oid *oid; + Cipher cipher; + size_t keylen; + unsigned rc2_bits; +}; + +const PbeInfo kPbe[] = { + {&oids::pbeSHA1RC4_128, Cipher::RC4, 16, 0}, {&oids::pbeSHA1RC4_40, Cipher::RC4, 5, 0}, + {&oids::pbeSHA1DES3, Cipher::DES3, 24, 0}, {&oids::pbeSHA1DES2, Cipher::DES3, 16, 0}, + {&oids::pbeSHA1RC2_128, Cipher::RC2, 16, 128}, {&oids::pbeSHA1RC2_40, Cipher::RC2, 5, 40}, +}; + +const PbeInfo *pbe_by_oid(const Oid &o) +{ + for (const auto &p : kPbe) + if (*p.oid == o) + return &p; + return nullptr; +} + +struct HashChoice { + Hash hash; + const Oid *digest_oid; + const Oid *hmac_oid; + const char *name; + size_t block; +}; + +const HashChoice kHashes[] = { + {Hash::SHA1, &oids::sha1, &oids::hmacSHA1, "SHA1", 64}, + {Hash::SHA256, &oids::sha256, &oids::hmacSHA256, "SHA256", 64}, + {Hash::SHA384, &oids::sha384, &oids::hmacSHA384, "SHA384", 128}, + {Hash::SHA512, &oids::sha512, &oids::hmacSHA512, "SHA512", 128}, +}; + +const HashChoice &hash_by_digest_oid(const Oid &o) +{ + for (const auto &h : kHashes) + if (*h.digest_oid == o) + return h; + fail(EP12INTMODE, "unsupported PKCS#12 MAC algorithm " + oid_to_string(o)); +} + +const HashChoice &hash_by_hmac_oid(const Oid &o) +{ + for (const auto &h : kHashes) + if (*h.hmac_oid == o) + return h; + fail(EP12ENCALG, "unsupported PBKDF2 PRF " + oid_to_string(o)); +} + +// RFC 7292 appendix B.2 +Bytes p12_kdf(const HashChoice &h, const Bytes &password, const Bytes &salt, int iterations, uint8_t id, size_t n) +{ + size_t u = digest_size(h.hash), v = h.block; + auto stretch = [v](const Bytes &in) { + Bytes out; + if (in.empty()) + return out; + size_t len = v * ((in.size() + v - 1) / v); + for (size_t i = 0; i < len; ++i) + out.push_back(in[i % in.size()]); + return out; + }; + Bytes d(v, id), i = stretch(salt), p = stretch(password); + der::append(i, p); + Bytes out; + while (out.size() < n) { + Bytes a = d; + der::append(a, i); + a = digest(h.hash, a.data(), a.size()); + for (int r = 1; r < iterations; ++r) + a = digest(h.hash, a.data(), a.size()); + out.insert(out.end(), a.begin(), a.begin() + long(std::min(u, n - out.size()))); + Bytes b; + while (b.size() < v) + der::append(b, a); + b.resize(v); + for (size_t off = 0; off < i.size(); off += v) { + unsigned carry = 1; + for (size_t k = v; k-- > 0;) { + carry += unsigned(i[off + k]) + b[k]; + i[off + k] = uint8_t(carry); + carry >>= 8; + } + } + } + return out; +} + +Bytes hmac(const HashChoice &h, const Bytes &key, const Bytes &data) +{ + Bytes out(EVP_MAX_MD_SIZE); + size_t len = 0; + if (!EVP_Q_mac(libctx(), "HMAC", nullptr, h.name, nullptr, key.data(), key.size(), data.data(), data.size(), + out.data(), out.size(), &len)) + fail(EINTERNAL, "HMAC failed"); + out.resize(len); + return out; +} + +// BMPString password (as produced by aux_latin1_to_unicode) as Latin-1 text for PBKDF2. +std::string password_text(const Bytes &bmp) +{ + std::string s; + for (size_t i = 0; i + 1 < bmp.size(); i += 2) { + unsigned c = (unsigned(bmp[i]) << 8) | bmp[i + 1]; + if (!c) + break; + s += char(c < 0x100 ? c : '?'); + } + return s; +} + +Bytes utf8(const std::string &latin1) +{ + Bytes t = der::string(der::UTF8String, latin1); + return der::parse_one(t).value(); +} + +Bytes pbe_crypt(const Bytes &algid_der, const Bytes &password, const uint8_t *in, size_t n, bool encrypt) +{ + der::Reader r(der::parse_one(algid_der)); + Oid oid = der::get_oid(r.next()); + der::Node params = r.next(der::SEQUENCE); + CipherSpec s; + if (const PbeInfo *p = pbe_by_oid(oid)) { + der::Reader pr(params); + Bytes salt = pr.next(der::OCTET_STRING).value(); + int iter = int(der::get_integer(pr.next(der::INTEGER))); + const HashChoice &h = kHashes[0]; + s.cipher = p->cipher; + s.key = p12_kdf(h, password, salt, iter, 1, p->keylen); + if (p->cipher != Cipher::RC4) { + s.mode = CBC; + s.pad = Pad::Pkcs; + s.iv = p12_kdf(h, password, salt, iter, 2, 8); + } + s.rc2_bits = p->rc2_bits; + } else if (oid == oids::pbes2) { + der::Reader pr(params); + der::Reader kdf(pr.next(der::SEQUENCE)); + der::Reader enc(pr.next(der::SEQUENCE)); + if (der::get_oid(kdf.next()) != oids::pbkdf2) + fail(EP12ENCALG, "unsupported PBES2 key derivation"); + der::Reader kp(kdf.next(der::SEQUENCE)); + Bytes salt = kp.next(der::OCTET_STRING).value(); + int iter = int(der::get_integer(kp.next(der::INTEGER))); + der::Node node; + long long keylen = 0; + if (kp.next_optional(der::INTEGER, node)) + keylen = der::get_integer(node); + const HashChoice *prf = &kHashes[0]; + if (kp.next_optional(der::SEQUENCE, node)) + prf = &hash_by_hmac_oid(der::get_oid(der::Reader(node).next())); + Oid eoid = der::get_oid(enc.next()); + s.iv = enc.next(der::OCTET_STRING).value(); + s.mode = CBC; + s.pad = Pad::Pkcs; + size_t klen; + if (eoid == oids::aes128CBC || eoid == oids::aes192CBC || eoid == oids::aes256CBC) { + s.cipher = Cipher::AES; + klen = eoid == oids::aes128CBC ? 16 : eoid == oids::aes192CBC ? 24 : 32; + } else if (eoid == oids::desEDE3CBC) { + s.cipher = Cipher::DES3; + klen = 24; + } else { + fail(EP12ENCALG, "unsupported PBES2 cipher " + oid_to_string(eoid)); + } + if (keylen && size_t(keylen) != klen) + fail(EP12ENCALG, "inconsistent PBES2 key length"); + std::string pw = password_text(password); + Bytes pw8 = utf8(pw); + EVP_MD *md = fetch_md(prf->name); + s.key.assign(klen, 0); + bool ok = md && PKCS5_PBKDF2_HMAC(reinterpret_cast(pw8.data()), int(pw8.size()), salt.data(), + int(salt.size()), iter, md, int(klen), s.key.data()); + EVP_MD_free(md); + if (!ok) + fail(EINTERNAL, "PBKDF2 failed"); + } else { + fail(EP12ENCALG, "unsupported PKCS#12 encryption algorithm " + oid_to_string(oid)); + } + return encrypt ? cipher_encrypt(s, in, n) : cipher_decrypt(s, in, n); +} + +Bytes pbe_algid(const Oid &oid, int iterations) +{ + if (!pbe_by_oid(oid)) + fail(EP12ENCALG, "unsupported PKCS#12 encryption algorithm " + oid_to_string(oid)); + return der::seq({der::oid(oid), der::seq({der::octet_string(random_bytes(8)), der::integer(iterations)})}); +} + +Bytes attributes(const P12_Bag *b) +{ + std::vector attrs; + if (b->friendlyName && b->friendlyName->noctets) + attrs.push_back(der::seq({der::oid(oids::friendlyName), + der::set_of({der::tlv(der::BMPString, bytes_of(b->friendlyName))})})); + if (b->localKeyID && b->localKeyID->noctets) + attrs.push_back(der::seq({der::oid(oids::localKeyId), der::set_of({der::octet_string(bytes_of(b->localKeyID))})})); + if (attrs.empty()) + return {}; + return der::set_of(attrs); +} + +Bytes safe_bag(const Oid &type, const Bytes &value, const P12_Bag *b) +{ + Bytes body = der::concat({der::oid(type), der::tlv(der::ctx(0), value)}); + der::append(body, attributes(b)); + return der::tlv(der::SEQUENCE, body); +} + +Bytes content_info_data(const Bytes &content) +{ + return der::seq({der::oid(oids::data), der::tlv(der::ctx(0), der::octet_string(content))}); +} + +Bytes content_info_encrypted(const Bytes &content, const Oid &alg, int iterations, const Bytes &password) +{ + Bytes algid = pbe_algid(alg, iterations); + Bytes enc = pbe_crypt(algid, password, content.data(), content.size(), true); + Bytes eci = der::seq({der::oid(oids::data), algid, der::tlv(der::ctx(0, false), enc)}); + return der::seq({der::oid(oids::encryptedData), der::tlv(der::ctx(0), der::seq({der::integer(0), eci}))}); +} + +Bytes octet_content(const der::Node &n) +{ + if (n.tag == der::OCTET_STRING) + return n.value(); + if (n.tag == (der::OCTET_STRING | 0x20)) { + Bytes out; + der::Reader r(n); + while (!r.empty()) + der::append(out, octet_content(r.next())); + return out; + } + fail(EDECODE, "OCTET STRING expected"); +} + +void append_bag(P12_Safe *safe, P12_Bag *bag) +{ + P12_Bag **tail = &safe->bags; + while (*tail) + tail = &(*tail)->next; + *tail = bag; +} + +void parse_attributes(const der::Node &set, P12_Bag *bag) +{ + der::Reader r(set); + while (!r.empty()) { + der::Reader a(r.next(der::SEQUENCE)); + Oid id = der::get_oid(a.next()); + der::Reader values(a.next(der::SET)); + if (values.empty()) + continue; + der::Node v = values.next(); + if (id == oids::friendlyName && v.tag == der::BMPString && !bag->friendlyName) + bag->friendlyName = new_ostr(v.value()); + else if (id == oids::localKeyId && v.tag == der::OCTET_STRING && !bag->localKeyID) + bag->localKeyID = new_ostr(v.value()); + } +} + +void keep_lowest(P12_Safe *safe, int iterations) +{ + if (!safe->iterationCount || iterations < safe->iterationCount) + safe->iterationCount = iterations; +} + +int iterations_of(const Bytes &algid_der) +{ + der::Reader r(der::parse_one(algid_der)); + Oid oid = der::get_oid(r.next()); + der::Reader p(r.next(der::SEQUENCE)); + if (oid == oids::pbes2) { + der::Reader kdf(p.next(der::SEQUENCE)); + kdf.next(); + der::Reader kp(kdf.next(der::SEQUENCE)); + kp.next(); + return int(der::get_integer(kp.next(der::INTEGER))); + } + p.next(); + return int(der::get_integer(p.next(der::INTEGER))); +} + +void parse_safe_contents(const Bytes &der_bytes, const Bytes &password, P12_Safe *safe, bool encrypted) +{ + der::Reader bags(der::parse_one(der_bytes)); + while (!bags.empty()) { + der::Reader b(bags.next(der::SEQUENCE)); + Oid type = der::get_oid(b.next()); + der::Node value = der::Reader(b.next(der::ctx(0))).next(); + der::Node attrs; + bool have_attrs = b.next_optional(der::SET, attrs); + P12_Bag *bag = nullptr; + if (type == oids::keyBag || type == oids::pkcs8ShroudedKeyBag) { + Bytes pkcs8 = value.raw(); + if (type == oids::pkcs8ShroudedKeyBag) { + der::Reader e(value); + Bytes algid = e.next(der::SEQUENCE).raw(); + Bytes enc = e.next(der::OCTET_STRING).value(); + pkcs8 = pbe_crypt(algid, password, enc.data(), enc.size(), false); + if (!safe->alg_oid.espvk) + safe->alg_oid.espvk = new_objid(der::get_oid(der::Reader(der::parse_one(algid)).next())); + keep_lowest(safe, iterations_of(algid)); + } + bag = mem_new(); + bag->type = P12_bc_key; + bag->int_encryption = type == oids::pkcs8ShroudedKeyBag; + bag->content.key = dec_privatekeyinfo(pkcs8); + } else if (type == oids::certBag) { + der::Reader c(value); + if (der::get_oid(c.next()) != oids::x509Certificate) + continue; + Bytes cert = octet_content(der::Reader(c.next(der::ctx(0))).next()); + bag = mem_new(); + bag->type = P12_bc_cert; + bag->int_encryption = encrypted; + bag->content.cert = dec_certificate(cert); + } else { + continue; + } + append_bag(safe, bag); + if (have_attrs) + parse_attributes(attrs, bag); + } +} + +} // namespace + +} // namespace compat + +using namespace compat; + +extern "C" { + +int pkcs12_encode(P12_Safe *safe, OctetString *password, OctetString *asn1_out) +{ + return guarded("pkcs12_encode", -1, [&] { + if (!safe || !password || !asn1_out) + fail(EINVALID, "missing parameter"); + Bytes pw = bytes_of(password); + int iterations = safe->iterationCount > 0 ? safe->iterationCount : kDefaultIterations; + Oid enc_alg = safe->alg_oid.enc ? oid_of(safe->alg_oid.enc) : oids::pbeSHA1RC2_40; + Oid key_alg = safe->alg_oid.espvk ? oid_of(safe->alg_oid.espvk) : oids::pbeSHA1DES3; + Bytes certs_encrypted, certs_plain, keys; + for (const P12_Bag *b = safe->bags; b; b = b->next) { + if (b->type == P12_bc_cert && b->content.cert) { + Bytes cert = enc_certificate(b->content.cert); + Bytes bag = safe_bag(oids::certBag, + der::seq({der::oid(oids::x509Certificate), der::tlv(der::ctx(0), der::octet_string(cert))}), b); + der::append(b->int_encryption ? certs_encrypted : certs_plain, bag); + } else if (b->type == P12_bc_key && b->content.key) { + Bytes pkcs8 = enc_privatekeyinfo(b->content.key); + if (b->int_encryption) { + Bytes algid = pbe_algid(key_alg, iterations); + Bytes enc = pbe_crypt(algid, pw, pkcs8.data(), pkcs8.size(), true); + der::append(keys, safe_bag(oids::pkcs8ShroudedKeyBag, der::seq({algid, der::octet_string(enc)}), b)); + } else { + der::append(keys, safe_bag(oids::keyBag, pkcs8, b)); + } + } + } + Bytes auth; + if (!certs_encrypted.empty()) + der::append(auth, content_info_encrypted(der::tlv(der::SEQUENCE, certs_encrypted), enc_alg, iterations, pw)); + if (!certs_plain.empty()) + der::append(auth, content_info_data(der::tlv(der::SEQUENCE, certs_plain))); + if (!keys.empty()) + der::append(auth, content_info_data(der::tlv(der::SEQUENCE, keys))); + Bytes auth_safe = der::tlv(der::SEQUENCE, auth); + + const HashChoice &h = hash_by_digest_oid(safe->alg_oid.mac ? oid_of(safe->alg_oid.mac) : oids::sha1); + Bytes salt = random_bytes(8); + Bytes mac = hmac(h, p12_kdf(h, pw, salt, iterations, 3, digest_size(h.hash)), auth_safe); + Bytes mac_data = der::seq({der::seq({der::seq({der::oid(*h.digest_oid), der::null()}), der::octet_string(mac)}), + der::octet_string(salt), der::integer(iterations)}); + fill_ostr(asn1_out, der::seq({der::integer(3), content_info_data(auth_safe), mac_data})); + return 0; + }); +} + +int pkcs12_decode(OctetString *asn1string, OctetString *password, P12_Safe *safe, Boolean *verified) +{ + return guarded("pkcs12_decode", -1, [&] { + if (!asn1string || !password || !safe) + fail(EINVALID, "missing parameter"); + Bytes pw = bytes_of(password); + Bytes in = bytes_of(asn1string); + der::Reader pfx(der::parse_one(in)); + if (der::get_integer(pfx.next(der::INTEGER)) != 3) + fail(EDECODE, "unsupported PFX version"); + der::Reader ci(pfx.next(der::SEQUENCE)); + if (der::get_oid(ci.next()) != oids::data) + fail(EP12INTMODE, "only password integrity mode is supported"); + Bytes auth_safe = octet_content(der::Reader(ci.next(der::ctx(0))).next()); + + if (verified) + *verified = FALSE; + der::Node mac_node; + if (pfx.next_optional(der::SEQUENCE, mac_node)) { + der::Reader md(mac_node); + der::Reader di(md.next(der::SEQUENCE)); + Oid digest_oid = der::get_oid(der::Reader(di.next(der::SEQUENCE)).next()); + Bytes expected = di.next(der::OCTET_STRING).value(); + Bytes salt = md.next(der::OCTET_STRING).value(); + der::Node it; + int iterations = md.next_optional(der::INTEGER, it) ? int(der::get_integer(it)) : 1; + const HashChoice &h = hash_by_digest_oid(digest_oid); + Bytes mac = hmac(h, p12_kdf(h, pw, salt, iterations, 3, digest_size(h.hash)), auth_safe); + if (mac != expected) + fail(EVERIFY, "PKCS#12 integrity check failed (wrong password?)"); + if (verified) + *verified = TRUE; + safe->alg_oid.mac = new_objid(digest_oid); + keep_lowest(safe, iterations); + } + + safe->version = 3; + der::Reader cis(der::parse_one(auth_safe)); + while (!cis.empty()) { + der::Reader c(cis.next(der::SEQUENCE)); + Oid type = der::get_oid(c.next()); + der::Node content = der::Reader(c.next(der::ctx(0))).next(); + if (type == oids::data) { + parse_safe_contents(octet_content(content), pw, safe, false); + } else if (type == oids::encryptedData) { + der::Reader ed(content); + ed.next(der::INTEGER); + der::Reader eci(ed.next(der::SEQUENCE)); + eci.next(); + Bytes algid = eci.next(der::SEQUENCE).raw(); + der::Node enc = eci.next(); + Bytes ct = enc.tag == der::ctx(0, false) ? enc.value() : octet_content(der::Reader(enc).next()); + Bytes plain = pbe_crypt(algid, pw, ct.data(), ct.size(), false); + if (!safe->alg_oid.enc) + safe->alg_oid.enc = new_objid(der::get_oid(der::Reader(der::parse_one(algid)).next())); + keep_lowest(safe, iterations_of(algid)); + parse_safe_contents(plain, pw, safe, true); + } + } + return 0; + }); +} + +PrivateKeyInfo *aux_create_PrivateKeyInfo(KeyInfo *key, Certificate *cert, SET_OF_Attr *attributes) +{ + return guarded("aux_create_PrivateKeyInfo", nullptr, [&] { + if (!key) + fail(EINVALID, "missing private key"); + if (attributes) + fail(ENOTSUPPORTED, "PKCS#8 attributes are not supported"); + PrivateKeyInfo *p = mem_new(); + try { + if (keyinfo_is_rsa(key)) { + Bytes e; + if (cert && cert->tbs && keyinfo_is_rsa(cert->tbs->subjectPK)) + e = rsa_public_from_keyinfo(cert->tbs->subjectPK).e; + RsaPrivate k = rsa_private_from_keyinfo(key, e); + p->privateKeyAlgorithm = copy_algid(&rsaEncryption_aid); + p->privateKey = new_ostr(rsa_private_key_der(k)); + } else if (keyinfo_is_dsa(key)) { + if (!key->subjectAI->param) + fail(EALGNOTFITKEY, "DSA key without domain parameters"); + p->privateKeyAlgorithm = mem_new(); + p->privateKeyAlgorithm->objid = new_objid(oids::id_dsa); + p->privateKeyAlgorithm->param = copy_keybits(static_cast(key->subjectAI->param)); + p->privateKey = new_ostr(bytes_of(&key->subjectkey)); + } else { + fail(EALGNOTFITKEY, "only RSA and DSA keys can be exported"); + } + return p; + } catch (...) { + free_privatekeyinfo(p); + throw; + } + }); +} + +} // extern "C" diff --git a/port/secude/src/provider.cpp b/port/secude/src/provider.cpp new file mode 100644 index 000000000..089ec3404 --- /dev/null +++ b/port/secude/src/provider.cpp @@ -0,0 +1,65 @@ +// Private OpenSSL library context with the default provider and, if present, +// the legacy provider (MD4, DES, IDEA, RC2, RC4). The application's default +// context is left untouched. Setting SECUDE_COMPAT_NO_LEGACY_PROVIDER forces +// the built-in implementations. +#include "internal.hpp" + +#include +#include + +namespace compat { + +namespace { + +struct Providers { + OSSL_LIB_CTX *ctx = nullptr; + bool legacy = false; + + Providers() + { + ctx = OSSL_LIB_CTX_new(); + if (!ctx) + return; + ERR_set_mark(); + OSSL_PROVIDER_load(ctx, "default"); + const char *off = std::getenv("SECUDE_COMPAT_NO_LEGACY_PROVIDER"); + if (!(off && *off && std::strcmp(off, "0"))) + legacy = OSSL_PROVIDER_load(ctx, "legacy") != nullptr; + ERR_pop_to_mark(); + } +}; + +Providers &providers() +{ + static Providers *p = new Providers; + return *p; +} + +} // namespace + +OSSL_LIB_CTX *libctx() { return providers().ctx; } + +bool legacy_enabled() { return providers().legacy; } + +EVP_MD *fetch_md(const char *name) +{ + ERR_set_mark(); + EVP_MD *md = EVP_MD_fetch(libctx(), name, nullptr); + ERR_pop_to_mark(); + return md; +} + +EVP_CIPHER *fetch_cipher(const char *name) +{ + ERR_set_mark(); + EVP_CIPHER *c = EVP_CIPHER_fetch(libctx(), name, nullptr); + ERR_pop_to_mark(); + return c; +} + +} // namespace compat + +extern "C" int secude_compat_legacy_provider_active(void) +{ + return compat::legacy_enabled() ? 1 : 0; +} diff --git a/port/secude/src/pse.cpp b/port/secude/src/pse.cpp new file mode 100644 index 000000000..ee5d7b738 --- /dev/null +++ b/port/secude/src/pse.cpp @@ -0,0 +1,743 @@ +// Personal Security Environment: a PIN protected key store file. +// +// CompatPSE ::= SEQUENCE { +// format UTF8String "SECUDE-compat PSE", +// version INTEGER (1), +// kdf SEQUENCE { pbkdf2 OID, salt OCTET STRING, iterations INTEGER, hmacWithSHA256 OID }, +// cipher SEQUENCE { aes256-GCM OID, nonce OCTET STRING }, +// ciphertext OCTET STRING } -- AES-256-GCM(PSEContents) || tag, AAD = DER of the fields above +// PSEContents ::= SEQUENCE { flags INTEGER, created Time, objects SEQUENCE OF PSEObject } +// PSEObject ::= SEQUENCE { name UTF8String, type OID, created Time, updated Time, value OCTET STRING } +#include "der.hpp" + +#include +#include + +namespace compat { + +namespace { + +const char kFormat[] = "SECUDE-compat PSE"; +const Oid kAesGcm{2, 16, 840, 1, 101, 3, 4, 1, 46}; +constexpr int kIterations = 100000; + +} // namespace + +struct PseStore { + std::string path; + bool onekeypaironly = true; + std::string created; + std::vector objects; + Bytes salt; + int iterations = kIterations; + Bytes key; + + void derive(const char *pin) + { + key.assign(32, 0); + const char *p = pin ? pin : ""; + if (!PKCS5_PBKDF2_HMAC(p, int(std::strlen(p)), salt.data(), int(salt.size()), iterations, EVP_sha256(), + int(key.size()), key.data())) + fail(EINTERNAL, "key derivation failed"); + } + + Bytes header() const + { + return der::concat({der::string(der::UTF8String, kFormat), der::integer(1), + der::seq({der::oid(oids::pbkdf2), der::octet_string(salt), der::integer(iterations), + der::oid(oids::hmacSHA256)})}); + } + + Bytes contents() const + { + Bytes objs; + for (const auto &o : objects) + der::append(objs, der::seq({der::string(der::UTF8String, o.name), der::oid(o.type), der::time(o.created), + der::time(o.updated), der::octet_string(o.value)})); + return der::seq({der::integer(onekeypaironly ? 1 : 0), der::time(created), der::tlv(der::SEQUENCE, objs)}); + } + + void save() const + { + Bytes plain = contents(); + Bytes nonce = random_bytes(12); + Bytes head = header(); + Bytes cipher_params = der::seq({der::oid(kAesGcm), der::octet_string(nonce)}); + Bytes aad = der::concat({head, cipher_params}); + Bytes ct = aes_gcm(true, nonce, aad, plain); + write_file_atomic(path, der::tlv(der::SEQUENCE, der::concat({aad, der::octet_string(ct)}))); + } + + void load(const char *pin) + { + bool exists = false; + Bytes file = read_file(path, exists); + if (!exists) + fail(EPSENOTEXISTING, "PSE " + path + " does not exist"); + Bytes nonce, ct, aad; + try { + der::Node top = der::parse_one(file); + if (top.tag != der::SEQUENCE) + fail(EPSEFILE); + der::Reader r(top); + der::Node fmt = r.next(der::UTF8String); + if (der::get_string(fmt) != kFormat) + fail(EPSEFILE); + der::Node ver = r.next(der::INTEGER); + if (der::get_integer(ver) != 1) + fail(EPSEFILESTRUCTURE, "unsupported PSE version"); + der::Node kdf = r.next(der::SEQUENCE); + der::Reader kr(kdf); + if (der::get_oid(kr.next()) != oids::pbkdf2) + fail(EPSEFILESTRUCTURE, "unsupported key derivation"); + salt = kr.next(der::OCTET_STRING).value(); + iterations = int(der::get_integer(kr.next(der::INTEGER))); + if (der::get_oid(kr.next()) != oids::hmacSHA256 || iterations < 1) + fail(EPSEFILESTRUCTURE, "unsupported key derivation"); + der::Node cp = r.next(der::SEQUENCE); + der::Reader cr(cp); + if (der::get_oid(cr.next()) != kAesGcm) + fail(EPSEFILESTRUCTURE, "unsupported PSE encryption"); + nonce = cr.next(der::OCTET_STRING).value(); + ct = r.next(der::OCTET_STRING).value(); + r.expect_end(); + aad.assign(fmt.hdr, cp.hdr + cp.total); + } catch (const Error &e) { + if (e.code == EDECODE) + fail(EPSEFILE, path + " is not a PSE of this implementation"); + throw; + } + derive(pin); + Bytes plain = aes_gcm(false, nonce, aad, ct); + der::Node c = der::parse_one(plain); + der::Reader r(c); + onekeypaironly = der::get_integer(r.next(der::INTEGER)) & 1; + created = der::get_time(r.next()); + der::Reader objs(r.next(der::SEQUENCE)); + objects.clear(); + while (!objs.empty()) { + der::Reader o(objs.next(der::SEQUENCE)); + PseObject po; + po.name = der::get_string(o.next(der::UTF8String)); + po.type = der::get_oid(o.next()); + po.created = der::get_time(o.next()); + po.updated = der::get_time(o.next()); + po.value = o.next(der::OCTET_STRING).value(); + objects.push_back(std::move(po)); + } + } + +private: + Bytes aes_gcm(bool encrypt, const Bytes &nonce, const Bytes &aad, const Bytes &in) const + { + EVP_CIPHER *cipher = fetch_cipher("AES-256-GCM"); + if (!cipher) + fail(EINTERNAL, "AES-256-GCM not available"); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + Bytes out(in.size() + 16); + int len = 0, fin = 0; + bool ok = ctx && EVP_CipherInit_ex2(ctx, cipher, nullptr, nullptr, encrypt, nullptr); + size_t data_len = in.size(); + if (!encrypt) { + if (in.size() < 16) + ok = false; + else + data_len -= 16; + } + if (ok) + ok = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, int(nonce.size()), nullptr) && + EVP_CipherInit_ex2(ctx, nullptr, key.data(), nonce.data(), encrypt, nullptr) && + EVP_CipherUpdate(ctx, nullptr, &len, aad.data(), int(aad.size())) && + EVP_CipherUpdate(ctx, out.data(), &len, in.data(), int(data_len)); + if (ok && !encrypt) + ok = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, const_cast(in.data() + data_len)); + if (ok) + ok = EVP_CipherFinal_ex(ctx, out.data() + len, &fin); + if (ok && encrypt) + ok = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, out.data() + len + fin); + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + if (!ok) { + if (!encrypt) + fail(EPIN, "wrong PIN or damaged PSE"); + fail(EINTERNAL, "PSE encryption failed"); + } + out.resize(size_t(len + fin) + (encrypt ? 16 : 0)); + return out; + } +}; + +namespace { + +struct HandleData { + std::shared_ptr store; +}; + +struct SelData { + std::shared_ptr store; + PSE owner = nullptr; // nullptr: opened by sec_open/sec_create +}; + +struct Registry { + std::mutex lock; + std::map handles; + std::map sels; +}; + +Registry ®() +{ + static Registry *r = new Registry; + return *r; +} + +std::shared_ptr open_store(const char *path, const char *pin) +{ + if (!path || !*path) + fail(EINVALID, "missing PSE name"); + auto s = std::make_shared(); + s->path = path; + s->load(pin); + return s; +} + +std::shared_ptr create_store(const char *path, const char *pin, bool onekeypaironly) +{ + if (!path || !*path) + fail(EINVALID, "missing PSE name"); + bool exists = false; + read_file(path, exists); + if (exists) + fail(EPSEALREADYEXISTING, std::string("PSE ") + path + " already exists"); + auto s = std::make_shared(); + s->path = path; + s->onekeypaironly = onekeypaironly; + s->created = utc_now(); + s->salt = random_bytes(16); + s->derive(pin); + s->save(); + return s; +} + +PSE new_handle(const std::shared_ptr &store, const char *psename, const char *cadir) +{ + AF_ctx *ctx = mem_new(); + AF_options defaults = AF_DEF_OPTIONS; + ctx->options = defaults; + ctx->onekeypaironly = store->onekeypaironly; + ctx->pse_name = mem_strdup(psename); + ctx->ca_dir = mem_strdup(cadir); + Registry &r = reg(); + std::lock_guard g(r.lock); + r.handles[ctx].store = store; + return ctx; +} + +PSESel *new_sel(const std::shared_ptr &store, PSE owner) +{ + PSESel *sel = mem_new(); + Registry &r = reg(); + std::lock_guard g(r.lock); + r.sels[sel] = SelData{store, owner}; + return sel; +} + +void destroy_sel(PSESel *sel) +{ + mem_free(sel->object); + aux_free_ObjId(&sel->object_type); + mem_free(sel); +} + +bool is_static_objid(const ObjId *o) +{ + return o && !mem_owned(o); +} + +std::string object_name_for(const char *name, const ObjId *type) +{ + if (name && *name) + return name; + if (const char *n = pse_object_name(type)) + return n; + fail(EOBJNAME, "missing PSE object name"); +} + +Oid object_type_for(const std::string &name, const ObjId *type) +{ + if (type && type->oid_nelem > 0) + return oid_of(type); + if (const ObjId *o = pse_object_oid(name.c_str())) + return oid_of(o); + return oid_of(&Uid_oid); +} + +bool type_in(const Oid &t, std::initializer_list list) +{ + for (const ObjId *o : list) + if (t == oid_of(o)) + return true; + return false; +} + +bool is_cert_type(const Oid &t) { return type_in(t, {&Cert_oid, &SignCert_oid, &EncCert_oid, &AuthCert_oid}); } + +bool is_key_type(const Oid &t) +{ + return type_in(t, {&SKnew_oid, &SKold_oid, &SignSK_oid, &DecSKnew_oid, &DecSKold_oid, &AuthSK_oid}); +} + +void *decode_object(const PseObject &o) +{ + if (is_cert_type(o.type)) + return dec_certificate(o.value); + if (is_key_type(o.type)) + return dec_keyinfo(o.value); + if (o.type == oid_of(&PKRoot_oid)) + return dec_pkroot(o.value); + if (o.type == oid_of(&FCPath_oid)) + return dec_fcpath(o.value); + if (o.type == oid_of(&Name_oid)) + return dec_dname(o.value); + return new_ostr(o.value); +} + +Bytes encode_object(const Oid &type, void *opaque) +{ + if (!opaque) + fail(EINVALID, "missing PSE object value"); + if (is_cert_type(type)) + return enc_certificate(static_cast(opaque)); + if (is_key_type(type)) + return enc_keyinfo(static_cast(opaque)); + if (type == oid_of(&PKRoot_oid)) + return enc_pkroot(static_cast(opaque)); + if (type == oid_of(&FCPath_oid)) + return enc_fcpath(static_cast(opaque)); + if (type == oid_of(&Name_oid)) + return enc_dname(static_cast(opaque)); + return bytes_of(static_cast(opaque)); +} + +const PseObject &require(const std::shared_ptr &s, const std::string &name) +{ + const PseObject *o = store_find(s, name); + if (!o) + fail(EPSEOBJECTNOTEXISTING, "PSE object " + name + " does not exist"); + return *o; +} + +Bytes toc_der(const PseStore &s) +{ + Bytes objs; + for (const auto &o : s.objects) + der::append(objs, der::seq({der::string(der::UTF8String, o.name), der::time(o.created), der::time(o.updated), + der::integer(long(o.value.size())), der::integer(0), der::oid(o.type)})); + std::string update = s.created; + for (const auto &o : s.objects) + if (o.updated > update) + update = o.updated; + return der::seq({der::string(der::UTF8String, s.path), der::time(s.created), der::time(update), der::integer(0), + der::tlv(der::SEQUENCE, objs)}); +} + +} // namespace + +std::shared_ptr store_of(PSE pse) +{ + Registry &r = reg(); + std::lock_guard g(r.lock); + auto it = r.handles.find(pse); + if (it == r.handles.end()) + fail(EINVALID, "invalid PSE handle"); + return it->second.store; +} + +std::shared_ptr store_of(PSESel *sel) +{ + Registry &r = reg(); + std::lock_guard g(r.lock); + auto it = r.sels.find(sel); + if (it == r.sels.end()) + fail(EINVALID, "invalid PSE selector"); + return it->second.store; +} + +const PseObject *store_find(const std::shared_ptr &s, const std::string &name) +{ + for (const auto &o : s->objects) + if (o.name == name) + return &o; + return nullptr; +} + +void store_put(const std::shared_ptr &s, const std::string &name, const Oid &type, const Bytes &value) +{ + std::string now = utc_now(); + for (auto &o : s->objects) + if (o.name == name) { + o.type = type; + o.value = value; + o.updated = now; + s->save(); + return; + } + s->objects.push_back(PseObject{name, type, now, now, value}); + s->save(); +} + +bool store_onekeypaironly(const std::shared_ptr &s) { return s->onekeypaironly; } + +const char *pse_cadir(PSE pse) +{ + store_of(pse); + return pse->ca_dir; +} + +static std::string pick(const std::shared_ptr &s, const char *preferred, const char *fallback) +{ + if (!s->onekeypaironly && store_find(s, preferred)) + return preferred; + return fallback; +} + +std::string private_key_object(PSE pse, KeyType type) +{ + auto s = store_of(pse); + return pick(s, type == SIGNATURE ? SignSK_name : DecSKnew_name, SKnew_name); +} + +std::string certificate_object(PSE pse, KeyType type) +{ + auto s = store_of(pse); + return pick(s, type == SIGNATURE ? SignCert_name : EncCert_name, Cert_name); +} + +KeyInfo *read_private_key(PSE pse, KeyType type) +{ + auto s = store_of(pse); + return dec_keyinfo(require(s, private_key_object(pse, type)).value); +} + +Bytes rsa_exponent_hint(PSE pse, const KeyInfo *priv) +{ + if (!keyinfo_is_rsa(priv)) + return {}; + auto s = store_of(pse); + for (const char *name : {Cert_name, SignCert_name, EncCert_name}) { + const PseObject *o = store_find(s, name); + if (!o) + continue; + try { + Certificate *c = dec_certificate(o->value); + Bytes e; + try { + RsaPublic pub = rsa_public_from_keyinfo(c->tbs->subjectPK); + RsaPrivate k = rsa_private_from_keyinfo(priv, pub.e); + if (k.n == pub.n) + e = pub.e; + } catch (const Error &) { + } + free_certificate(c); + if (!e.empty()) + return e; + } catch (const Error &) { + } + } + return {}; +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +PSE af_create(char *psename, char *cadir, char *pin, SC_DATA *sc_data, Boolean onekeypaironly) +{ + return guarded("af_create", nullptr, [&] { + return new_handle(create_store(psename, pin, onekeypaironly != 0), psename, cadir); + }); +} + +PSE af_open(char *psename, char *cadir, char *pin, SC_DATA *sc_data) +{ + return guarded("af_open", nullptr, [&] { return new_handle(open_store(psename, pin), psename, cadir); }); +} + +RC af_close(PSE pse_handle) +{ + return guarded("af_close", -1, [&] { + Registry &r = reg(); + std::vector sels; + { + std::lock_guard g(r.lock); + if (!r.handles.erase(pse_handle)) + fail(EINVALID, "invalid PSE handle"); + for (auto it = r.sels.begin(); it != r.sels.end();) { + if (it->second.owner == pse_handle) { + sels.push_back(it->first); + it = r.sels.erase(it); + } else { + ++it; + } + } + } + for (PSESel *s : sels) + destroy_sel(s); + mem_free(pse_handle->pse_name); + mem_free(pse_handle->ca_dir); + mem_free(pse_handle); + return 0; + }); +} + +PSESel *af_get_PSESel(PSE pse_hdl, ObjId *af_object) +{ + return guarded("af_get_PSESel", nullptr, [&] { + PSESel *sel = new_sel(store_of(pse_hdl), pse_hdl); + if (const char *name = pse_object_name(af_object)) { + sel->object = mem_strdup(name); + sel->object_type = copy_objid(af_object); + } + return sel; + }); +} + +RC af_get_options(PSE pse, AF_options *options) +{ + return guarded("af_get_options", -1, [&] { + store_of(pse); + if (!options) + fail(EINVALID, "missing options"); + *options = pse->options; + return 0; + }); +} + +PSESel *sec_create(char *psename, char *pin, SC_DATA *sc_data, Boolean onekeypaironly) +{ + return guarded("sec_create", nullptr, [&] { return new_sel(create_store(psename, pin, onekeypaironly != 0), nullptr); }); +} + +PSESel *sec_open(char *pse_name, char *pin, SC_DATA *sc_data) +{ + return guarded("sec_open", nullptr, [&] { return new_sel(open_store(pse_name, pin), nullptr); }); +} + +static RC release_sel(PSESel *pse_sel) +{ + Registry &r = reg(); + { + std::lock_guard g(r.lock); + if (!r.sels.erase(pse_sel)) + return -1; + } + destroy_sel(pse_sel); + return 0; +} + +RC sec_close(PSESel *pse_sel) +{ + if (release_sel(pse_sel) < 0) { + push_error(EINVALID, "sec_close", "invalid PSE selector"); + return -1; + } + return 0; +} + +void aux_free_PSESel(PSESel **pse_sel) +{ + if (!pse_sel || !*pse_sel) + return; + if (release_sel(*pse_sel) < 0 && mem_owned(*pse_sel)) + destroy_sel(*pse_sel); + *pse_sel = nullptr; +} + +int sec_onekeypaironly(PSESel *pse_sel) +{ + return guarded("sec_onekeypaironly", 0, [&] { return store_onekeypaironly(store_of(pse_sel)) ? TRUE : FALSE; }); +} + +int sec_write_PSE(PSESel *pse_sel, OctetString *value) +{ + return guarded("sec_write_PSE", -1, [&] { + auto s = store_of(pse_sel); + std::string name = object_name_for(pse_sel->object, pse_sel->object_type); + if (!value) + fail(EINVALID, "missing value"); + store_put(s, name, object_type_for(name, pse_sel->object_type), bytes_of(value)); + return 0; + }); +} + +RC sec_read_PSE(PSESel *pse_sel, OctetString *value) +{ + return guarded("sec_read_PSE", -1, [&] { + auto s = store_of(pse_sel); + std::string name = object_name_for(pse_sel->object, pse_sel->object_type); + const PseObject &o = require(s, name); + if (pse_sel->object_type && pse_sel->object_type->oid_nelem > 0 && oid_of(pse_sel->object_type) != o.type && + !oid_equal(pse_sel->object_type, &Uid_oid)) + fail(EOBJ, "PSE object " + name + " has a different type"); + if (!value) + fail(EINVALID, "missing value"); + fill_ostr(value, o.value); + return 0; + }); +} + +RC sec_write(PSESel *pse_sel, OctetString *content) +{ + return guarded("sec_write", -1, [&] { + auto s = store_of(pse_sel); + std::string name = object_name_for(pse_sel->object, pse_sel->object_type); + if (!content) + fail(EINVALID, "missing content"); + const PseObject *existing = store_find(s, name); + Oid type = existing && !(pse_sel->object_type && pse_sel->object_type->oid_nelem > 0) + ? existing->type + : object_type_for(name, pse_sel->object_type); + store_put(s, name, type, bytes_of(content)); + return 0; + }); +} + +RC sec_read(PSESel *pse_sel, OctetString *content) +{ + return guarded("sec_read", -1, [&] { + auto s = store_of(pse_sel); + if (!content) + fail(EINVALID, "missing content"); + if (pse_sel->object && !std::strcmp(pse_sel->object, Toc_name)) { + fill_ostr(content, toc_der(*s)); + return 0; + } + fill_ostr(content, require(s, object_name_for(pse_sel->object, pse_sel->object_type)).value); + return 0; + }); +} + +PSEToc *d_PSEToc(OctetString *asn1_string) +{ + return guarded("d_PSEToc", nullptr, [&] { + Bytes in = bytes_of(asn1_string); + der::Node top = der::parse_one(in); + if (top.tag != der::SEQUENCE) + fail(EDECODE, "PSE table of contents expected"); + PSEToc *t = mem_new(); + try { + der::Reader r(top); + t->owner = mem_strdup(der::get_string(r.next(der::UTF8String))); + t->create = mem_strdup(der::get_time(r.next())); + t->update = mem_strdup(der::get_time(r.next())); + t->status = unsigned(der::get_integer(r.next(der::INTEGER))); + der::Reader objs(r.next(der::SEQUENCE)); + PSEObjects **tail = &t->obj; + while (!objs.empty()) { + der::Reader o(objs.next(der::SEQUENCE)); + PSEObjects *po = mem_new(); + *tail = po; + tail = &po->next; + po->name = mem_strdup(der::get_string(o.next(der::UTF8String))); + po->create = mem_strdup(der::get_time(o.next())); + po->update = mem_strdup(der::get_time(o.next())); + po->noOctets = int(der::get_integer(o.next(der::INTEGER))); + po->status = unsigned(der::get_integer(o.next(der::INTEGER))); + po->objType = new_objid(der::get_oid(o.next())); + } + return t; + } catch (...) { + aux_free_PSEToc(&t); + throw; + } + }); +} + +void *af_pse_get(PSE pse_handle, char *objname, ObjId *objtype) +{ + return guarded("af_pse_get", nullptr, [&] { + auto s = store_of(pse_handle); + if (!objname) + fail(EOBJNAME, "missing PSE object name"); + const PseObject &o = require(s, objname); + void *result = decode_object(o); + if (objtype && !is_static_objid(objtype)) + fill_objid(objtype, o.type); + return result; + }); +} + +RC af_pse_update(PSE pse_handle, char *objname, void *opaque, ObjId *opaque_type) +{ + return guarded("af_pse_update", -1, [&] { + auto s = store_of(pse_handle); + std::string name = object_name_for(objname, opaque_type); + Oid type = object_type_for(name, opaque_type); + store_put(s, name, type, encode_object(type, opaque)); + return 0; + }); +} + +DName *af_pse_get_Name(PSE pse_handle) +{ + return guarded("af_pse_get_Name", nullptr, [&]() -> DName * { + auto s = store_of(pse_handle); + if (const PseObject *o = store_find(s, "Name")) + return dec_dname(o->value); + const PseObject &c = require(s, certificate_object(pse_handle, SIGNATURE)); + Certificate *cert = dec_certificate(c.value); + DName *d = copy_dname(cert->tbs->subject); + free_certificate(cert); + return d; + }); +} + +SerialNumber *af_pse_get_SerialNumber(PSE pse_handle) +{ + return guarded("af_pse_get_SerialNumber", nullptr, [&] { + return new_ostr(require(store_of(pse_handle), SerialNumber_name).value); + }); +} + +RC af_pse_update_SerialNumber(PSE pse_handle, SerialNumber *serial) +{ + return guarded("af_pse_update_SerialNumber", -1, [&] { + if (!serial || !serial->noctets) + fail(EINVALID, "missing serial number"); + store_put(store_of(pse_handle), SerialNumber_name, oid_of(&SerialNumber_oid), bytes_of(serial)); + return 0; + }); +} + +PKRoot *af_pse_get_PKRoot(PSE pse_handle) +{ + return guarded("af_pse_get_PKRoot", nullptr, [&] { + return dec_pkroot(require(store_of(pse_handle), PKRoot_name).value); + }); +} + +int af_pse_update_PKRoot(PSE pse_handle, PKRoot *pkroot) +{ + return guarded("af_pse_update_PKRoot", -1, [&] { + store_put(store_of(pse_handle), PKRoot_name, oid_of(&PKRoot_oid), enc_pkroot(pkroot)); + return 0; + }); +} + +FCPath *af_pse_get_FCPath(PSE pse_handle, DName *name) +{ + return guarded("af_pse_get_FCPath", nullptr, [&] { + return dec_fcpath(require(store_of(pse_handle), FCPath_name).value); + }); +} + +CrlSet *af_pse_get_CrlSet(PSE pse_handle) +{ + return guarded("af_pse_get_CrlSet", nullptr, [&]() -> CrlSet * { + store_of(pse_handle); + fail(ENOCRL, "revocation lists are not supported by this implementation"); + }); +} + +} // extern "C" diff --git a/port/secude/src/structs.cpp b/port/secude/src/structs.cpp new file mode 100644 index 000000000..df838ad08 --- /dev/null +++ b/port/secude/src/structs.cpp @@ -0,0 +1,652 @@ +// Deep copy and release of SECUDE structures. +#include "internal.hpp" + +namespace compat { + +namespace { + +ParmType parm_type_of(const ObjId *o) +{ + const AlgInfo *a = alg_by_oid(o); + return a ? a->parm : NoParmType; +} + +void copy_ostr_into(OctetString *dst, const OctetString *src) +{ + fill_ostr(dst, bytes_of(src)); +} + +char *copy_str(const char *s) { return mem_strdup(s); } + +} // namespace + +AlgId *copy_algid(const AlgId *a) +{ + if (!a) + return nullptr; + AlgId *r = mem_new(); + r->objid = copy_objid(a->objid); + if (a->parmoverride) { + r->parmoverride = mem_new(); + *r->parmoverride = *a->parmoverride; + } + if (!a->param) + return r; + switch (parm_type_of(a->objid)) { + case PARM_INTEGER: { + unsigned int *v = mem_new(); + *v = *static_cast(a->param); + r->param = v; + break; + } + case PARM_OctetString: + case NoParmType: + r->param = new_ostr(bytes_of(static_cast(a->param))); + break; + case PARM_KeyBits: + r->param = copy_keybits(static_cast(a->param)); + break; + case PARM_RC2CBC: { + auto *src = static_cast(a->param); + auto *p = mem_new(); + p->version = src->version; + copy_ostr_into(&p->IV, &src->IV); + r->param = p; + break; + } + case PARM_PKCS5: { + auto *src = static_cast(a->param); + auto *p = mem_new(); + p->iterationCount = src->iterationCount; + copy_ostr_into(&p->salt, &src->salt); + r->param = p; + break; + } + default: + break; + } + return r; +} + +void free_algid_content(AlgId *a) +{ + if (!a) + return; + if (a->param && mem_owned(a->param)) { + switch (parm_type_of(a->objid)) { + case PARM_OctetString: + case NoParmType: { + OctetString *o = static_cast(a->param); + aux_free_OctetString(&o); + break; + } + case PARM_KeyBits: { + KeyBits *k = static_cast(a->param); + free_keybits_content(k); + mem_free(k); + break; + } + case PARM_RC2CBC: + aux_free2_OctetString(&static_cast(a->param)->IV); + mem_free(a->param); + break; + case PARM_PKCS5: + aux_free2_OctetString(&static_cast(a->param)->salt); + mem_free(a->param); + break; + default: + mem_free(a->param); + break; + } + a->param = nullptr; + } + ObjId *o = a->objid; + aux_free_ObjId(&o); + a->objid = nullptr; + mem_free(a->parmoverride); + a->parmoverride = nullptr; +} + +void free_algid(AlgId *a) +{ + if (!mem_owned(a)) + return; + if (!a) + return; + free_algid_content(a); + mem_free(a); +} + +KeyBits *copy_keybits(const KeyBits *k) +{ + if (!k) + return nullptr; + KeyBits *r = mem_new(); + copy_ostr_into(&r->part1, &k->part1); + copy_ostr_into(&r->part2, &k->part2); + copy_ostr_into(&r->part3, &k->part3); + copy_ostr_into(&r->part4, &k->part4); + copy_ostr_into(&r->part5, &k->part5); + r->choice = k->choice; + return r; +} + +void free_keybits_content(KeyBits *k) +{ + if (!k) + return; + aux_free2_OctetString(&k->part1); + aux_free2_OctetString(&k->part2); + aux_free2_OctetString(&k->part3); + aux_free2_OctetString(&k->part4); + aux_free2_OctetString(&k->part5); +} + +KeyInfo *copy_keyinfo(const KeyInfo *k) +{ + if (!k) + return nullptr; + KeyInfo *r = mem_new(); + r->subjectAI = copy_algid(k->subjectAI); + fill_bstr(&r->subjectkey, bytes_of(&k->subjectkey), k->subjectkey.nbits); + return r; +} + +void free_keyinfo_content(KeyInfo *k) +{ + if (!k) + return; + free_algid(k->subjectAI); + k->subjectAI = nullptr; + aux_free2_BitString(&k->subjectkey); +} + +void free_keyinfo(KeyInfo *k) +{ + if (!mem_owned(k)) + return; + if (!k) + return; + free_keyinfo_content(k); + mem_free(k); +} + +DName *copy_dname(const DName *d) +{ + DName *head = nullptr, **tail = &head; + for (; d; d = d->next) { + DName *n = mem_new(); + RDName **rtail = &n->element_IF_2; + for (const RDName *r = d->element_IF_2; r; r = r->next) { + RDName *nr = mem_new(); + if (r->member_IF_0) { + AttrValueAssertion *ava = mem_new(); + ava->element_IF_0 = copy_objid(r->member_IF_0->element_IF_0); + if (r->member_IF_0->element_IF_1) + ava->element_IF_1 = new_ostr(bytes_of(r->member_IF_0->element_IF_1)); + ava->attr_encoding = r->member_IF_0->attr_encoding; + nr->member_IF_0 = ava; + } + *rtail = nr; + rtail = &nr->next; + } + *tail = n; + tail = &n->next; + } + return head; +} + +void free_dname(DName *d) +{ + while (d && mem_owned(d)) { + DName *next = d->next; + RDName *r = d->element_IF_2; + while (r) { + RDName *rn = r->next; + if (r->member_IF_0) { + aux_free_ObjId(&r->member_IF_0->element_IF_0); + aux_free_OctetString(&r->member_IF_0->element_IF_1); + mem_free(r->member_IF_0); + } + mem_free(r); + r = rn; + } + mem_free(d); + d = next; + } +} + +Validity *copy_validity(const Validity *v) +{ + if (!v) + return nullptr; + Validity *r = mem_new(); + r->notbefore = copy_str(v->notbefore); + r->notafter = copy_str(v->notafter); + return r; +} + +void free_validity(Validity *v) +{ + if (!mem_owned(v)) + return; + if (!v) + return; + mem_free(v->notbefore); + mem_free(v->notafter); + mem_free(v); +} + +Signature *copy_signature(const Signature *s) +{ + if (!s) + return nullptr; + Signature *r = mem_new(); + r->signAI = copy_algid(s->signAI); + fill_bstr(&r->signature, bytes_of(&s->signature), s->signature.nbits); + return r; +} + +void free_signature(Signature *s) +{ + if (!mem_owned(s)) + return; + if (!s) + return; + free_algid(s->signAI); + aux_free2_BitString(&s->signature); + mem_free(s); +} + +CertExtensions *copy_extensions(const CertExtensions *e) +{ + if (!e) + return nullptr; + CertExtensions *r = mem_new(); + SEQUENCE_OF_Extension **tail = &r->nonSupported; + for (const SEQUENCE_OF_Extension *s = e->nonSupported; s; s = s->next) { + if (!s->element) + continue; + auto *n = mem_new(); + n->element = mem_new(); + n->element->extnId = copy_objid(s->element->extnId); + n->element->critical = s->element->critical; + if (s->element->extnDERcode) + n->element->extnDERcode = new_ostr(bytes_of(s->element->extnDERcode)); + n->element->seqnum = s->element->seqnum; + *tail = n; + tail = &n->next; + } + return r; +} + +void free_extensions(CertExtensions *e) +{ + if (!mem_owned(e)) + return; + if (!e) + return; + SEQUENCE_OF_Extension *s = e->nonSupported; + while (s) { + SEQUENCE_OF_Extension *next = s->next; + if (s->element) { + aux_free_ObjId(&s->element->extnId); + aux_free_OctetString(&s->element->extnDERcode); + mem_free(s->element); + } + mem_free(s); + s = next; + } + mem_free(e); +} + +ToBeSigned *copy_tbs(const ToBeSigned *t) +{ + if (!t) + return nullptr; + ToBeSigned *r = mem_new(); + r->version = t->version; + if (t->serialnumber) + r->serialnumber = new_ostr(bytes_of(t->serialnumber)); + r->signatureAI = copy_algid(t->signatureAI); + r->issuer = copy_dname(t->issuer); + r->valid = copy_validity(t->valid); + r->subject = copy_dname(t->subject); + r->subjectPK = copy_keyinfo(t->subjectPK); + if (t->issuerUId) + r->issuerUId = new_bstr(bytes_of(t->issuerUId), t->issuerUId->nbits); + if (t->subjectUId) + r->subjectUId = new_bstr(bytes_of(t->subjectUId), t->subjectUId->nbits); + r->extensions = copy_extensions(t->extensions); + return r; +} + +void free_tbs(ToBeSigned *t) +{ + if (!mem_owned(t)) + return; + if (!t) + return; + aux_free_OctetString(&t->serialnumber); + free_algid(t->signatureAI); + free_dname(t->issuer); + free_validity(t->valid); + free_dname(t->subject); + free_keyinfo(t->subjectPK); + aux_free_BitString(&t->issuerUId); + aux_free_BitString(&t->subjectUId); + free_extensions(t->extensions); + mem_free(t); +} + +Certificate *copy_certificate(const Certificate *c) +{ + if (!c) + return nullptr; + Certificate *r = mem_new(); + if (c->tbs_DERcode) + r->tbs_DERcode = new_ostr(bytes_of(c->tbs_DERcode)); + r->tbs = copy_tbs(c->tbs); + r->sig = copy_signature(c->sig); + return r; +} + +void free_certificate(Certificate *c) +{ + if (!mem_owned(c)) + return; + if (!c) + return; + aux_free_OctetString(&c->tbs_DERcode); + free_tbs(c->tbs); + free_signature(c->sig); + mem_free(c); +} + +FCPath *copy_fcpath(const FCPath *f) +{ + FCPath *head = nullptr, **tail = &head; + for (; f; f = f->next_forwardpath) { + FCPath *n = mem_new(); + SET_OF_Certificate **ctail = &n->liste; + for (const SET_OF_Certificate *s = f->liste; s; s = s->next) { + if (!s->element) + continue; + auto *e = mem_new(); + e->element = copy_certificate(s->element); + *ctail = e; + ctail = &e->next; + } + *tail = n; + tail = &n->next_forwardpath; + } + return head; +} + +void free_fcpath(FCPath *f) +{ + while (f && mem_owned(f)) { + FCPath *next = f->next_forwardpath; + SET_OF_Certificate *s = f->liste; + while (s) { + SET_OF_Certificate *sn = s->next; + free_certificate(s->element); + mem_free(s); + s = sn; + } + mem_free(f); + f = next; + } +} + +static Serial *copy_serial(const Serial *s) +{ + if (!s) + return nullptr; + Serial *r = mem_new(); + if (s->serial) + r->serial = new_ostr(bytes_of(s->serial)); + r->version = s->version; + r->key = copy_keyinfo(s->key); + r->valid = copy_validity(s->valid); + r->sig = copy_signature(s->sig); + return r; +} + +void free_serial(Serial *s) +{ + if (!mem_owned(s)) + return; + if (!s) + return; + aux_free_OctetString(&s->serial); + free_keyinfo(s->key); + free_validity(s->valid); + free_signature(s->sig); + mem_free(s); +} + +PKRoot *copy_pkroot(const PKRoot *p) +{ + if (!p) + return nullptr; + PKRoot *r = mem_new(); + r->ca = copy_dname(p->ca); + r->newkey = copy_serial(p->newkey); + r->oldkey = copy_serial(p->oldkey); + r->extensions = copy_extensions(p->extensions); + return r; +} + +void free_pkroot(PKRoot *p) +{ + if (!mem_owned(p)) + return; + if (!p) + return; + free_dname(p->ca); + free_serial(p->newkey); + free_serial(p->oldkey); + free_extensions(p->extensions); + mem_free(p); +} + +void free_privatekeyinfo(PrivateKeyInfo *p) +{ + if (!mem_owned(p)) + return; + if (!p) + return; + free_algid(p->privateKeyAlgorithm); + aux_free_OctetString(&p->privateKey); + mem_free(p); +} + +} // namespace compat + +using namespace compat; + +extern "C" { + +AlgId *aux_cpy_AlgId(AlgId *aid) +{ + return guarded("aux_cpy_AlgId", nullptr, [&] { return copy_algid(aid); }); +} + +int aux_cpy2_AlgId(AlgId *dup_aid, AlgId *aid) +{ + return guarded("aux_cpy2_AlgId", -1, [&] { + if (!dup_aid || !aid) + fail(EINVALID, "missing algorithm identifier"); + AlgId *c = copy_algid(aid); + *dup_aid = *c; + mem_free(c); + return 0; + }); +} + +void aux_free2_AlgId(AlgId *algid) { free_algid_content(algid); } + +void aux_free_AlgId(AlgId **aid) +{ + if (!aid || !*aid) + return; + if (!mem_owned(*aid)) { + *aid = nullptr; + return; + } + free_algid(*aid); + *aid = nullptr; +} + +void aux_free2_KeyBits(KeyBits *p) { free_keybits_content(p); } + +void aux_free_KeyBits(KeyBits **kb) +{ + if (!kb || !*kb) + return; + if (!mem_owned(*kb)) { + *kb = nullptr; + return; + } + free_keybits_content(*kb); + mem_free(*kb); + *kb = nullptr; +} + +void aux_free2_KeyInfo(KeyInfo *p) { free_keyinfo_content(p); } + +void aux_free_KeyInfo(KeyInfo **ki) +{ + if (!ki || !*ki) + return; + if (!mem_owned(*ki)) { + *ki = nullptr; + return; + } + free_keyinfo(*ki); + *ki = nullptr; +} + +void aux_free_DName(DName **dn) +{ + if (!dn || !*dn) + return; + if (!mem_owned(*dn)) { + *dn = nullptr; + return; + } + free_dname(*dn); + *dn = nullptr; +} + +void aux_free_Certificate(Certificate **cert) +{ + if (!cert || !*cert) + return; + if (!mem_owned(*cert)) { + *cert = nullptr; + return; + } + free_certificate(*cert); + *cert = nullptr; +} + +void aux_free_Certificates(Certificates **to_be_freed) +{ + if (!to_be_freed || !*to_be_freed) + return; + if (!mem_owned(*to_be_freed)) { + *to_be_freed = nullptr; + return; + } + free_certificate((*to_be_freed)->usercertificate); + free_fcpath((*to_be_freed)->forwardpath); + mem_free(*to_be_freed); + *to_be_freed = nullptr; +} + +void aux_free_FCPath(FCPath **path) +{ + if (!path || !*path) + return; + if (!mem_owned(*path)) { + *path = nullptr; + return; + } + free_fcpath(*path); + *path = nullptr; +} + +void aux_free_PKRoot(PKRoot **pkroot) +{ + if (!pkroot || !*pkroot) + return; + if (!mem_owned(*pkroot)) { + *pkroot = nullptr; + return; + } + free_pkroot(*pkroot); + *pkroot = nullptr; +} + +void aux_free_RSAPrivateKey(RSAPrivateKey **privkey) +{ + if (!privkey || !*privkey) + return; + if (!mem_owned(*privkey)) { + *privkey = nullptr; + return; + } + RSAPrivateKey *k = *privkey; + for (OctetString *o : {&k->modulus, &k->pubex, &k->privex, &k->prime1, &k->prime2, &k->exp1, &k->exp2, &k->coeff}) + aux_free2_OctetString(o); + mem_free(k); + *privkey = nullptr; +} + +void aux_free_SET_OF_IssuedCertificate(SET_OF_IssuedCertificate **isscertset) +{ + if (!isscertset) + return; + SET_OF_IssuedCertificate *s = *isscertset; + while (s && mem_owned(s)) { + SET_OF_IssuedCertificate *next = s->next; + if (s->element) { + aux_free_OctetString(&s->element->serial); + mem_free(s->element->date_of_issue); + mem_free(s->element); + } + mem_free(s); + s = next; + } + *isscertset = nullptr; +} + +void aux_free_PSEToc(PSEToc **toc) +{ + if (!toc || !*toc) + return; + if (!mem_owned(*toc)) { + *toc = nullptr; + return; + } + PSEToc *t = *toc; + mem_free(t->owner); + mem_free(t->create); + mem_free(t->update); + PSEObjects *o = t->obj; + while (o) { + PSEObjects *next = o->next; + mem_free(o->name); + mem_free(o->create); + mem_free(o->update); + aux_free_ObjId(&o->objType); + mem_free(o); + o = next; + } + mem_free(t); + *toc = nullptr; +} + +} // extern "C" diff --git a/port/secude/src/symbols.cpp b/port/secude/src/symbols.cpp new file mode 100644 index 000000000..2659dedd3 --- /dev/null +++ b/port/secude/src/symbols.cpp @@ -0,0 +1,241 @@ +// Name -> address table of all SECUDE functions and data objects used by +// CrypTool (the DoAll list in CrypTool/SecudeLib.h) and libec. +#include "internal.hpp" + +namespace { + +struct Symbol { + const char *name; + void *address; +}; + +const std::vector &symbols() +{ + static const std::vector table = { + {"SECUDE_HasValidTicket", reinterpret_cast(&SECUDE_HasValidTicket)}, + {"light_version", reinterpret_cast(&light_version)}, + {"aux_sprint_version", reinterpret_cast(&aux_sprint_version)}, + {"aux_sxdump2", reinterpret_cast(&aux_sxdump2)}, + {"aux_sxdump", reinterpret_cast(&aux_sxdump)}, + {"d_KeyBits", reinterpret_cast(&d_KeyBits)}, + {"af_cadb_add_Certificate", reinterpret_cast(&af_cadb_add_Certificate)}, + {"aux_free_OctetString", reinterpret_cast(&aux_free_OctetString)}, + {"aux_alloc_OctetString", reinterpret_cast(&aux_alloc_OctetString)}, + {"sec_verify_all", reinterpret_cast(&sec_verify_all)}, + {"arithmetic_comp", reinterpret_cast(&arithmetic_comp)}, + {"af_cadb_list_user", reinterpret_cast(&af_cadb_list_user)}, + {"af_pse_get", reinterpret_cast(&af_pse_get)}, + {"af_pse_update", reinterpret_cast(&af_pse_update)}, + {"af_pse_update_SerialNumber", reinterpret_cast(&af_pse_update_SerialNumber)}, + {"e_OctetString", reinterpret_cast(&e_OctetString)}, + {"lngtouse", reinterpret_cast(&lngtouse)}, + {"aux_OctetString2LN2", reinterpret_cast(&aux_OctetString2LN2)}, + {"d_OctetString", reinterpret_cast(&d_OctetString)}, + {"aux_free_DName", reinterpret_cast(&aux_free_DName)}, + {"aux_OctetString2file", reinterpret_cast(&aux_OctetString2file)}, + {"af_certify", reinterpret_cast(&af_certify)}, + {"af_create_Certificate", reinterpret_cast(&af_create_Certificate)}, + {"aux_Name2DName", reinterpret_cast(&aux_Name2DName)}, + {"af_gen_key", reinterpret_cast(&af_gen_key)}, + {"sec_encrypt_all", reinterpret_cast(&sec_encrypt_all)}, + {"sec_decrypt_all", reinterpret_cast(&sec_decrypt_all)}, + {"arithmetic_mexp", reinterpret_cast(&arithmetic_mexp)}, + {"arithmetic_shift", reinterpret_cast(&arithmetic_shift)}, + {"aux_OString2BString", reinterpret_cast(&aux_OString2BString)}, + {"aux_BitString2LN2", reinterpret_cast(&aux_BitString2LN2)}, + {"arithmetic_sub", reinterpret_cast(&arithmetic_sub)}, + {"rndm", reinterpret_cast(&rndm)}, + {"arithmetic_msub", reinterpret_cast(&arithmetic_msub)}, + {"arithmetic_mdiv", reinterpret_cast(&arithmetic_mdiv)}, + {"arithmetic_mmult", reinterpret_cast(&arithmetic_mmult)}, + {"arithmetic_madd", reinterpret_cast(&arithmetic_madd)}, + {"arithmetic_div", reinterpret_cast(&arithmetic_div)}, + {"arithmetic_mult", reinterpret_cast(&arithmetic_mult)}, + {"arithmetic_add", reinterpret_cast(&arithmetic_add)}, + {"sec_hash_all", reinterpret_cast(&sec_hash_all)}, + {"sec_hash_init", reinterpret_cast(&sec_hash_init)}, + {"sec_hash_more", reinterpret_cast(&sec_hash_more)}, + {"sec_hash_end", reinterpret_cast(&sec_hash_end)}, + {"aux_sprint_Certificate", reinterpret_cast(&aux_sprint_Certificate)}, + {"aux_sprint_error", reinterpret_cast(&aux_sprint_error)}, + {"aux_LN2OctetString", reinterpret_cast(&aux_LN2OctetString)}, + {"af_create", reinterpret_cast(&af_create)}, + {"sec_create", reinterpret_cast(&sec_create)}, + {"af_cadb_get_Certificate", reinterpret_cast(&af_cadb_get_Certificate)}, + {"aux_BString2OString", reinterpret_cast(&aux_BString2OString)}, + {"aux_free_Certificate", reinterpret_cast(&aux_free_Certificate)}, + {"aux_free_Certificates", reinterpret_cast(&aux_free_Certificates)}, + {"d_ContentInfo", reinterpret_cast(&d_ContentInfo)}, + {"aux_free_SET_OF_IssuedCertificate", reinterpret_cast(&aux_free_SET_OF_IssuedCertificate)}, + {"af_close", reinterpret_cast(&af_close)}, + {"sec_close", reinterpret_cast(&sec_close)}, + {"af_encrypt_all", reinterpret_cast(&af_encrypt_all)}, + {"af_cadb_get_user", reinterpret_cast(&af_cadb_get_user)}, + {"th_get_last_error_text", reinterpret_cast(&th_get_last_error_text)}, + {"th_last_error", reinterpret_cast(&th_last_error)}, + {"af_open", reinterpret_cast(&af_open)}, + {"aux_file2OctetString", reinterpret_cast(&aux_file2OctetString)}, + {"sdumpasn", reinterpret_cast(&sdumpasn)}, + {"aux_adump", reinterpret_cast(&aux_adump)}, + {"af_pse_get_Name", reinterpret_cast(&af_pse_get_Name)}, + {"aux_DName2Attr", reinterpret_cast(&aux_DName2Attr)}, + {"af_pse_get_SerialNumber", reinterpret_cast(&af_pse_get_SerialNumber)}, + {"af_pse_get_Certificates", reinterpret_cast(&af_pse_get_Certificates)}, + {"af_pse_get_CrlSet", reinterpret_cast(&af_pse_get_CrlSet)}, + {"d_PSEToc", reinterpret_cast(&d_PSEToc)}, + {"af_decrypt_all", reinterpret_cast(&af_decrypt_all)}, + {"af_sign_all", reinterpret_cast(&af_sign_all)}, + {"aux_free", reinterpret_cast(&aux_free)}, + {"th_remove_last_error", reinterpret_cast(&th_remove_last_error)}, + {"aux_free_BitString", reinterpret_cast(&aux_free_BitString)}, + {"aux_free_AlgId", reinterpret_cast(&aux_free_AlgId)}, + {"aux_free_KeyInfo", reinterpret_cast(&aux_free_KeyInfo)}, + {"aux_free_ObjId", reinterpret_cast(&aux_free_ObjId)}, + {"aux_free_KeyBits", reinterpret_cast(&aux_free_KeyBits)}, + {"aux_free_PSEToc", reinterpret_cast(&aux_free_PSEToc)}, + {"aux_cpy_ObjId", reinterpret_cast(&aux_cpy_ObjId)}, + {"aux_cpy_String", reinterpret_cast(&aux_cpy_String)}, + {"aux_free_String", reinterpret_cast(&aux_free_String)}, + {"sec_onekeypaironly", reinterpret_cast(&sec_onekeypaironly)}, + {"af_get_PSESel", reinterpret_cast(&af_get_PSESel)}, + {"aux_latin1_to_unicode", reinterpret_cast(&aux_latin1_to_unicode)}, + {"aux_calloc", reinterpret_cast(&aux_calloc)}, + {"aux_malloc", reinterpret_cast(&aux_malloc)}, + {"aux_cpy_OctetString", reinterpret_cast(&aux_cpy_OctetString)}, + {"aux_create_PrivateKeyInfo", reinterpret_cast(&aux_create_PrivateKeyInfo)}, + {"af_pse_get_FCPath", reinterpret_cast(&af_pse_get_FCPath)}, + {"aux_free_FCPath", reinterpret_cast(&aux_free_FCPath)}, + {"af_pse_get_PKRoot", reinterpret_cast(&af_pse_get_PKRoot)}, + {"af_PKRoot2Protocert", reinterpret_cast(&af_PKRoot2Protocert)}, + {"aux_free_PKRoot", reinterpret_cast(&aux_free_PKRoot)}, + {"aux_free_RSAPrivateKey", reinterpret_cast(&aux_free_RSAPrivateKey)}, + {"pkcs12_encode", reinterpret_cast(&pkcs12_encode)}, + {"aux_free_error", reinterpret_cast(&aux_free_error)}, + {"af_pse_update_PKRoot", reinterpret_cast(&af_pse_update_PKRoot)}, + {"aux_cmp_DName", reinterpret_cast(&aux_cmp_DName)}, + {"aux_create_PKRoot", reinterpret_cast(&aux_create_PKRoot)}, + {"sec_write_PSE", reinterpret_cast(&sec_write_PSE)}, + {"e_FCPath", reinterpret_cast(&e_FCPath)}, + {"e_Certificate", reinterpret_cast(&e_Certificate)}, + {"aux_ObjId2AlgEnc", reinterpret_cast(&aux_ObjId2AlgEnc)}, + {"d_RSAPrivateKey", reinterpret_cast(&d_RSAPrivateKey)}, + {"e_KeyBits", reinterpret_cast(&e_KeyBits)}, + {"aux_cpy_AlgId", reinterpret_cast(&aux_cpy_AlgId)}, + {"e_KeyInfo", reinterpret_cast(&e_KeyInfo)}, + {"e_PKRoot", reinterpret_cast(&e_PKRoot)}, + {"pkcs12_decode", reinterpret_cast(&pkcs12_decode)}, + {"af_pse_get_Certificate", reinterpret_cast(&af_pse_get_Certificate)}, + {"aux_DName2Name", reinterpret_cast(&aux_DName2Name)}, + {"aux_sprint_AlgId", reinterpret_cast(&aux_sprint_AlgId)}, + {"e_PrintableString", reinterpret_cast(&e_PrintableString)}, + {"d_PrintableString", reinterpret_cast(&d_PrintableString)}, + {"aux_cmp_ObjId", reinterpret_cast(&aux_cmp_ObjId)}, + {"af_get_objoid", reinterpret_cast(&af_get_objoid)}, + {"af_pse_get_keysize", reinterpret_cast(&af_pse_get_keysize)}, + {"sec_write", reinterpret_cast(&sec_write)}, + {"sec_read", reinterpret_cast(&sec_read)}, + {"sec_read_PSE", reinterpret_cast(&sec_read_PSE)}, + {"d_KeyInfo", reinterpret_cast(&d_KeyInfo)}, + {"aux_Name2AlgId", reinterpret_cast(&aux_Name2AlgId)}, + {"af_get_options", reinterpret_cast(&af_get_options)}, + {"aux_cpy2_AlgId", reinterpret_cast(&aux_cpy2_AlgId)}, + {"aux_free2_AlgId", reinterpret_cast(&aux_free2_AlgId)}, + {"aux_cpy2_ObjId", reinterpret_cast(&aux_cpy2_ObjId)}, + {"aux_free2_BitString", reinterpret_cast(&aux_free2_BitString)}, + {"aux_free_PSESel", reinterpret_cast(&aux_free_PSESel)}, + {"e_AlgId", reinterpret_cast(&e_AlgId)}, + {"rsa_sign_all", reinterpret_cast(&rsa_sign_all)}, + {"sec_get_key", reinterpret_cast(&sec_get_key)}, + {"sec_open", reinterpret_cast(&sec_open)}, + {"d_Certificate", reinterpret_cast(&d_Certificate)}, + {"aux_free2_KeyBits", reinterpret_cast(&aux_free2_KeyBits)}, + {"aux_free2_KeyInfo", reinterpret_cast(&aux_free2_KeyInfo)}, + {"aux_free2_OctetString", reinterpret_cast(&aux_free2_OctetString)}, + {"aux_cpy2_BitString", reinterpret_cast(&aux_cpy2_BitString)}, + {"sec_MD2Init", reinterpret_cast(&sec_MD2Init)}, + {"sec_MD2Update", reinterpret_cast(&sec_MD2Update)}, + {"sec_MD2Final", reinterpret_cast(&sec_MD2Final)}, + {"sec_MD4Init", reinterpret_cast(&sec_MD4Init)}, + {"sec_MD4Update", reinterpret_cast(&sec_MD4Update)}, + {"sec_MD4Final", reinterpret_cast(&sec_MD4Final)}, + {"sec_MD5Init", reinterpret_cast(&sec_MD5Init)}, + {"sec_MD5Update", reinterpret_cast(&sec_MD5Update)}, + {"sec_MD5Final", reinterpret_cast(&sec_MD5Final)}, + {"shsInit", reinterpret_cast(&shsInit)}, + {"shsUpdate", reinterpret_cast(&shsUpdate)}, + {"shsFinal", reinterpret_cast(&shsFinal)}, + {"shs1Init", reinterpret_cast(&shs1Init)}, + {"shs1Update", reinterpret_cast(&shs1Update)}, + {"shs1Final", reinterpret_cast(&shs1Final)}, + {"sec_random_ostr", reinterpret_cast(&sec_random_ostr)}, + // called directly by libec (s_ecvali.c) + {"global_add_error", reinterpret_cast(&global_add_error)}, + {"rabinstest", reinterpret_cast(&rabinstest)}, + {"ripemd160WithRSASignature_aid", static_cast(&ripemd160WithRSASignature_aid)}, + {"shaWithRSASignature_aid", static_cast(&shaWithRSASignature_aid)}, + {"md2WithRsaEncryption_aid", static_cast(&md2WithRsaEncryption_aid)}, + {"md2WithRSASignature_aid", static_cast(&md2WithRSASignature_aid)}, + {"dsa_aid", static_cast(&dsa_aid)}, + {"rc2CBC_aid", static_cast(&rc2CBC_aid)}, + {"rc4_aid", static_cast(&rc4_aid)}, + {"md5WithRsaEncryption_aid", static_cast(&md5WithRsaEncryption_aid)}, + {"desEDE_aid", static_cast(&desEDE_aid)}, + {"desCBC3_aid", static_cast(&desCBC3_aid)}, + {"desCBC_pad_aid", static_cast(&desCBC_pad_aid)}, + {"desECB_aid", static_cast(&desECB_aid)}, + {"idea_aid", static_cast(&idea_aid)}, + {"md2_aid", static_cast(&md2_aid)}, + {"md4_aid", static_cast(&md4_aid)}, + {"md5_aid", static_cast(&md5_aid)}, + {"sha_aid", static_cast(&sha_aid)}, + {"sha1_aid", static_cast(&sha1_aid)}, + {"ripemd160_aid", static_cast(&ripemd160_aid)}, + {"sha1WithRSASignature_aid", static_cast(&sha1WithRSASignature_aid)}, + {"rsa_aid", static_cast(&rsa_aid)}, + {"rsaEncryption_aid", static_cast(&rsaEncryption_aid)}, + {"dsaWithSHA_aid", static_cast(&dsaWithSHA_aid)}, + {"dsaWithSHA1_aid", static_cast(&dsaWithSHA1_aid)}, + {"Uid_OID", static_cast(&Uid_OID)}, + {"Cert_OID", static_cast(&Cert_OID)}, + {"sha1_oid", static_cast(&sha1_oid)}, + {"pbeWithSHA1And40BitRC2CBC_oid", static_cast(&pbeWithSHA1And40BitRC2CBC_oid)}, + {"pbeWithSHA1AndDES3xCBC_oid", static_cast(&pbeWithSHA1AndDES3xCBC_oid)}, + {"PKRoot_oid", static_cast(&PKRoot_oid)}, + {"SKnew_oid", static_cast(&SKnew_oid)}, + {"Cert_oid", static_cast(&Cert_oid)}, + {"FCPath_oid", static_cast(&FCPath_oid)}, + {"print_cert_flag", compat::print_cert_flag_address()}, + {"print_keyinfo_flag", compat::print_keyinfo_flag_address()}, + }; + return table; +} + +} // namespace + +using namespace compat; + +extern "C" { + +void *secude_compat_symbol(const char *name) +{ + if (!name) + return nullptr; + for (const auto &s : symbols()) + if (!std::strcmp(s.name, name)) + return s.address; + return nullptr; +} + +int secude_compat_symbol_count(void) +{ + return int(symbols().size()); +} + +const char *secude_compat_symbol_name(int index) +{ + if (index < 0 || size_t(index) >= symbols().size()) + return nullptr; + return symbols()[size_t(index)].name; +} + +} // extern "C" diff --git a/port/secude/src/symcipher.cpp b/port/secude/src/symcipher.cpp new file mode 100644 index 000000000..17ce7df1f --- /dev/null +++ b/port/secude/src/symcipher.cpp @@ -0,0 +1,244 @@ +// Symmetric ciphers. SECUDE "std" padding: the last block is filled with zero +// octets and its final octet holds the number of data octets in that block +// (0..blocksize-1); PKCS padding as in PKCS#5/RFC 1423. +#include "legacy.hpp" +#include "symcipher.hpp" + +#include + +namespace compat { + +namespace { + +size_t block_size(Cipher c) +{ + switch (c) { + case Cipher::RC4: + return 1; + case Cipher::AES: + return 16; + default: + return 8; + } +} + +void check_key(Cipher c, size_t keylen) +{ + bool ok = false; + switch (c) { + case Cipher::DES: ok = keylen == 8; break; + case Cipher::DES3: ok = keylen == 16 || keylen == 24; break; + case Cipher::IDEA: ok = keylen == 16; break; + case Cipher::RC2: ok = keylen >= 1 && keylen <= 128; break; + case Cipher::RC4: ok = keylen >= 1 && keylen <= 256; break; + case Cipher::AES: ok = keylen == 16 || keylen == 24 || keylen == 32; break; + default: break; + } + if (!ok) + fail(EKEYSIZE, str_printf("invalid key length of %u bits", unsigned(keylen * 8))); +} + +std::string evp_cipher_name(Cipher c, AlgMode mode, size_t keylen) +{ + bool cbc = mode == CBC; + switch (c) { + case Cipher::DES: return cbc ? "DES-CBC" : "DES-ECB"; + case Cipher::DES3: + if (keylen == 16) + return cbc ? "DES-EDE-CBC" : "DES-EDE"; + return cbc ? "DES-EDE3-CBC" : "DES-EDE3"; + case Cipher::IDEA: return cbc ? "IDEA-CBC" : "IDEA-ECB"; + case Cipher::RC2: return cbc ? "RC2-CBC" : "RC2-ECB"; + case Cipher::RC4: return "RC4"; + case Cipher::AES: return str_printf("AES-%u-%s", unsigned(keylen * 8), cbc ? "CBC" : "ECB"); + default: return {}; + } +} + +bool run_evp(const CipherSpec &s, const uint8_t *in, size_t n, Bytes &out, bool encrypt) +{ + std::string name = evp_cipher_name(s.cipher, s.mode, s.key.size()); + EVP_CIPHER *cipher = name.empty() ? nullptr : fetch_cipher(name.c_str()); + if (!cipher) + return false; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + bool ok = ctx && EVP_CipherInit_ex2(ctx, cipher, nullptr, nullptr, encrypt, nullptr); + if (ok && (s.cipher == Cipher::RC2 || s.cipher == Cipher::RC4)) { + size_t keylen = s.key.size(); + size_t keybits = s.rc2_bits; + OSSL_PARAM params[3]; + int i = 0; + params[i++] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &keylen); + if (s.cipher == Cipher::RC2) + params[i++] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, &keybits); + params[i] = OSSL_PARAM_construct_end(); + ok = EVP_CIPHER_CTX_set_params(ctx, params); + } + if (ok) + ok = EVP_CIPHER_CTX_set_padding(ctx, 0) && + EVP_CipherInit_ex2(ctx, nullptr, s.key.data(), s.iv.empty() ? nullptr : s.iv.data(), encrypt, nullptr); + out.assign(n + 32, 0); + int len1 = 0, len2 = 0; + if (ok) + ok = EVP_CipherUpdate(ctx, out.data(), &len1, in, int(n)) && EVP_CipherFinal_ex(ctx, out.data() + len1, &len2); + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + if (!ok) + fail(EINTERNAL, "cipher operation failed"); + out.resize(size_t(len1 + len2)); + return true; +} + +Bytes run_builtin(const CipherSpec &s, const uint8_t *in, size_t n, bool encrypt) +{ + Bytes out(n); + if (s.cipher == Cipher::RC4) { + legacy::rc4(s.key.data(), s.key.size(), in, out.data(), n); + return out; + } + std::unique_ptr bc; + switch (s.cipher) { + case Cipher::DES: bc = legacy::make_des(s.key.data()); break; + case Cipher::DES3: bc = legacy::make_des3(s.key.data(), s.key.size()); break; + case Cipher::IDEA: bc = legacy::make_idea(s.key.data()); break; + case Cipher::RC2: bc = legacy::make_rc2(s.key.data(), s.key.size(), s.rc2_bits); break; + default: fail(EUNKNOWNALGID, "cipher not available"); + } + size_t bs = bc->block_size(); + uint8_t chain[16] = {0}; + if (s.mode == CBC) + std::memcpy(chain, s.iv.data(), bs); + for (size_t off = 0; off < n; off += bs) { + const uint8_t *src = in + off; + uint8_t *dst = out.data() + off; + if (s.mode != CBC) { + encrypt ? bc->encrypt(src, dst) : bc->decrypt(src, dst); + } else if (encrypt) { + uint8_t x[16]; + for (size_t i = 0; i < bs; ++i) + x[i] = src[i] ^ chain[i]; + bc->encrypt(x, dst); + std::memcpy(chain, dst, bs); + } else { + uint8_t saved[16]; + std::memcpy(saved, src, bs); + bc->decrypt(src, dst); + for (size_t i = 0; i < bs; ++i) + dst[i] ^= chain[i]; + std::memcpy(chain, saved, bs); + } + } + return out; +} + +Bytes raw(const CipherSpec &s, const uint8_t *in, size_t n, bool encrypt) +{ + Bytes out; + if (run_evp(s, in, n, out, encrypt)) + return out; + return run_builtin(s, in, n, encrypt); +} + +unsigned rc2_bits_from_version(int version) +{ + switch (version) { + case 160: return 40; + case 120: return 64; + case 58: return 128; + default: return version >= 256 ? unsigned(version) : 0; + } +} + +CipherSpec spec_from_algid(const AlgId *alg, const Bytes &key) +{ + if (!alg || !alg->objid) + fail(EALGID, "missing algorithm identifier"); + const AlgInfo *a = alg_by_oid(alg->objid); + if (!a || a->type != SYM_ENC || a->cipher == Cipher::None) + fail(EUNKNOWNALGID, "not a symmetric algorithm: " + oid_to_string(oid_of(alg->objid))); + CipherSpec s; + s.cipher = a->cipher; + s.mode = a->mode; + s.pad = a->pad; + s.key = key; + check_key(s.cipher, key.size()); + size_t bs = block_size(s.cipher); + if (s.mode == CBC) { + s.iv.assign(bs, 0); + const OctetString *iv = nullptr; + if (alg->param && a->parm == PARM_OctetString) + iv = static_cast(alg->param); + else if (alg->param && a->parm == PARM_RC2CBC) + iv = &static_cast(alg->param)->IV; + if (iv && iv->noctets) { + if (iv->noctets != bs) + fail(EWRONGPARM, "wrong IV length"); + s.iv = bytes_of(iv); + } + } + if (s.cipher == Cipher::RC2) { + unsigned bits = 0; + if (alg->param) + bits = rc2_bits_from_version(static_cast(alg->param)->version); + s.rc2_bits = bits ? bits : unsigned(key.size() * 8); + } + return s; +} + +} // namespace + +Bytes cipher_encrypt(const CipherSpec &s, const uint8_t *in, size_t n) +{ + size_t bs = block_size(s.cipher); + Bytes data(in, in + n); + if (bs > 1) { + if (s.pad == Pad::Std) { + size_t r = n % bs; + data.resize(n - r + bs, 0); + data.back() = uint8_t(r); + } else if (s.pad == Pad::Pkcs) { + size_t k = bs - n % bs; + data.insert(data.end(), k, uint8_t(k)); + } else if (n % bs) { + fail(EINVALID, "input is not a multiple of the block size"); + } + } + return raw(s, data.data(), data.size(), true); +} + +Bytes cipher_decrypt(const CipherSpec &s, const uint8_t *in, size_t n) +{ + size_t bs = block_size(s.cipher); + if (bs > 1 && (n % bs || (s.pad != Pad::None && n == 0))) + fail(EDECRYPTION, "ciphertext length is not a multiple of the block size"); + Bytes out = raw(s, in, n, false); + if (bs > 1 && s.pad == Pad::Std) { + size_t r = out.back(); + if (r >= bs) + fail(EDECRYPTION, "invalid padding"); + out.resize(out.size() - bs + r); + } else if (bs > 1 && s.pad == Pad::Pkcs) { + size_t k = out.back(); + if (k == 0 || k > bs) + fail(EDECRYPTION, "invalid padding"); + for (size_t i = out.size() - k; i < out.size(); ++i) + if (out[i] != k) + fail(EDECRYPTION, "invalid padding"); + out.resize(out.size() - k); + } + return out; +} + +Bytes sym_encrypt(const AlgId *alg, const Bytes &key, size_t keybits, const uint8_t *in, size_t n) +{ + Bytes k(key.begin(), key.begin() + long(std::min(key.size(), (keybits + 7) / 8))); + return cipher_encrypt(spec_from_algid(alg, k), in, n); +} + +Bytes sym_decrypt(const AlgId *alg, const Bytes &key, size_t keybits, const uint8_t *in, size_t n) +{ + Bytes k(key.begin(), key.begin() + long(std::min(key.size(), (keybits + 7) / 8))); + return cipher_decrypt(spec_from_algid(alg, k), in, n); +} + +} // namespace compat diff --git a/port/secude/src/symcipher.hpp b/port/secude/src/symcipher.hpp new file mode 100644 index 000000000..eda3d7959 --- /dev/null +++ b/port/secude/src/symcipher.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "internal.hpp" + +namespace compat { + +struct CipherSpec { + Cipher cipher = Cipher::None; + AlgMode mode = ECB; + Pad pad = Pad::None; + Bytes key; + Bytes iv; + unsigned rc2_bits = 0; +}; + +Bytes cipher_encrypt(const CipherSpec &s, const uint8_t *in, size_t n); +Bytes cipher_decrypt(const CipherSpec &s, const uint8_t *in, size_t n); + +} // namespace compat diff --git a/port/secude/tests/main.cpp b/port/secude/tests/main.cpp new file mode 100644 index 000000000..7c7d5a87f --- /dev/null +++ b/port/secude/tests/main.cpp @@ -0,0 +1,75 @@ +#include "testing.hpp" + +#include +#include +#include + +#include "secude_compat.h" + +extern "C" int secude_compat_test_libec(void); + +namespace testing { + +namespace { +int failures = 0; +std::string g_scratch; +} // namespace + +std::vector ®istry() +{ + static std::vector r; + return r; +} + +void report_failure(const char *file, int line, const std::string &what) +{ + ++failures; + std::fprintf(stderr, " FAILED %s:%d: %s\n", file, line, what.c_str()); +} + +std::string scratch_dir() { return g_scratch; } + +std::string hex(const void *p, size_t n) +{ + static const char d[] = "0123456789abcdef"; + std::string s; + const unsigned char *b = static_cast(p); + for (size_t i = 0; i < n; ++i) { + s += d[b[i] >> 4]; + s += d[b[i] & 15]; + } + return s; +} + +} // namespace testing + +TEST(libec_binding) +{ + CHECK_EQ(secude_compat_test_libec(), 0); +} + +int main(int argc, char **argv) +{ + char tmpl[] = "/tmp/secude_compat_tests.XXXXXX"; + const char *dir = mkdtemp(tmpl); + if (!dir) { + std::perror("mkdtemp"); + return 2; + } + testing::g_scratch = dir; + std::printf("SECUDE compat tests (%s, legacy provider %s)\n", secude_compat_version(), + secude_compat_legacy_provider_active() ? "active" : "not used"); + const char *only = argc > 1 ? argv[1] : nullptr; + for (const auto &c : testing::registry()) { + if (only && !std::strstr(c.name, only)) + continue; + int before = testing::failures; + c.fn(); + std::printf("%s %s\n", testing::failures == before ? "ok " : "FAIL", c.name); + } + std::string cleanup = "rm -rf '" + testing::g_scratch + "'"; + if (std::system(cleanup.c_str()) != 0) + std::fprintf(stderr, "could not remove %s\n", testing::g_scratch.c_str()); + std::printf("%d failure(s)\n", testing::failures); + return testing::failures ? 1 : 0; +} diff --git a/port/secude/tests/test_asym.cpp b/port/secude/tests/test_asym.cpp new file mode 100644 index 000000000..817a7571f --- /dev/null +++ b/port/secude/tests/test_asym.cpp @@ -0,0 +1,183 @@ +#include "bn.hpp" +#include "der.hpp" +#include "testing.hpp" + +#include +#include + +using namespace compat; + +namespace { + +struct KeyPair { + KeyInfo *pub = nullptr, *priv = nullptr; + ~KeyPair() + { + aux_free_KeyInfo(&pub); + aux_free_KeyInfo(&priv); + } +}; + +Signature sign(KeyInfo *priv, AlgId *alg, const Bytes &msg) +{ + Bytes s = sign_message(priv, Bytes(), alg, msg.data(), msg.size()); + Signature sig{}; + sig.signAI = alg; + fill_bstr(&sig.signature, s, s.size() * 8); + return sig; +} + +int verify(KeyInfo *pub, Signature *sig, const Bytes &msg) +{ + Key key{}; + key.key = pub; + OctetString in{sec_uint4(msg.size()), reinterpret_cast(const_cast(msg.data()))}; + return sec_verify_all(&in, sig, &key, nullptr); +} + +EVP_PKEY *openssl_rsa(const RsaPublic &k) +{ + Bn n = bn_from(k.n), e = bn_from(k.e); + OSSL_PARAM_BLD *b = OSSL_PARAM_BLD_new(); + OSSL_PARAM_BLD_push_BN(b, OSSL_PKEY_PARAM_RSA_N, n.get()); + OSSL_PARAM_BLD_push_BN(b, OSSL_PKEY_PARAM_RSA_E, e.get()); + OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(b); + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr); + EVP_PKEY *pkey = nullptr; + EVP_PKEY_fromdata_init(ctx); + EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params); + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(b); + return pkey; +} + +} // namespace + +TEST(asym_rsa_sign_verify_all_algorithms) +{ + for (int bits : {512, 768}) { + KeyPair kp; + rsa_generate(bits, &kp.pub, &kp.priv); + RsaPublic pub = rsa_public_from_keyinfo(kp.pub); + CHECK_EQ(rsa_bits(pub.n), bits); + CHECK_HEX(pub.e.data(), pub.e.size(), "010001"); + Bytes msg = random_bytes(100); + for (AlgId *alg : {&md2WithRsaEncryption_aid, &md5WithRsaEncryption_aid, &shaWithRSASignature_aid, + &sha1WithRSASignature_aid, &ripemd160WithRSASignature_aid, &sha1WithRsaEncryption_aid}) { + Signature sig = sign(kp.priv, alg, msg); + CHECK_EQ(sig.signature.nbits, sec_uint4(bits)); + CHECK_EQ(verify(kp.pub, &sig, msg), 0); + sig.signature.bits[3] ^= 1; + CHECK_EQ(verify(kp.pub, &sig, msg), -1); + aux_free2_BitString(&sig.signature); + } + // PKCS#1 v1.5 interoperability + Signature sig = sign(kp.priv, &md5WithRsaEncryption_aid, msg); + EVP_PKEY *pkey = openssl_rsa(pub); + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + CHECK_EQ(EVP_DigestVerifyInit_ex(mctx, nullptr, "MD5", nullptr, nullptr, pkey, nullptr), 1); + CHECK_EQ(EVP_DigestVerify(mctx, reinterpret_cast(sig.signature.bits), sig.signature.nbits / 8, + msg.data(), msg.size()), + 1); + EVP_MD_CTX_free(mctx); + EVP_PKEY_free(pkey); + aux_free2_BitString(&sig.signature); + } + aux_free_error(); +} + +TEST(asym_rsa_small_key_and_blocks) +{ + KeyPair kp; + rsa_generate(301, &kp.pub, &kp.priv); + RsaPublic pub = rsa_public_from_keyinfo(kp.pub); + CHECK_EQ(rsa_bits(pub.n), 301); + RsaPrivate priv = rsa_private_from_keyinfo(kp.priv, Bytes()); + // block sizes: 37 octets of plain text per 38 octet cipher block + Bytes msg = random_bytes(37 * 3); + Bytes c = rsa_encrypt_blocks(pub, msg.data(), msg.size()); + CHECK_EQ(c.size(), size_t(38 * 3)); + CHECK(rsa_decrypt_blocks(priv, c.data(), c.size()) == msg); + Bytes partial = random_bytes(40); + c = rsa_encrypt_blocks(pub, partial.data(), partial.size()); + Bytes d = rsa_decrypt_blocks(priv, c.data(), c.size()); + CHECK_EQ(d.size(), size_t(74)); + CHECK(Bytes(d.begin(), d.begin() + 40) == partial); + CHECK(Bytes(d.begin() + 40, d.end()) == Bytes(34, 0)); +} + +TEST(asym_rsa_textbook_property_for_side_channel_demo) +{ + KeyPair kp; + rsa_generate(512, &kp.pub, &kp.priv); + RsaPublic pub = rsa_public_from_keyinfo(kp.pub); + RsaPrivate priv = rsa_private_from_keyinfo(kp.priv, Bytes()); + Bytes session = random_bytes(16); + Bytes block(63 - 16, 0); + block.insert(block.end(), session.begin(), session.end()); + Bytes c = rsa_encrypt_blocks(pub, block.data(), block.size()); + CHECK_EQ(c.size(), size_t(64)); + // C' = C * 3^e mod n decrypts to 3*m mod n + Bn n = bn_from(pub.n), e = bn_from(pub.e), three = bn_word(3), f = bn_new(), c2 = bn_new(); + BN_CTX *ctx = BN_CTX_new(); + BN_mod_exp(f.get(), three.get(), e.get(), n.get(), ctx); + BN_mod_mul(c2.get(), bn_from(c).get(), f.get(), n.get(), ctx); + Bytes m2 = rsa_decrypt_blocks(priv, bn_bytes(c2.get(), 64).data(), 64); + Bn expect = bn_new(); + BN_mod_mul(expect.get(), bn_from(block).get(), three.get(), n.get(), ctx); + CHECK(BN_cmp(bn_from(m2).get(), expect.get()) == 0); + BN_CTX_free(ctx); +} + +TEST(asym_rsa_user_chosen_exponent) +{ + Bytes e17{0x11}; + KeyPair kp; + RsaPrivate k17; + for (;;) { + aux_free_KeyInfo(&kp.pub); + aux_free_KeyInfo(&kp.priv); + rsa_generate(512, &kp.pub, &kp.priv); + try { + k17 = rsa_private_from_keyinfo(kp.priv, e17); + break; + } catch (const Error &e) { + CHECK_EQ(e.code, EALGNOTFITKEY); // 17 divides (p-1)(q-1) + } + } + RsaPrivate base = rsa_private_from_keyinfo(kp.priv, Bytes()); + CHECK(k17.d != base.d); + Bytes m = random_bytes(20); + Bytes s = rsa_raw_private(k17, m); + Bn r = bn_new(); + BN_CTX *ctx = BN_CTX_new(); + BN_mod_exp(r.get(), bn_from(s).get(), bn_from(e17).get(), bn_from(k17.n).get(), ctx); + CHECK(BN_cmp(r.get(), bn_from(m).get()) == 0); + BN_CTX_free(ctx); +} + +TEST(asym_dsa_sign_verify) +{ + KeyPair kp; + dsa_generate(512, &kp.pub, &kp.priv); + CHECK(keyinfo_is_dsa(kp.pub)); + auto *params = static_cast(kp.pub->subjectAI->param); + CHECK_EQ(rsa_bits(bytes_of(¶ms->part1)), 512); + CHECK_EQ(rsa_bits(bytes_of(¶ms->part2)), 160); + Bytes msg = random_bytes(77); + for (AlgId *alg : {&dsaWithSHA_aid, &dsaWithSHA1_aid}) { + Signature sig = sign(kp.priv, alg, msg); + CHECK_EQ(verify(kp.pub, &sig, msg), 0); + Bytes other = msg; + other[0] ^= 1; + CHECK_EQ(verify(kp.pub, &sig, other), -1); + aux_free2_BitString(&sig.signature); + } + Signature wrong = sign(kp.priv, &dsaWithSHA1_aid, msg); + wrong.signAI = &md5WithRsaEncryption_aid; + CHECK_EQ(verify(kp.pub, &wrong, msg), -1); + CHECK_EQ(th_last_error(), EALGNOTFITKEY); + aux_free2_BitString(&wrong.signature); + aux_free_error(); +} diff --git a/port/secude/tests/test_binding.cpp b/port/secude/tests/test_binding.cpp new file mode 100644 index 000000000..164be8926 --- /dev/null +++ b/port/secude/tests/test_binding.cpp @@ -0,0 +1,69 @@ +// Compiles CrypTool/SecudeLib.h exactly as the application does and binds +// every member through secude_compat_symbol(), mirroring the non-Windows +// branch of CSecudeLib::OpenSecudeLib(). +typedef void *HINSTANCE; +typedef unsigned int UINT; + +#include "SecudeLib.h" +#include "secude_compat.h" +#include "testing.hpp" + +#include + +int CSecudeLib::OpenSecudeLib() +{ + int errcnt = 0; +#define DoOneFn(a, b, c, d) \ + c = (c##_t)secude_compat_symbol(#c); \ + if (c == NULL) \ + errcnt++; +#define DoOneData(a, b) \ + b = (a *)secude_compat_symbol(#b); \ + if (b == NULL) \ + errcnt++; + DoAll +#undef DoOneFn +#undef DoOneData + char *line; + Status = errcnt ? 0 : (SECUDE_HasValidTicket(&line) < 0 ? 1 : 2); + if ((MaxBits = light_version()) == 0) + MaxBits = 8192; + return errcnt; +} + +CSecudeLib::CSecudeLib() : MaxBits(0), hDLL(nullptr), Status(0) {} +CSecudeLib::~CSecudeLib() {} +int CSecudeLib::CloseSecudeLib() { return 0; } + +TEST(binding_cryptool_secudelib) +{ + CSecudeLib lib; + CHECK_EQ(lib.OpenSecudeLib(), 0); + CHECK_EQ(lib.GetStatus(), 2); + CHECK_EQ(lib.MaxBits, 8192); + CHECK(secude_compat_symbol("no_such_symbol") == nullptr); + + char data[] = "abc"; + OctetString in = {3, data}; + OctetString out = {0, nullptr}; + CHECK_EQ(lib.sec_hash_all(&in, &out, lib.md5_aid, NULL), 0); + CHECK_HEX(out.octets, out.noctets, "900150983cd24fb0d6963f7d28e17f72"); + lib.aux_free(out.octets); + + // flags are written through sec_uint4 pointers + *lib.print_keyinfo_flag = 0x0d; + *lib.print_cert_flag = 0x77e; + CHECK_EQ(*lib.print_keyinfo_flag, 0x0du); + + CHECK(lib.af_open(const_cast("/nonexistent/x.pse"), NULL, const_cast("1"), NULL) == NULL); + CHECK(lib.LASTERROR != 0); + CHECK(std::strlen(lib.LASTTEXT) > 0); + char *err = lib.aux_sprint_error(NULL, NULL, 1); + CHECK(err && std::strstr(err, "EPSENOTEXISTING")); + lib.aux_free_String(&err); + lib.aux_free_error(); + CHECK_EQ(lib.LASTERROR, 0); + CHECK_EQ((*lib.Cert_OID)->oid_nelem, lib.Cert_oid->oid_nelem); + CHECK(lib.rsa_aid->param != nullptr); + CHECK(std::strstr(lib.aux_sprint_version(NULL), "compatibility") != nullptr); +} diff --git a/port/secude/tests/test_cipher.cpp b/port/secude/tests/test_cipher.cpp new file mode 100644 index 000000000..9607e460d --- /dev/null +++ b/port/secude/tests/test_cipher.cpp @@ -0,0 +1,238 @@ +#include "legacy.hpp" +#include "testing.hpp" + +#include +#include +#include + +using namespace compat; + +namespace { + +Bytes unhex(const std::string &h) +{ + Bytes b; + for (size_t i = 0; i + 1 < h.size(); i += 2) + b.push_back(uint8_t(std::stoi(h.substr(i, 2), nullptr, 16))); + return b; +} + +struct SymKey { + Key key{}; + KeyInfo info{}; + Bytes material; + SymKey(AlgId *alg, const Bytes &k) : material(k) + { + info.subjectAI = alg; + info.subjectkey.bits = reinterpret_cast(material.data()); + info.subjectkey.nbits = sec_uint4(material.size() * 8); + key.key = &info; + } +}; + +Bytes encrypt(AlgId *alg, const Bytes &key, const Bytes &plain) +{ + SymKey k(alg, key); + OctetString in{sec_uint4(plain.size()), reinterpret_cast(const_cast(plain.data()))}; + std::vector buf(plain.size() + 64); + BitString out{0, buf.data()}; + CHECK_EQ(sec_encrypt_all(&in, &out, &k.key), 0); + return Bytes(buf.begin(), buf.begin() + out.nbits / 8); +} + +int decrypt(AlgId *alg, const Bytes &key, const Bytes &cipher, Bytes &plain) +{ + SymKey k(alg, key); + BitString in{sec_uint4(cipher.size() * 8), reinterpret_cast(const_cast(cipher.data()))}; + std::vector buf(cipher.size() + 64); + OctetString out{0, buf.data()}; + int rc = sec_decrypt_all(&in, &out, &k.key); + plain.assign(buf.begin(), buf.begin() + out.noctets); + return rc; +} + +} // namespace + +TEST(cipher_des_known_answer) +{ + Bytes key = unhex("133457799bbcdff1"), pt = unhex("0123456789abcdef"); + uint8_t ct[8]; + legacy::make_des(key.data())->encrypt(pt.data(), ct); + CHECK_HEX(ct, 8, "85e813540f0ab405"); + Bytes c = encrypt(&desECB_aid, key, pt); + CHECK_EQ(c.size(), size_t(16)); + CHECK_HEX(c.data(), 8, "85e813540f0ab405"); + Bytes back; + CHECK_EQ(decrypt(&desECB_aid, key, c, back), 0); + CHECK(back == pt); +} + +TEST(cipher_idea_known_answer) +{ + Bytes key = unhex("00010002000300040005000600070008"), pt = unhex("0000000100020003"); + auto idea = legacy::make_idea(key.data()); + uint8_t ct[8], back[8]; + idea->encrypt(pt.data(), ct); + CHECK_HEX(ct, 8, "11fbed2b01986de5"); + idea->decrypt(ct, back); + CHECK_HEX(back, 8, "0000000100020003"); + Bytes c = encrypt(&idea_aid, key, pt); + CHECK_HEX(c.data(), 8, "11fbed2b01986de5"); +} + +TEST(cipher_rc2_rfc2268) +{ + struct { + const char *key; + unsigned bits; + const char *pt; + const char *ct; + } v[] = { + {"0000000000000000", 63, "0000000000000000", "ebb773f993278eff"}, + {"ffffffffffffffff", 64, "ffffffffffffffff", "278b27e42e2f0d49"}, + {"3000000000000000", 64, "1000000000000001", "30649edf9be7d2c2"}, + {"88", 64, "0000000000000000", "61a8a244adacccf0"}, + {"88bca90e90875a", 64, "0000000000000000", "6ccf4308974c267f"}, + {"88bca90e90875a7f0f79c384627bafb2", 64, "0000000000000000", "1a807d272bbe5db1"}, + {"88bca90e90875a7f0f79c384627bafb2", 128, "0000000000000000", "2269552ab0f85ca6"}, + }; + for (const auto &t : v) { + Bytes key = unhex(t.key), pt = unhex(t.pt); + auto rc2 = legacy::make_rc2(key.data(), key.size(), t.bits); + uint8_t ct[8], back[8]; + rc2->encrypt(pt.data(), ct); + CHECK_HEX(ct, 8, t.ct); + rc2->decrypt(ct, back); + CHECK_HEX(back, 8, t.pt); + } +} + +TEST(cipher_rc4_known_answer) +{ + const char *pt = "Plaintext"; + uint8_t out[9]; + legacy::rc4(reinterpret_cast("Key"), 3, reinterpret_cast(pt), out, 9); + CHECK_HEX(out, 9, "bbf316e8d940af0ad3"); + Bytes c = encrypt(&rc4_aid, Bytes{'K', 'e', 'y'}, Bytes(pt, pt + 9)); + CHECK_HEX(c.data(), c.size(), "bbf316e8d940af0ad3"); +} + +TEST(cipher_round_trips_and_padding) +{ + struct { + AlgId *alg; + size_t keylen; + size_t block; + bool std_pad; + } algs[] = { + {&desECB_aid, 8, 8, true}, {&desCBC_pad_aid, 8, 8, false}, {&desCBC3_aid, 16, 8, true}, + {&desEDE_aid, 16, 8, true}, {&idea_aid, 16, 8, true}, {&rc2CBC_aid, 1, 8, false}, + {&rc2CBC_aid, 16, 8, false}, {&rc4_aid, 5, 1, false}, {&rc4_aid, 16, 1, false}, + {&aes128CBC_aid, 16, 16, false}, {&desCBC3_aid, 24, 8, true}, + }; + for (const auto &a : algs) { + Bytes key = random_bytes(a.keylen); + for (size_t len = 0; len < 35; ++len) { + Bytes pt = random_bytes(len); + Bytes c = encrypt(a.alg, key, pt); + size_t expected = a.block == 1 ? len : (len / a.block + 1) * a.block; + CHECK_EQ(c.size(), expected); + Bytes back; + CHECK_EQ(decrypt(a.alg, key, c, back), 0); + CHECK(back == pt); + } + } +} + +TEST(cipher_std_padding_layout) +{ + Bytes key = unhex("0123456789abcdef"); + Bytes pt = {'a', 'b', 'c'}; + Bytes c = encrypt(&desECB_aid, key, pt); + uint8_t block[8]; + legacy::make_des(key.data())->decrypt(c.data(), block); + CHECK_HEX(block, 8, "6162630000000003"); +} + +TEST(cipher_bad_padding_is_decryption_error) +{ + Bytes key = unhex("0123456789abcdef"); + uint8_t garbage[8] = {0x61, 0x62, 0x63, 0, 0, 0, 0, 0x09}; + uint8_t ct[8]; + legacy::make_des(key.data())->encrypt(garbage, ct); + Bytes back; + CHECK_EQ(decrypt(&desECB_aid, key, Bytes(ct, ct + 8), back), -1); + ErrStack *err = th_remove_last_error(); + CHECK_EQ(err->e_number, 1792); + aux_free(err->e_text); + aux_free(err->e_proc); + aux_free(err); + CHECK_EQ(decrypt(&desECB_aid, key, Bytes(ct, ct + 7), back), -1); + aux_free_error(); +} + +TEST(cipher_builtin_matches_openssl_legacy) +{ + OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new(); + OSSL_PROVIDER_load(ctx, "default"); + if (!OSSL_PROVIDER_load(ctx, "legacy")) { + std::printf(" (legacy provider not available, cross-check skipped)\n"); + OSSL_LIB_CTX_free(ctx); + return; + } + // returns the input unchanged if the cipher is missing from this OpenSSL build (e.g. IDEA on Debian) + std::set missing; + auto ref = [&](const char *name, const Bytes &key, unsigned rc2bits, const Bytes &in) { + EVP_CIPHER *c = EVP_CIPHER_fetch(ctx, name, nullptr); + if (!c) { + if (missing.insert(name).second) + std::printf(" (%s not provided by this OpenSSL, cross-check skipped)\n", name); + return in; + } + EVP_CIPHER_CTX *cc = EVP_CIPHER_CTX_new(); + EVP_CipherInit_ex2(cc, c, nullptr, nullptr, 1, nullptr); + size_t keylen = key.size(), bits = rc2bits; + if (EVP_CIPHER_get_key_length(c) != int(keylen)) { + OSSL_PARAM p[3] = {OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &keylen), + OSSL_PARAM_construct_end(), OSSL_PARAM_construct_end()}; + if (rc2bits) + p[1] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, &bits); + EVP_CIPHER_CTX_set_params(cc, p); + } else if (rc2bits) { + OSSL_PARAM p[2] = {OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, &bits), OSSL_PARAM_construct_end()}; + EVP_CIPHER_CTX_set_params(cc, p); + } + EVP_CIPHER_CTX_set_padding(cc, 0); + EVP_CipherInit_ex2(cc, nullptr, key.data(), nullptr, 1, nullptr); + Bytes out(in.size() + 16); + int n = 0, f = 0; + EVP_CipherUpdate(cc, out.data(), &n, in.data(), int(in.size())); + EVP_CipherFinal_ex(cc, out.data() + n, &f); + out.resize(size_t(n + f)); + EVP_CIPHER_CTX_free(cc); + EVP_CIPHER_free(c); + return out; + }; + auto same = [](const Bytes &own, const Bytes &reference, const Bytes &in) { return reference == in || own == reference; }; + auto ecb = [](legacy::BlockCipher &bc, const Bytes &in) { + Bytes out(in.size()); + for (size_t i = 0; i < in.size(); i += 8) + bc.encrypt(in.data() + i, out.data() + i); + return out; + }; + for (int round = 0; round < 20; ++round) { + Bytes data = random_bytes(64); + Bytes k8 = random_bytes(8), k16 = random_bytes(16), k24 = random_bytes(24); + CHECK(same(ecb(*legacy::make_des(k8.data()), data), ref("DES-ECB", k8, 0, data), data)); + CHECK(same(ecb(*legacy::make_des3(k16.data(), 16), data), ref("DES-EDE", k16, 0, data), data)); + CHECK(same(ecb(*legacy::make_des3(k24.data(), 24), data), ref("DES-EDE3", k24, 0, data), data)); + CHECK(same(ecb(*legacy::make_idea(k16.data()), data), ref("IDEA-ECB", k16, 0, data), data)); + size_t rl = size_t(1 + round % 16); + Bytes kr = random_bytes(rl); + CHECK(same(ecb(*legacy::make_rc2(kr.data(), kr.size(), unsigned(rl * 8)), data), ref("RC2-ECB", kr, unsigned(rl * 8), data), data)); + Bytes rc4out(data.size()); + legacy::rc4(kr.data(), kr.size(), data.data(), rc4out.data(), data.size()); + CHECK(same(rc4out, ref("RC4", kr, 0, data), data)); + } + OSSL_LIB_CTX_free(ctx); +} diff --git a/port/secude/tests/test_encode.cpp b/port/secude/tests/test_encode.cpp new file mode 100644 index 000000000..ea1fa2aa5 --- /dev/null +++ b/port/secude/tests/test_encode.cpp @@ -0,0 +1,145 @@ +#include "der.hpp" +#include "testing.hpp" + +using namespace compat; + +namespace { + +std::string str(char *s) +{ + std::string r = s ? s : "(null)"; + aux_free(s); + return r; +} + +} // namespace + +TEST(encode_octetstring_and_printable) +{ + char data[] = "hello"; + OctetString in{5, data}; + OctetString *e = e_OctetString(&in); + CHECK_HEX(e->octets, e->noctets, "040568656c6c6f"); + OctetString *d = d_OctetString(e); + CHECK_HEX(d->octets, d->noctets, "68656c6c6f"); + aux_free_OctetString(&e); + aux_free_OctetString(&d); + CHECK(e == nullptr); + + char name[] = "[SideChannelAttack][Bob][RSA-512][1152179494][PIN=1234]"; + OctetString *p = e_PrintableString(name); + CHECK_EQ(uint8_t(p->octets[0]), uint8_t(0x13)); + CHECK_EQ(str(d_PrintableString(p)), std::string(name)); + aux_free_OctetString(&p); +} + +TEST(encode_keybits_keyinfo_algid) +{ + uint8_t n[] = {0xc0, 0x01, 0x02}, ev[] = {0x01, 0x00, 0x01}; + KeyBits kb{}; + kb.part1 = {3, reinterpret_cast(n)}; + kb.part2 = {3, reinterpret_cast(ev)}; + BitString *bs = e_KeyBits(&kb); + CHECK_HEX(bs->bits, bs->nbits / 8, "300b020400c001020203010001"); + KeyBits *back = d_KeyBits(bs); + CHECK_EQ(back->choice, 2); + CHECK_HEX(back->part1.octets, back->part1.noctets, "c00102"); + CHECK_HEX(back->part2.octets, back->part2.noctets, "010001"); + aux_free_KeyBits(&back); + + KeyInfo ki{}; + ki.subjectAI = aux_cpy_AlgId(&rsa_aid); + *static_cast(ki.subjectAI->param) = 1024; + CHECK(aux_cpy2_BitString(&ki.subjectkey, bs) == 0); + OctetString *enc = e_KeyInfo(&ki); + KeyInfo *dec = d_KeyInfo(enc); + CHECK_EQ(aux_cmp_ObjId(dec->subjectAI->objid, rsa_aid.objid), 0); + CHECK_EQ(*static_cast(dec->subjectAI->param), 1024u); + CHECK_EQ(str(aux_sprint_AlgId(nullptr, dec->subjectAI)), std::string("Algorithm RSA (OID 2.5.8.1.1), Keysize = 1024")); + CHECK_EQ(str(aux_sprint_AlgId(nullptr, &sha1WithRsaEncryption_aid)), + std::string("Algorithm sha1WithRsaEncryption (OID 1.2.840.113549.1.1.5), NULL")); + CHECK_EQ(aux_ObjId2AlgEnc(dec->subjectAI->objid), SECUDE_ALG_RSA); + CHECK_EQ(aux_ObjId2AlgEnc(dsa_aid.objid), SECUDE_ALG_DSA); + CHECK_EQ(aux_ObjId2AlgEnc(idea_aid.objid), IDEA); + CHECK_EQ(rsa_aid.objid->oid_nelem, 5); + CHECK_EQ(dsa_aid.objid->oid_nelem, 6); + aux_free_KeyInfo(&dec); + aux_free_OctetString(&enc); + aux_free2_KeyInfo(&ki); + aux_free_BitString(&bs); + + OctetString *a = e_AlgId(&md5WithRsaEncryption_aid); + CHECK_HEX(a->octets, a->noctets, "300d06092a864886f70d0101040500"); + aux_free_OctetString(&a); + a = e_AlgId(&dsaWithSHA1_aid); + CHECK_HEX(a->octets, a->noctets, "300706052b0e03021b"); + aux_free_OctetString(&a); + CHECK(aux_Name2AlgId(const_cast("desCBC_pad")) == &desCBC_pad_aid); +} + +TEST(encode_distinguished_names) +{ + const char *text = "CN=Bob SideChannelAttack [1152179494], DC=cryptool, DC=org"; + DName *dn = aux_Name2DName(const_cast(text)); + CHECK(dn != nullptr); + Bytes der_bytes = enc_dname(dn); + // most significant RDN first in DER: DC=org + CHECK_EQ(testing::hex(der_bytes.data(), der_bytes.size()).find("060a0992268993f22c6401191603" "6f7267"), size_t(12)); + CHECK_EQ(str(aux_DName2Name(dn)), std::string(text)); + CHECK_EQ(str(aux_DName2Attr(dn, const_cast("CN"))), std::string("Bob SideChannelAttack [1152179494]")); + DName *other = aux_Name2DName(const_cast("cn=bob sidechannelattack [1152179494],DC=cryptool,DC=org")); + CHECK_EQ(aux_cmp_DName(dn, other), 0); + DName *diff = aux_Name2DName(const_cast("CN=Alice, DC=cryptool, DC=org")); + CHECK(aux_cmp_DName(dn, diff) != 0); + aux_free_DName(&dn); + aux_free_DName(&other); + aux_free_DName(&diff); + CHECK(dn == nullptr); +} + +TEST(encode_latin1_unicode) +{ + OctetString *u = aux_latin1_to_unicode(const_cast("A\xe4"), TRUE); + CHECK_HEX(u->octets, u->noctets, "004100e40000"); + aux_free_OctetString(&u); +} + +TEST(encode_asn1_dump) +{ + Bytes good = der::seq({der::integer(5), der::oid(oids::sha1), der::octet_string(der::seq({der::null()}))}); + OctetString o{sec_uint4(good.size()), reinterpret_cast(good.data())}; + std::string dump = str(sdumpasn(&o, 0, 0)); + CHECK(dump.find("SEQUENCE {") != std::string::npos); + CHECK(dump.find("1.3.14.3.2.26 (sha1)") != std::string::npos); + CHECK(dump.find("encapsulates") != std::string::npos); + CHECK(dump.find("FATAL") == std::string::npos); + + Bytes junk = good; + junk.push_back(0); + o = {sec_uint4(junk.size()), reinterpret_cast(junk.data())}; + CHECK(str(sdumpasn(&o, 0, 0)).find("junk at end of PDU") != std::string::npos); + char text[] = "plain text, not ASN.1"; + o = {sec_uint4(std::strlen(text)), text}; + CHECK(str(sdumpasn(&o, 0, 0)).find("FATAL: decoding failed!") != std::string::npos); + + char buf[] = "0123456789abcdefXYZ"; + std::string hexd = str(aux_sxdump(nullptr, buf, 19, 0)); + CHECK(hexd.find("30313233 34353637 38396162 63646566") != std::string::npos); + CHECK(hexd.find("0123456789abcdef") != std::string::npos); +} + +TEST(memory_safety_of_free_functions) +{ + // CrypTool passes addresses of stack variables and globals to free functions + char *s = aux_cpy_String(const_cast("x")); + aux_free(&s); + aux_free_String(&s); + CHECK(s == nullptr); + ObjId *global = &SKnew_oid; + aux_free_ObjId(&global); + CHECK(global == nullptr); + CHECK_EQ(SKnew_oid.oid_nelem, 5); + AlgId *g = &rsa_aid; + aux_free_AlgId(&g); + CHECK(rsa_aid.param != nullptr); +} diff --git a/port/secude/tests/test_hash.cpp b/port/secude/tests/test_hash.cpp new file mode 100644 index 000000000..7a58aef26 --- /dev/null +++ b/port/secude/tests/test_hash.cpp @@ -0,0 +1,177 @@ +#include "legacy.hpp" +#include "testing.hpp" + +#include + +using namespace compat; + +namespace { + +struct Vector { + AlgId *aid; + const char *msg; + const char *digest; +}; + +const char kLong[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + +std::vector vectors() +{ + return { + {&md2_aid, "", "8350e5a3e24c153df2275c9f80692773"}, + {&md2_aid, "abc", "da853b0d3f88d99b30283a69e6ded6bb"}, + {&md2_aid, "message digest", "ab4f496bfb2a530b219ff33031fe06b0"}, + {&md2_aid, "abcdefghijklmnopqrstuvwxyz", "4e8ddff3650292ab5a4108c3aa47940b"}, + {&md4_aid, "", "31d6cfe0d16ae931b73c59d7e0c089c0"}, + {&md4_aid, "abc", "a448017aaf21d8525fc10ae87aa6729d"}, + {&md4_aid, "message digest", "d9130a8164549fe818874806e1c7014b"}, + {&md5_aid, "", "d41d8cd98f00b204e9800998ecf8427e"}, + {&md5_aid, "abc", "900150983cd24fb0d6963f7d28e17f72"}, + {&md5_aid, "message digest", "f96b697d7cb7938d525a2f31aaf161d0"}, + {&sha_aid, "abc", "0164b8a914cd2a5e74c4f7ff082c4d97f1edf880"}, + {&sha_aid, kLong, "d2516ee1acfa5baf33dfc1c471e438449ef134c8"}, + {&sha1_aid, "abc", "a9993e364706816aba3e25717850c26c9cd0d89d"}, + {&sha1_aid, kLong, "84983e441c3bd26ebaae4aa1f95129e5e54670f1"}, + {&ripemd160_aid, "", "9c1185a5c5e9fc54612808977ee8f548b2258d31"}, + {&ripemd160_aid, "abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"}, + {&ripemd160_aid, kLong, "12a053384a9c0c88e405a06c27dcf49ada62eb2b"}, + }; +} + +OctetString ostr(const char *s) +{ + return OctetString{sec_uint4(std::strlen(s)), const_cast(s)}; +} + +} // namespace + +TEST(hash_known_answers_all) +{ + for (const auto &v : vectors()) { + OctetString in = ostr(v.msg); + OctetString out{0, nullptr}; + CHECK_EQ(sec_hash_all(&in, &out, v.aid, nullptr), 0); + CHECK_HEX(out.octets, out.noctets, v.digest); + aux_free2_OctetString(&out); + } +} + +TEST(hash_known_answers_incremental) +{ + for (const auto &v : vectors()) { + void *ctx = nullptr; + CHECK_EQ(sec_hash_init(&ctx, v.aid, nullptr), 0); + size_t n = std::strlen(v.msg); + for (size_t i = 0; i < n; i += 3) { + OctetString part{sec_uint4(std::min(3, n - i)), const_cast(v.msg + i)}; + CHECK_EQ(sec_hash_more(&ctx, &part), 0); + } + OctetString out{0, nullptr}; + CHECK_EQ(sec_hash_end(&ctx, &out), 0); + CHECK(ctx == nullptr); + CHECK_HEX(out.octets, out.noctets, v.digest); + aux_free2_OctetString(&out); + } +} + +TEST(hash_in_place_like_pkcs5_dialog) +{ + OctetString h{0, nullptr}; + OctetString in = ostr("abc"); + CHECK_EQ(sec_hash_all(&in, &h, &sha1_aid, nullptr), 0); + CHECK_EQ(sec_hash_all(&h, &h, &sha1_aid, nullptr), 0); + Bytes once = digest(Hash::SHA1, reinterpret_cast("abc"), 3); + Bytes twice = digest(Hash::SHA1, once.data(), once.size()); + CHECK_HEX(h.octets, h.noctets, testing::hex(twice.data(), twice.size())); +} + +TEST(hash_million_a) +{ + std::string a(1000000, 'a'); + OctetString in{sec_uint4(a.size()), &a[0]}; + OctetString out{0, nullptr}; + CHECK_EQ(sec_hash_all(&in, &out, &sha1_aid, nullptr), 0); + CHECK_HEX(out.octets, out.noctets, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + CHECK_EQ(sec_hash_all(&in, &out, &md5_aid, nullptr), 0); + CHECK_HEX(out.octets, out.noctets, "7707d6ae4e027c70eea2a935c2296f21"); + CHECK_EQ(sec_hash_all(&in, &out, &ripemd160_aid, nullptr), 0); + CHECK_HEX(out.octets, out.noctets, "52783243c1697bdbe16d37f97f68f08325dc1528"); +} + +TEST(hash_context_apis) +{ + unsigned char d[16]; + SEC_MD2_CTX m2; + sec_MD2Init(&m2); + sec_MD2Update(&m2, (unsigned char *)"message ", 8); + sec_MD2Update(&m2, (unsigned char *)"digest", 6); + sec_MD2Final(d, &m2); + CHECK_HEX(d, 16, "ab4f496bfb2a530b219ff33031fe06b0"); + SEC_MD4_CTX m4; + sec_MD4Init(&m4); + sec_MD4Update(&m4, (unsigned char *)"abc", 3); + sec_MD4Final(d, &m4); + CHECK_HEX(d, 16, "a448017aaf21d8525fc10ae87aa6729d"); + SEC_MD5_CTX m5; + sec_MD5Init(&m5); + sec_MD5Update(&m5, (unsigned char *)"message digest", 14); + sec_MD5Final(d, &m5); + CHECK_HEX(d, 16, "f96b697d7cb7938d525a2f31aaf161d0"); + + SHS_INFO s; + unsigned char be[20]; + shsInit(&s); + shsUpdate(&s, (unsigned char *)"ab", 2); + shsUpdate(&s, (unsigned char *)"c", 1); + shsFinal(&s); + for (int i = 0; i < 5; ++i) + for (int j = 0; j < 4; ++j) + be[4 * i + j] = (unsigned char)(s.digest[i] >> (24 - 8 * j)); + CHECK_HEX(be, 20, "0164b8a914cd2a5e74c4f7ff082c4d97f1edf880"); + shs1Init(&s); + shs1Update(&s, (unsigned char *)kLong, sec_int4(std::strlen(kLong))); + shs1Final(&s); + for (int i = 0; i < 5; ++i) + for (int j = 0; j < 4; ++j) + be[4 * i + j] = (unsigned char)(s.digest[i] >> (24 - 8 * j)); + CHECK_HEX(be, 20, "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); +} + +TEST(hash_builtin_matches_openssl) +{ + OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new(); + OSSL_PROVIDER_load(ctx, "default"); + bool legacy = OSSL_PROVIDER_load(ctx, "legacy") != nullptr; + struct { + Hash h; + const char *name; + } algs[] = {{Hash::MD4, "MD4"}, {Hash::MD5, "MD5"}, {Hash::SHA1, "SHA1"}, {Hash::RIPEMD160, "RIPEMD160"}}; + for (size_t len : {0u, 1u, 55u, 56u, 63u, 64u, 65u, 1000u}) { + Bytes msg = random_bytes(len); + for (const auto &a : algs) { + EVP_MD *md = EVP_MD_fetch(ctx, a.name, nullptr); + if (!md) { + CHECK(a.h == Hash::MD4 && !legacy); + continue; + } + unsigned char ref[EVP_MAX_MD_SIZE]; + unsigned int n = 0; + EVP_Digest(msg.data(), msg.size(), ref, &n, md, nullptr); + EVP_MD_free(md); + auto own = legacy::make_digest(a.h); + own->update(msg.data(), msg.size()); + Bytes d = own->final(); + CHECK_HEX(d.data(), d.size(), testing::hex(ref, n)); + } + } + OSSL_LIB_CTX_free(ctx); +} + +TEST(hash_unknown_algorithm_reports_error) +{ + OctetString in = ostr("abc"); + OctetString out{0, nullptr}; + CHECK_EQ(sec_hash_all(&in, &out, &desECB_aid, nullptr), -1); + CHECK_EQ(th_last_error(), EUNKNOWNALGID); + aux_free_error(); +} diff --git a/port/secude/tests/test_libec_binding.c b/port/secude/tests/test_libec_binding.c new file mode 100644 index 000000000..c5d5da150 --- /dev/null +++ b/port/secude/tests/test_libec_binding.c @@ -0,0 +1,29 @@ +/* Checks libec's statically initialised ECSecudeLib table (libec/sources/ECsecude.c). */ +#include + +#include "ECsecude.h" + +int secude_compat_test_libec(void) +{ + L_NUMBER a[MAXLGTH] = {1, 7}, b[MAXLGTH] = {1, 5}, m[MAXLGTH] = {1, 11}, r[MAXLGTH]; + OctetString msg, hash; + char abc[] = "abc"; + + if (!ECSecudeLib.arithmetic_mmult || !ECSecudeLib.sec_hash_all || !ECSecudeLib.sha1_aid || !ECSecudeLib.ripemd160_aid) + return 1; + if (ECSecudeLib.arithmetic_mmult(a, b, r, m) != 0 || r[0] != 1 || r[1] != 2) + return 2; + if (ECSecudeLib.arithmetic_comp(a, b) != 1 || ECSecudeLib.lngtouse(a) != 2) + return 3; + ECSecudeLib.arithmetic_div(a, b, r, b); + if (r[1] != 1 || b[1] != 2) + return 4; + msg.noctets = 3; + msg.octets = abc; + hash.noctets = 0; + hash.octets = NULL; + if (ECSecudeLib.sec_hash_all(&msg, &hash, ECSecudeLib.sha1_aid, NULL) != 0 || hash.noctets != 20 || + (unsigned char)hash.octets[0] != 0xa9) + return 5; + return 0; +} diff --git a/port/secude/tests/test_lnumber.cpp b/port/secude/tests/test_lnumber.cpp new file mode 100644 index 000000000..13f4bc5d2 --- /dev/null +++ b/port/secude/tests/test_lnumber.cpp @@ -0,0 +1,182 @@ +#include "bn.hpp" +#include "testing.hpp" + +#include + +using namespace compat; + +namespace { + +struct Ln { + L_NUMBER v[MAXGENL]; + Ln() { std::memset(v, 0, sizeof v); } +}; + +Ln ln_from(const BIGNUM *b) +{ + Ln l; + Bytes be = bn_bytes(b); + OctetString o{sec_uint4(be.size()), reinterpret_cast(be.data())}; + CHECK_EQ(aux_OctetString2LN2(l.v, &o), 0); + if (BN_is_negative(b)) + l.v[0] = L_NUMBER(~l.v[0] + 1); + return l; +} + +Bn bn_of(const Ln &l) +{ + Ln copy = l; + bool neg = copy.v[0] & 0x80000000u; + if (neg) + copy.v[0] = L_NUMBER(~copy.v[0] + 1); + OctetString *o = aux_LN2OctetString(copy.v, 0); + Bn b = bn_from(bytes_of(o)); + aux_free_OctetString(&o); + BN_set_negative(b.get(), neg); + return b; +} + +Bn rnd(int bits) +{ + Bn b = bn_new(); + if (bits > 0) + BN_rand(b.get(), bits, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); + return b; +} + +bool same(const BIGNUM *a, const Ln &l) +{ + return BN_cmp(a, bn_of(l).get()) == 0; +} + +} // namespace + +TEST(lnumber_layout) +{ + uint8_t be[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + OctetString o{5, reinterpret_cast(be)}; + L_NUMBER l[MAXLGTH]; + CHECK_EQ(aux_OctetString2LN2(l, &o), 0); + CHECK_EQ(l[0], L_NUMBER(2)); + CHECK_EQ(l[1], L_NUMBER(0x02030405)); + CHECK_EQ(l[2], L_NUMBER(0x01)); + CHECK_EQ(lngtouse(l), 32); + L_NUMBER zero[1] = {0}; + CHECK_EQ(lngtouse(zero), -1); + OctetString *back = aux_LN2OctetString(l, 8); + CHECK_HEX(back->octets, back->noctets, "0000000102030405"); + aux_free_OctetString(&back); + L_NUMBER big[3] = {2, 0, 0x01000000}; + back = aux_LN2OctetString(big, 2); + CHECK_HEX(back->octets, back->noctets, "0100000000000000"); + aux_free_OctetString(&back); +} + +TEST(lnumber_bitstring_and_random) +{ + uint8_t bits[] = {0xab, 0xcd}; + BitString b{12, reinterpret_cast(bits)}; + L_NUMBER l[MAXLGTH]; + CHECK_EQ(aux_BitString2LN2(l, &b), 0); + CHECK_EQ(l[0], L_NUMBER(1)); + CHECK_EQ(l[1], L_NUMBER(0xabc)); + for (int i = 0; i < 50; ++i) { + CHECK_EQ(rndm(1, l, 0), 0); + CHECK(l[0] == 0 || (l[0] == 1 && l[1] == 1)); + CHECK_EQ(rndm(100, l, 0), 0); + CHECK(lngtouse(l) < 100); + } +} + +TEST(lnumber_matches_bignum) +{ + BN_CTX *ctx = BN_CTX_new(); + for (int round = 0; round < 300; ++round) { + int sizes[] = {0, 1, 31, 32, 33, 64, 160, 239, 512, 1024, 2048}; + Bn a = rnd(sizes[round % 11]), b = rnd(sizes[(round / 11) % 11]); + Bn m = rnd(239 + round % 300); + BN_set_bit(m.get(), 0); + if (BN_is_zero(m.get()) || BN_is_one(m.get())) + BN_set_word(m.get(), 65537); + Ln la = ln_from(a.get()), lb = ln_from(b.get()), lm = ln_from(m.get()), r, q; + Bn e = bn_new(); + + CHECK_EQ(arithmetic_comp(la.v, lb.v), BN_cmp(a.get(), b.get())); + arithmetic_add(la.v, lb.v, r.v); + BN_add(e.get(), a.get(), b.get()); + CHECK(same(e.get(), r)); + arithmetic_sub(la.v, lb.v, r.v); + BN_sub(e.get(), a.get(), b.get()); + CHECK(same(e.get(), r)); + arithmetic_mult(la.v, lb.v, r.v); + BN_mul(e.get(), a.get(), b.get(), ctx); + CHECK(same(e.get(), r)); + if (!BN_is_zero(b.get())) { + Bn eq = bn_new(); + arithmetic_div(la.v, lb.v, q.v, r.v); + BN_div(eq.get(), e.get(), a.get(), b.get(), ctx); + CHECK(same(eq.get(), q)); + CHECK(same(e.get(), r)); + } + arithmetic_shift(la.v, 37, r.v); + BN_lshift(e.get(), a.get(), 37); + CHECK(same(e.get(), r)); + arithmetic_shift(la.v, -5, r.v); + BN_rshift(e.get(), a.get(), 5); + CHECK(same(e.get(), r)); + + CHECK_EQ(arithmetic_madd(la.v, lb.v, r.v, lm.v), 0); + BN_mod_add(e.get(), a.get(), b.get(), m.get(), ctx); + CHECK(same(e.get(), r)); + CHECK_EQ(arithmetic_msub(la.v, lb.v, r.v, lm.v), 0); + BN_mod_sub(e.get(), a.get(), b.get(), m.get(), ctx); + CHECK(same(e.get(), r)); + CHECK_EQ(arithmetic_mmult(la.v, lb.v, r.v, lm.v), 0); + BN_mod_mul(e.get(), a.get(), b.get(), m.get(), ctx); + CHECK(same(e.get(), r)); + CHECK_EQ(arithmetic_mexp(la.v, lb.v, r.v, lm.v), 0); + BN_mod_exp(e.get(), a.get(), b.get(), m.get(), ctx); + CHECK(same(e.get(), r)); + Bn inv = bn_new(); + ERR_set_mark(); + bool invertible = BN_mod_inverse(inv.get(), b.get(), m.get(), ctx) != nullptr; + ERR_pop_to_mark(); + int rc = arithmetic_mdiv(la.v, lb.v, r.v, lm.v); + if (invertible) { + CHECK_EQ(rc, 0); + BN_mod_mul(e.get(), a.get(), inv.get(), m.get(), ctx); + CHECK(same(e.get(), r)); + } else { + CHECK_EQ(rc, -1); + } + } + aux_free_error(); + BN_CTX_free(ctx); +} + +TEST(lnumber_aliasing_like_libec) +{ + Bn a = rnd(300), m = rnd(301); + BN_set_bit(m.get(), 300); + Ln la = ln_from(a.get()), lm = ln_from(m.get()); + arithmetic_mmult(la.v, la.v, la.v, lm.v); + Bn e = bn_new(); + BN_CTX *ctx = BN_CTX_new(); + BN_mod_mul(e.get(), a.get(), a.get(), m.get(), ctx); + CHECK(same(e.get(), la)); + Ln n = ln_from(e.get()), tmp; + arithmetic_div(n.v, lm.v, tmp.v, n.v); + BN_nnmod(e.get(), e.get(), m.get(), ctx); + CHECK(same(e.get(), n)); + BN_CTX_free(ctx); +} + +TEST(lnumber_zero_result_clears_first_word) +{ + // libec's ln_to_string reads rem[1] without looking at rem[0] + L_NUMBER a[MAXLGTH] = {1, 32}, b[MAXLGTH] = {1, 16}, q[MAXLGTH], r[MAXLGTH] = {1, 0xdeadbeef}; + arithmetic_div(a, b, q, r); + CHECK_EQ(q[1], L_NUMBER(2)); + CHECK_EQ(r[0], L_NUMBER(0)); + CHECK_EQ(r[1], L_NUMBER(0)); +} diff --git a/port/secude/tests/test_pkcs12.cpp b/port/secude/tests/test_pkcs12.cpp new file mode 100644 index 000000000..394264d7a --- /dev/null +++ b/port/secude/tests/test_pkcs12.cpp @@ -0,0 +1,177 @@ +#include "bn.hpp" +#include "testing.hpp" + +#include +#include + +using namespace compat; + +namespace { + +std::string root() { return testing::scratch_dir() + "/p12"; } + +// CrypTool's PKCS12_encode (SecudeTools.cpp) +OctetString *export_pse(PSE pse, OctetString *PIN, int encrypt_priv_key) +{ + P12_Safe P12safe; + std::memset(&P12safe, 0, sizeof(P12safe)); + P12safe.version = 3; + P12safe.iterationCount = 2048; + P12safe.alg_oid.mac = aux_cpy_ObjId(&sha1_oid); + P12safe.alg_oid.enc = aux_cpy_ObjId(&pbeWithSHA1And40BitRC2CBC_oid); + P12safe.alg_oid.espvk = aux_cpy_ObjId(&pbeWithSHA1AndDES3xCBC_oid); + CHECK(sec_onekeypaironly(af_get_PSESel(pse, nullptr))); + ObjId oid; + Certificate *cert = (Certificate *)af_pse_get(pse, const_cast("Cert"), &oid); + KeyInfo *key = (KeyInfo *)af_pse_get(pse, const_cast("SKnew"), &oid); + CHECK(cert && key); + char oarr[4] = {0x01, 0x00, 0x00, 0x00}; + OctetString ostr{4, oarr}; + OctetString *lkid = aux_cpy_OctetString(&ostr); + + P12_Bag *keybag = (P12_Bag *)aux_malloc(sizeof(P12_Bag)); + std::memset(keybag, 0, sizeof(P12_Bag)); + keybag->int_encryption = encrypt_priv_key; + keybag->type = P12_bc_key; + keybag->friendlyName = aux_latin1_to_unicode(const_cast("name"), FALSE); + keybag->localKeyID = aux_cpy_OctetString(lkid); + keybag->content.key = aux_create_PrivateKeyInfo(key, cert, nullptr); + CHECK(keybag->content.key != nullptr); + P12_Bag *certbag = (P12_Bag *)aux_malloc(sizeof(P12_Bag)); + std::memset(certbag, 0, sizeof(P12_Bag)); + certbag->int_encryption = TRUE; + certbag->type = P12_bc_cert; + certbag->localKeyID = lkid; + certbag->content.cert = cert; + keybag->next = certbag; + P12safe.bags = keybag; + aux_free_KeyInfo(&key); + + PKRoot *pkroot = af_pse_get_PKRoot(pse); + if (pkroot) { + P12_Bag *rootbag = (P12_Bag *)aux_malloc(sizeof(P12_Bag)); + std::memset(rootbag, 0, sizeof(P12_Bag)); + rootbag->int_encryption = TRUE; + rootbag->type = P12_bc_cert; + rootbag->content.cert = af_PKRoot2Protocert(pkroot); + certbag->next = rootbag; + aux_free_PKRoot(&pkroot); + } + OctetString *P12container = aux_alloc_OctetString(); + CHECK_EQ(pkcs12_encode(&P12safe, PIN, P12container), 0); + return P12container; +} + +} // namespace + +TEST(pkcs12_export_import_round_trip) +{ + std::string dir = root(); + CHECK_EQ(secude_compat_create_sample_keystore(dir.c_str(), 0), 0); + std::string bob = dir + "/PSE/[SideChannelAttack][Bob][RSA-512][1152179494][PIN=1234].pse"; + PSE pse = af_open(const_cast(bob.c_str()), nullptr, const_cast("1234"), nullptr); + CHECK(pse != nullptr); + OctetString *pw = aux_latin1_to_unicode(const_cast("secret"), TRUE); + OctetString *p12 = export_pse(pse, pw, TRUE); + CHECK(p12 && p12->noctets > 500); + char *dump = sdumpasn(p12, 0, 0); + CHECK(std::string(dump).find("FATAL") == std::string::npos); + aux_free_String(&dump); + + // CrypTool's PKCS12_import into a new PSE + P12_Safe safe; + std::memset(&safe, 0, sizeof safe); + Boolean verified = 0; + CHECK_EQ(pkcs12_decode(p12, pw, &safe, &verified), 0); + CHECK(verified); + CHECK_EQ(safe.iterationCount, 2048); + CHECK_EQ(aux_cmp_ObjId(safe.alg_oid.enc, &pbeWithSHA1And40BitRC2CBC_oid), 0); + int keys = 0, certs = 0; + PrivateKeyInfo *pki = nullptr; + for (P12_Bag *b = safe.bags; b; b = b->next) { + if (b->type == P12_bc_key) { + ++keys; + pki = b->content.key; + CHECK(b->localKeyID && b->friendlyName); + } else if (b->type == P12_bc_cert) { + ++certs; + } + } + CHECK_EQ(keys, 1); + CHECK_EQ(certs, 2); + CHECK_EQ(aux_ObjId2AlgEnc(pki->privateKeyAlgorithm->objid), SECUDE_ALG_RSA); + RSAPrivateKey *rsa = d_RSAPrivateKey(pki->privateKey); + CHECK(rsa && rsa->pubex.noctets == 3); + KeyInfo *orig = (KeyInfo *)af_pse_get(pse, const_cast("SKnew"), nullptr); + KeyBits *kb = d_KeyBits(&orig->subjectkey); + CHECK(bytes_of(&kb->part1) == bytes_of(&rsa->prime1)); + CHECK(bytes_of(&kb->part2) == bytes_of(&rsa->prime2)); + aux_free_KeyBits(&kb); + aux_free_KeyInfo(&orig); + aux_free_RSAPrivateKey(&rsa); + + OctetString *wrong = aux_latin1_to_unicode(const_cast("wrong"), TRUE); + P12_Safe other; + std::memset(&other, 0, sizeof other); + CHECK_EQ(pkcs12_decode(p12, wrong, &other, &verified), -1); + CHECK(!verified); + aux_free_error(); + + // the same file is readable by OpenSSL (MAC and shrouded key do not need the legacy provider) + const unsigned char *p = reinterpret_cast(p12->octets); + PKCS12 *ossl = d2i_PKCS12(nullptr, &p, long(p12->noctets)); + CHECK(ossl != nullptr); + CHECK_EQ(PKCS12_verify_mac(ossl, "secret", -1), 1); + PKCS12_free(ossl); + + aux_free_OctetString(&wrong); + aux_free_OctetString(&p12); + aux_free_OctetString(&pw); + af_close(pse); +} + +TEST(pkcs12_import_openssl_default_file) +{ + // RSA key and certificate created by OpenSSL 3 with its defaults (PBES2, AES-256, SHA-256 MAC) + EVP_PKEY *pkey = EVP_RSA_gen(1024); + X509 *x = X509_new(); + X509_set_version(x, 2); + ASN1_INTEGER_set(X509_get_serialNumber(x), 7); + X509_gmtime_adj(X509_getm_notBefore(x), 0); + X509_gmtime_adj(X509_getm_notAfter(x), 3600); + X509_set_pubkey(x, pkey); + X509_NAME *name = X509_get_subject_name(x); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast("OpenSSL user"), -1, -1, 0); + X509_set_issuer_name(x, name); + X509_sign(x, pkey, EVP_sha256()); + PKCS12 *p12 = PKCS12_create("pass", "friendly", pkey, x, nullptr, 0, 0, 0, 0, 0); + CHECK(p12 != nullptr); + unsigned char *der = nullptr; + int len = i2d_PKCS12(p12, &der); + OctetString in{sec_uint4(len), reinterpret_cast(der)}; + OctetString *pw = aux_latin1_to_unicode(const_cast("pass"), TRUE); + P12_Safe safe; + std::memset(&safe, 0, sizeof safe); + Boolean verified = 0; + CHECK_EQ(pkcs12_decode(&in, pw, &safe, &verified), 0); + CHECK(verified); + int keys = 0, certs = 0; + for (P12_Bag *b = safe.bags; b; b = b->next) { + if (b->type == P12_bc_key) { + ++keys; + RSAPrivateKey *rsa = d_RSAPrivateKey(b->content.key->privateKey); + CHECK(rsa != nullptr); + aux_free_RSAPrivateKey(&rsa); + } else if (b->type == P12_bc_cert) { + ++certs; + CHECK_EQ(std::string(aux_DName2Name(b->content.cert->tbs->subject)), std::string("CN=OpenSSL user")); + } + } + CHECK_EQ(keys, 1); + CHECK_EQ(certs, 1); + aux_free_OctetString(&pw); + OPENSSL_free(der); + PKCS12_free(p12); + X509_free(x); + EVP_PKEY_free(pkey); +} diff --git a/port/secude/tests/test_pse.cpp b/port/secude/tests/test_pse.cpp new file mode 100644 index 000000000..628e9890d --- /dev/null +++ b/port/secude/tests/test_pse.cpp @@ -0,0 +1,552 @@ +// Integration tests replaying the call sequences of the CrypTool dialogs. +#include "bn.hpp" +#include "testing.hpp" + +#include +#include +#include +#include + +using namespace compat; + +namespace { + +const char kCaPin[] = SECUDE_COMPAT_CA_PIN; + +struct Store { + std::string root, pse_dir, ca_dir, ca_pse; +}; + +const Store &store() +{ + static Store s = [] { + Store st; + st.root = testing::scratch_dir() + "/keystore"; + st.pse_dir = st.root + "/PSE"; + st.ca_dir = st.pse_dir + "/PSECA"; + st.ca_pse = st.ca_dir + "/capse.cse"; + if (secude_compat_create_sample_keystore(st.root.c_str(), 0) != 0) + testing::report_failure(__FILE__, __LINE__, std::string("keystore creation: ") + th_get_last_error_text()); + return st; + }(); + return s; +} + +char *cstr(const std::string &s) { return const_cast(s.c_str()); } + +PSE open_ca() +{ + return af_open(cstr(store().ca_pse), cstr(store().ca_dir), const_cast(kCaPin), nullptr); +} + +std::string read_text(const std::string &path) +{ + std::ifstream f(path, std::ios::binary); + std::stringstream ss; + ss << f.rdbuf(); + return ss.str(); +} + +std::string text_of(char *s) +{ + std::string r = s ? s : ""; + aux_free_String(&s); + return r; +} + +// CDlgKeyAsymGeneration::CreateAsymKeys for RSA/DSA +std::string create_user(const std::string &name, const std::string &first, bool dsa, int bits, const std::string &time, + const char *pin) +{ + std::string key_id = "[" + name + "][" + first + "][" + (dsa ? "DSA-" : "RSA-") + std::to_string(bits) + "][" + time + "]"; + std::string path = store().pse_dir + "/" + key_id + ".pse"; + PSE pse = af_create(cstr(path), nullptr, const_cast(pin), nullptr, TRUE); + CHECK(pse != nullptr); + Key keyinfo{}; + keyinfo.alg = dsa ? &dsa_aid : &rsa_aid; + keyinfo.key_size = bits; + CHECK_EQ(af_gen_key(pse, &keyinfo, SIGNATURE, 1), 0); + char serial_text[] = "000001"; + OctetString SNummer{6, serial_text}; + std::string dn_text = "CN=" + first + " " + name + " [" + time + "], DC=cryptool, DC=org"; + DName *DisName = aux_Name2DName(cstr(dn_text)); + AlgId *alg = dsa ? &dsaWithSHA1_aid : &sha1WithRSASignature_aid; + Certificate *Zert = af_create_Certificate(pse, keyinfo.key, alg, const_cast("SKnew"), DisName, &SNummer, + nullptr, nullptr, TRUE, nullptr); + CHECK(Zert != nullptr); + + SEQUENCE_OF_Extension extensions; + extensions.element = (v3Extension *)aux_malloc(sizeof(v3Extension)); + static ObjId oid; + static unsigned int oid_n[6] = {2, 206, 5, 4, 3, 2}; + oid.oid_nelem = 6; + oid.oid_elements = oid_n; + extensions.element->extnId = &oid; + extensions.element->critical = false; + extensions.element->extnDERcode = e_PrintableString(cstr(key_id)); + extensions.next = nullptr; + CertExtensions cert_ext; + std::memset(&cert_ext, 0, sizeof(CertExtensions)); + cert_ext.nonSupported = &extensions; + Zert->tbs->extensions = &cert_ext; + + PSE PseHandle2 = open_ca(); + CHECK(PseHandle2 != nullptr); + SerialNumber *serial = sec_random_ostr(8, 1); + CHECK(af_cadb_get_Certificate(PseHandle2, serial) == nullptr); + aux_free_error(); + CHECK_EQ(af_pse_update_SerialNumber(PseHandle2, serial), 0); + Certificate *Zert2 = af_certify(PseHandle2, Zert, nullptr, &sha1WithRSASignature_aid, nullptr); + CHECK(Zert2 != nullptr); + CHECK(Zert2->tbs->serialnumber->noctets >= 1); + CHECK_EQ(af_cadb_add_Certificate(PseHandle2, SIGNATURE, Zert2), 0); + CHECK_EQ(af_cadb_add_Certificate(PseHandle2, SIGNATURE, Zert2), -1); + aux_free_error(); + PKRoot *pkroot = af_pse_get_PKRoot(PseHandle2); + CHECK(pkroot != nullptr); + CHECK_EQ(af_pse_update_PKRoot(pse, pkroot), 0); + aux_free_PKRoot(&pkroot); + CHECK_EQ(af_pse_update(pse, const_cast("Cert"), Zert2, *&Cert_OID), 0); + af_close(PseHandle2); + aux_free_DName(&DisName); + af_close(pse); + aux_free_OctetString(&serial); + aux_free_Certificate(&Zert2); + aux_free_OctetString(&extensions.element->extnDERcode); + aux_free(extensions.element); + Zert->tbs->extensions = nullptr; + aux_free_Certificate(&Zert); + aux_free_KeyInfo(&keyinfo.key); + return key_id; +} + +Certificate *ca_lookup(const std::string &dn) +{ + PSE ca = open_ca(); + SET_OF_IssuedCertificate *Liste = af_cadb_get_user(ca, cstr(dn)); + CHECK(Liste != nullptr); + Certificate *Zert = Liste ? af_cadb_get_Certificate(ca, Liste->element->serial) : nullptr; + CHECK(Zert != nullptr); + aux_free_SET_OF_IssuedCertificate(&Liste); + af_close(ca); + return Zert; +} + +} // namespace + +TEST(pse_create_open_and_pin) +{ + std::string path = testing::scratch_dir() + "/test.pse"; + PSE pse = af_create(cstr(path), nullptr, const_cast("1234"), nullptr, TRUE); + CHECK(pse != nullptr); + CHECK_EQ(std::string(pse->pse_name), path); + CHECK(af_create(cstr(path), nullptr, const_cast("1234"), nullptr, TRUE) == nullptr); + CHECK_EQ(th_last_error(), EPSEALREADYEXISTING); + CHECK_EQ(af_close(pse), 0); + + CHECK(af_open(cstr(path), nullptr, const_cast("4321"), nullptr) == nullptr); + CHECK_EQ(th_last_error(), EPIN); + CHECK(af_open(cstr(path), cstr(store().ca_dir), const_cast("NULL"), nullptr) == nullptr); + CHECK_EQ(th_last_error(), EPIN); + pse = af_open(cstr(path), nullptr, const_cast("1234"), nullptr); + CHECK(pse != nullptr); + af_close(pse); + + std::string junk = testing::scratch_dir() + "/junk.pse"; + std::ofstream(junk) << "not a PSE"; + CHECK(af_open(cstr(junk), nullptr, const_cast("1234"), nullptr) == nullptr); + CHECK(th_last_error() != EPIN); + CHECK(af_open(cstr(testing::scratch_dir() + "/missing.pse"), nullptr, const_cast("1"), nullptr) == nullptr); + CHECK_EQ(th_last_error(), EPSENOTEXISTING); + aux_free_error(); + + OctetString *raw = aux_file2OctetString(cstr(path)); + std::string dump = text_of(sdumpasn(raw, 0, 0)); + CHECK(dump.find("FATAL") == std::string::npos && dump.find("junk") == std::string::npos); + aux_free_OctetString(&raw); + CHECK(aux_file2OctetString(cstr(testing::scratch_dir() + "/nothing")) == nullptr); + CHECK_EQ(th_last_error(), EFILENOTEXISTING); + aux_free_error(); +} + +TEST(pse_objects_and_selectors) +{ + std::string path = testing::scratch_dir() + "/objects.pse"; + PSE pse = af_create(cstr(path), nullptr, const_cast("pin"), nullptr, FALSE); + char raw[] = "\x01\x02\x03"; + OctetString value{3, raw}; + OctetString *ostr = e_OctetString(&value); + ObjId *uid_before = Uid_OID; + CHECK_EQ(af_pse_update(pse, const_cast("EcPrivKey"), ostr, *&Uid_OID), 0); + aux_free_OctetString(&ostr); + af_close(pse); + + pse = af_open(cstr(path), nullptr, const_cast("pin"), nullptr); + OctetString *got = (OctetString *)af_pse_get(pse, const_cast("EcPrivKey"), Uid_OID); + CHECK(got != nullptr); + OctetString *inner = d_OctetString(got); + CHECK_HEX(inner->octets, inner->noctets, "010203"); + L_NUMBER l[MAXLGTH]; + CHECK_EQ(aux_OctetString2LN2(l, inner), 0); + CHECK_EQ(l[1], L_NUMBER(0x010203)); + CHECK(Uid_OID == uid_before); + CHECK_EQ(Uid_OID->oid_nelem, 5); + + PSESel *sel = af_get_PSESel(pse, nullptr); + CHECK_EQ(sec_onekeypaironly(sel), FALSE); + sel->object = aux_cpy_String(const_cast(Toc_name)); + OctetString toc_der{0, nullptr}; + CHECK_EQ(sec_read(sel, &toc_der), 0); + PSEToc *toc = d_PSEToc(&toc_der); + CHECK(toc && toc->obj && std::string(toc->obj->name) == "EcPrivKey"); + aux_free_PSEToc(&toc); + aux_free2_OctetString(&toc_der); + ObjId oid; + CHECK(af_pse_get(pse, const_cast("missing"), &oid) == nullptr); + CHECK_EQ(th_last_error(), EPSEOBJECTNOTEXISTING); + aux_free_error(); + aux_free_OctetString(&got); + aux_free_OctetString(&inner); + af_close(pse); +} + +TEST(pse_key_generation_certification_and_use) +{ + std::string id = create_user("Doe", "Alice", false, 768, "1700000000", "4711"); + Certificate *Zert = ca_lookup("CN=Alice Doe [1700000000], DC=cryptool, DC=org"); + CHECK_EQ(Zert->tbs->subjectPK->subjectAI->objid->oid_nelem, 5); + char *alg_name = aux_sprint_AlgId(nullptr, Zert->tbs->subjectPK->subjectAI); + CHECK_EQ(std::string(alg_name), std::string("Algorithm RSA (OID 2.5.8.1.1), Keysize = 768")); + aux_free(&alg_name); + aux_free_String(&alg_name); + + // private PSE name extension (used by the PKCS#12 import) + char *pse_name = nullptr; + for (SEQUENCE_OF_Extension *x = Zert->tbs->extensions ? Zert->tbs->extensions->nonSupported : nullptr; x; x = x->next) + if (x->element->extnId->oid_nelem == 6 && x->element->extnId->oid_elements[1] == 206) + pse_name = d_PrintableString(x->element->extnDERcode); + CHECK(pse_name && std::string(pse_name) == id); + aux_free(pse_name); + + // RsaEnc / RsaDec + std::string doc = "CrypTool RSA encryption round trip"; + OctetString in{sec_uint4(doc.size()), cstr(doc)}; + std::vector buf(doc.size() + doc.size() / 37 + 1025); + BitString out{0, buf.data()}; + Key Schluessel{}; + Schluessel.key = Zert->tbs->subjectPK; + Schluessel.alg = &rsa_aid; + PSE ca = open_ca(); + CHECK_EQ(af_encrypt_all(ca, &in, &out, &Schluessel, nullptr), 0); + af_close(ca); + CHECK_EQ(out.nbits, sec_uint4(96 * 8)); + OctetString *outOctet = aux_BString2OString(&out); + PSE user = af_open(cstr(store().pse_dir + "/" + id + ".pse"), nullptr, const_cast("4711"), nullptr); + CHECK(user != nullptr); + BitString cin{outOctet->noctets * 8, outOctet->octets}; + std::vector plain(cin.nbits / 8 + 256); + OctetString dec{0, plain.data()}; + Key priv{}; + priv.alg = &rsa_aid; + CHECK_EQ(af_decrypt_all(user, &cin, &dec, &priv), 0); + CHECK_EQ(dec.noctets, sec_uint4(95)); + CHECK_EQ(std::string(dec.octets, doc.size()), doc); + aux_free_OctetString(&outOctet); + + // Sign / Verify + Signature Signatur; + Signatur.signAI = &ripemd160WithRSASignature_aid; + user->options.af_sign_check_Validity = FALSE; + CHECK_EQ(af_sign_all(user, &in, &Signatur), 0); + Key keyinfo{}; + keyinfo.key = Zert->tbs->subjectPK; + CHECK_EQ(sec_verify_all(&in, &Signatur, &keyinfo, nullptr), 0); + int sig_bits = 0, enc_bits = 0; + AlgEnc sig_type = NoAlgEnc; + CHECK_EQ(af_pse_get_keysize(user, &sig_bits, &enc_bits, &sig_type), 0); + CHECK_EQ(sig_bits, 768); + CHECK_EQ(sig_type, SECUDE_ALG_RSA); + + // certificate display (CDlgKeyAsym / sprint_Certificate_with_key) + *(sec_uint4 *)secude_compat_symbol("print_cert_flag") = TBS | KEYINFO | VAL | ISSUER | ALG | SIGNAT | HSH | VER | SUBJECT | EXTENSIONS; + *(sec_uint4 *)secude_compat_symbol("print_keyinfo_flag") = ALGID | KEYBITS | PK; + std::string text = text_of(aux_sprint_Certificate(user, nullptr, Zert)); + CHECK(text.find("Modulus (768 bits)") != std::string::npos); + CHECK(text.find("Public exponent") != std::string::npos); + CHECK(text.find("CrypToolPSEName: " + id) != std::string::npos); + CHECK(text.find("Issuer: CN=CrypTool CA 2, DC=cryptool, DC=org") != std::string::npos); + + // PKRoot copied from the CA reconstructs the CA certificate + PKRoot *root = af_pse_get_PKRoot(user); + Certificate *proto = af_PKRoot2Protocert(root); + ca = open_ca(); + Certificate *ca_cert = af_pse_get_Certificate(ca, SIGNATURE, nullptr, nullptr); + OctetString *a = e_Certificate(proto), *b = e_Certificate(ca_cert); + CHECK(a->noctets == b->noctets && !std::memcmp(a->octets, b->octets, a->noctets)); + Key ca_key{}; + ca_key.key = ca_cert->tbs->subjectPK; + CHECK_EQ(sec_verify_all(Zert->tbs_DERcode, Zert->sig, &ca_key, nullptr), 0); + Certificates *certs = af_pse_get_Certificates(user, ENCRYPTION, nullptr); + CHECK(certs && certs->usercertificate && !certs->forwardpath); + aux_free_Certificates(&certs); + aux_free_OctetString(&a); + aux_free_OctetString(&b); + aux_free_Certificate(&proto); + aux_free_Certificate(&ca_cert); + aux_free_PKRoot(&root); + af_close(ca); + af_close(user); + aux_free2_BitString(&Signatur.signature); + aux_free_Certificate(&Zert); +} + +TEST(pse_dsa_user) +{ + std::string id = create_user("Dsa", "Dave", true, 512, "1700000001", "dsa"); + Certificate *Zert = ca_lookup("CN=Dave Dsa [1700000001], DC=cryptool, DC=org"); + CHECK_EQ(Zert->tbs->subjectPK->subjectAI->objid->oid_nelem, 6); + PSE user = af_open(cstr(store().pse_dir + "/" + id + ".pse"), nullptr, const_cast("dsa"), nullptr); + char msg[] = "signed by DSA"; + OctetString in{sec_uint4(std::strlen(msg)), msg}; + for (AlgId *alg : {&dsaWithSHA_aid, &dsaWithSHA1_aid}) { + Signature s; + s.signAI = alg; + CHECK_EQ(af_sign_all(user, &in, &s), 0); + Key k{}; + k.key = Zert->tbs->subjectPK; + CHECK_EQ(sec_verify_all(&in, &s, &k, nullptr), 0); + aux_free2_BitString(&s.signature); + } + af_close(user); + aux_free_Certificate(&Zert); +} + +TEST(pse_tutorial_flow_with_user_chosen_exponent) +{ + // CPSEDemo::CreatePSE / AccessPSE with p, q and e chosen by the user + Bn p = bn_new(), q = bn_new(), e = bn_word(17), n = bn_new(), one = bn_word(1), g = bn_new(), t = bn_new(); + BN_CTX *ctx = BN_CTX_new(); + do { + BN_generate_prime_ex(p.get(), 256, 0, nullptr, nullptr, nullptr); + BN_sub(t.get(), p.get(), one.get()); + BN_gcd(g.get(), t.get(), e.get(), ctx); + } while (!BN_is_one(g.get())); + do { + BN_generate_prime_ex(q.get(), 256, 0, nullptr, nullptr, nullptr); + BN_sub(t.get(), q.get(), one.get()); + BN_gcd(g.get(), t.get(), e.get(), ctx); + } while (!BN_is_one(g.get())); + BN_mul(n.get(), p.get(), q.get(), ctx); + BN_CTX_free(ctx); + + KeyBits keybits; + std::memset(&keybits, 0, sizeof(KeyBits)); + Bytes pb = bn_bytes(p.get()), qb = bn_bytes(q.get()), nb = bn_bytes(n.get()), eb = bn_bytes(e.get()); + keybits.part1 = {sec_uint4(pb.size()), reinterpret_cast(pb.data())}; + keybits.part2 = {sec_uint4(qb.size()), reinterpret_cast(qb.data())}; + BitString *bitstring = e_KeyBits(&keybits); + KeyInfo keyinfo; + CHECK_EQ(aux_cpy2_BitString(&keyinfo.subjectkey, bitstring), 0); + aux_free_BitString(&bitstring); + keyinfo.subjectAI = aux_cpy_AlgId(&rsa_aid); + *reinterpret_cast(keyinfo.subjectAI->param) = 512; + + std::string name = store().pse_dir + "/[Tutorial][Tom][RSA-512][1].pse"; + PSE m_hPSE = af_create(cstr(name), nullptr, const_cast("tut"), nullptr, TRUE); + PSE_Sel *psesel = af_get_PSESel(m_hPSE, static_cast(0)); + psesel->object = aux_cpy_String(const_cast(SKnew_name)); + psesel->object_type = &SKnew_oid; + OctetString *octetstring = e_KeyInfo(&keyinfo); + aux_free2_KeyInfo(&keyinfo); + CHECK_EQ(sec_write_PSE(psesel, octetstring), 0); + aux_free_OctetString(&octetstring); + + char serial_text[] = "000001"; + OctetString osSerial{6, serial_text}; + DName *dn = aux_Name2DName(const_cast("CN=Tom Tutorial [1], DC=cryptool, DC=org")); + std::memset(&keybits, 0, sizeof(KeyBits)); + keybits.part1 = {sec_uint4(nb.size()), reinterpret_cast(nb.data())}; + keybits.part2 = {sec_uint4(eb.size()), reinterpret_cast(eb.data())}; + bitstring = e_KeyBits(&keybits); + CHECK_EQ(aux_cpy2_BitString(&keyinfo.subjectkey, bitstring), 0); + aux_free_BitString(&bitstring); + keyinfo.subjectAI = aux_cpy_AlgId(&rsa_aid); + Certificate *Cert = af_create_Certificate(m_hPSE, &keyinfo, &sha1WithRSASignature_aid, const_cast("SKnew"), dn, + &osSerial, nullptr, nullptr, TRUE, nullptr); + CHECK(Cert != nullptr); + Key self{}; + self.key = &keyinfo; + CHECK_EQ(sec_verify_all(Cert->tbs_DERcode, Cert->sig, &self, nullptr), 0); + PSE hPSE_CA = open_ca(); + Certificate *Cert_CA = af_certify(hPSE_CA, Cert, nullptr, &sha1WithRSASignature_aid, nullptr); + CHECK_EQ(af_cadb_add_Certificate(hPSE_CA, SIGNATURE, Cert_CA), 0); + CHECK_EQ(af_pse_update(m_hPSE, const_cast("Cert"), Cert_CA, *&Cert_OID), 0); + af_close(hPSE_CA); + af_close(m_hPSE); + + // AccessPSE + PSESel *sel = sec_open(cstr(name), const_cast("tut"), nullptr); + CHECK(sel != nullptr); + sel->object = aux_cpy_String(const_cast(SKnew_name)); + sel->object_type = aux_cpy_ObjId(&SKnew_oid); + OctetString value; + CHECK_EQ(sec_read_PSE(sel, &value), 0); + KeyInfo *ki = d_KeyInfo(&value); + KeyBits *kb = d_KeyBits(&ki->subjectkey); + CHECK(bytes_of(&kb->part1) == pb && bytes_of(&kb->part2) == qb); + aux_free_KeyInfo(&ki); + aux_free2_OctetString(&value); + aux_free_KeyBits(&kb); + aux_free_String(&sel->object); + aux_free_ObjId(&sel->object_type); + sel->object = aux_cpy_String(const_cast(Cert_name)); + sel->object_type = aux_cpy_ObjId(&Cert_oid); + CHECK_EQ(sec_read_PSE(sel, &value), 0); + Certificate *cert = d_Certificate(&value); + CHECK_EQ(text_of(aux_DName2Name(cert->tbs->subject)), std::string("CN=Tom Tutorial [1], DC=cryptool, DC=org")); + kb = d_KeyBits(&cert->tbs->subjectPK->subjectkey); + CHECK(bytes_of(&kb->part2) == eb); + aux_free_KeyBits(&kb); + aux_free_Certificate(&cert); + aux_free2_OctetString(&value); + CHECK_EQ(sec_close(sel), 0); + + // private key operations use the exponent of the PSE certificate + PSE pse = af_open(cstr(name), nullptr, const_cast("tut"), nullptr); + char msg[] = "tutorial"; + OctetString in{8, msg}; + Signature s; + s.signAI = &md5WithRsaEncryption_aid; + CHECK_EQ(af_sign_all(pse, &in, &s), 0); + Key k{}; + k.key = Cert_CA->tbs->subjectPK; + CHECK_EQ(sec_verify_all(&in, &s, &k, nullptr), 0); + aux_free2_BitString(&s.signature); + af_close(pse); + aux_free_DName(&dn); + aux_free2_KeyInfo(&keyinfo); + aux_free_Certificate(&Cert); + aux_free_Certificate(&Cert_CA); +} + +TEST(pse_sample_keystore) +{ + const Store &st = store(); + std::string rsa = st.pse_dir + "/[SideChannelAttack][Bob][RSA-512][1152179494][PIN=1234].pse"; + PSE bob = af_open(cstr(rsa), nullptr, const_cast("1234"), nullptr); + CHECK(bob != nullptr); + Certificate *Zert = ca_lookup("CN=Bob SideChannelAttack [1152179494], DC=cryptool, DC=org"); + + // CDlgHybridEncryptionDemo: session key left padded to (512-1)/8 octets + Bytes session = random_bytes(16); + Bytes padded(63 - 16, 0); + padded.insert(padded.end(), session.begin(), session.end()); + OctetString in{63, reinterpret_cast(padded.data())}; + std::vector buf(2048); + BitString out{0, buf.data()}; + Key Schluessel{}; + Schluessel.key = Zert->tbs->subjectPK; + Schluessel.alg = &rsa_aid; + PSE ca = open_ca(); + CHECK_EQ(af_encrypt_all(ca, &in, &out, &Schluessel, nullptr), 0); + af_close(ca); + CHECK_EQ(out.nbits, sec_uint4(512)); + std::vector dbuf(64 + 256); + OctetString dec{0, dbuf.data()}; + Key priv{}; + priv.alg = &rsa_aid; + CHECK_EQ(af_decrypt_all(bob, &out, &dec, &priv), 0); + CHECK_EQ(dec.noctets, sec_uint4(63)); + CHECK(Bytes(dbuf.begin() + 47, dbuf.begin() + 63) == session); + af_close(bob); + aux_free_Certificate(&Zert); + + // EC key of the hybrid encryption demo: text file with domain parameters and public key + std::string ec = st.pse_dir + "/[HybridEncryption][Bob][EC-prime239v1][1178702474][PIN=1234]"; + std::istringstream lines(read_text(ec)); + std::vector v; + for (std::string line; std::getline(lines, line);) + v.push_back(line); + CHECK_EQ(v.size(), size_t(9)); + CHECK_EQ(v[0], std::string("0X7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC")); + CHECK_EQ(v[3], std::string("0XFFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF")); + CHECK_EQ(v[5], std::string("0X1")); + PSE ecpse = af_open(cstr(ec + ".pse"), nullptr, const_cast("1234"), nullptr); + CHECK(ecpse != nullptr); + OctetString *ostr = (OctetString *)af_pse_get(ecpse, const_cast("EcPrivKey"), *&Uid_OID); + af_close(ecpse); + OctetString *d = d_OctetString(ostr); + Bn priv_key = bn_from(bytes_of(d)); + EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_X9_62_prime239v1); + EC_POINT *q = EC_POINT_new(group); + Bn x = bn_new(), y = bn_new(); + EC_POINT_mul(group, q, priv_key.get(), nullptr, nullptr, nullptr); + EC_POINT_get_affine_coordinates(group, q, x.get(), y.get(), nullptr); + char *xs = BN_bn2hex(x.get()), *ys = BN_bn2hex(y.get()); + std::string xh = xs, yh = ys; + while (xh.size() > 1 && xh[0] == '0') + xh.erase(0, 1); + while (yh.size() > 1 && yh[0] == '0') + yh.erase(0, 1); + CHECK_EQ(v[7], "0X" + xh); + CHECK_EQ(v[8], "0X" + yh); + OPENSSL_free(xs); + OPENSSL_free(ys); + EC_POINT_free(q); + EC_GROUP_free(group); + aux_free_OctetString(&ostr); + aux_free_OctetString(&d); + + // serial numbers handed out by the CA increase + ca = open_ca(); + SerialNumber *s1 = af_pse_get_SerialNumber(ca); + CHECK(s1 != nullptr); + SET_OF_Name *users = af_cadb_list_user(ca); + int count = 0; + for (SET_OF_Name *u = users; u; u = u->next) + ++count; + CHECK(count >= 2); + af_close(ca); + aux_free_OctetString(&s1); +} + +TEST(pse_windows_style_paths) +{ + // CrypTool keeps paths like "C:\\...\\PSE\\PSECA\\capse.cse" + auto win = [](const std::string &posix) { + std::string w = "C:" + posix; + for (char &c : w) + if (c == '/') + c = '\\'; + return w; + }; + std::string path = testing::scratch_dir() + "/win.pse"; + PSE pse = af_create(cstr(win(path)), nullptr, const_cast("pin"), nullptr, TRUE); + CHECK(pse != nullptr); + af_close(pse); + CHECK(std::ifstream(path).good()); + pse = af_open(cstr(win(path)), nullptr, const_cast("pin"), nullptr); + CHECK(pse != nullptr); + af_close(pse); + + char text[] = "data"; + OctetString o{4, text}; + std::string file = testing::scratch_dir() + "/win.txt"; + CHECK_EQ(aux_OctetString2file(&o, cstr(win(file)), 2), 0); + CHECK_EQ(aux_OctetString2file(&o, cstr(win(file)), 3), 0); + OctetString *back = aux_file2OctetString(cstr(win(file))); + CHECK(back && std::string(back->octets, back->noctets) == "datadata"); + aux_free_OctetString(&back); + + PSE ca = af_open(cstr(win(store().ca_pse)), cstr(win(store().ca_dir)), const_cast(kCaPin), nullptr); + CHECK(ca != nullptr); + SET_OF_IssuedCertificate *l = af_cadb_get_user(ca, const_cast("CN=Bob SideChannelAttack [1152179494], DC=cryptool, DC=org")); + CHECK(l != nullptr); + aux_free_SET_OF_IssuedCertificate(&l); + af_close(ca); + + std::string root = testing::scratch_dir() + "/winstore"; + CHECK_EQ(secude_compat_create_sample_keystore(win(root).c_str(), 0), 0); + CHECK(std::ifstream(root + "/PSE/PSECA/capse.cse").good()); + CHECK(std::ifstream(root + "/PSE/PSECA/cadb.der").good()); +} diff --git a/port/secude/tests/testing.hpp b/port/secude/tests/testing.hpp new file mode 100644 index 000000000..3ea6eef6e --- /dev/null +++ b/port/secude/tests/testing.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include + +namespace testing { + +struct Case { + const char *name; + std::function fn; +}; + +std::vector ®istry(); +void report_failure(const char *file, int line, const std::string &what); +std::string scratch_dir(); + +struct Register { + Register(const char *name, std::function fn) { registry().push_back({name, std::move(fn)}); } +}; + +std::string hex(const void *p, size_t n); + +} // namespace testing + +#define TEST_CONCAT2(a, b) a##b +#define TEST_CONCAT(a, b) TEST_CONCAT2(a, b) +#define TEST(name) \ + static void name(); \ + static testing::Register TEST_CONCAT(register_, name)(#name, name); \ + static void name() + +#define CHECK(cond) \ + do { \ + if (!(cond)) \ + testing::report_failure(__FILE__, __LINE__, "CHECK(" #cond ")"); \ + } while (0) + +#define CHECK_EQ(a, b) \ + do { \ + auto va_ = (a); \ + auto vb_ = (b); \ + if (!(va_ == vb_)) \ + testing::report_failure(__FILE__, __LINE__, "CHECK_EQ(" #a ", " #b ")"); \ + } while (0) + +#define CHECK_HEX(ptr, len, expected) \ + do { \ + std::string got_ = testing::hex((ptr), (len)); \ + if (got_ != (expected)) \ + testing::report_failure(__FILE__, __LINE__, \ + std::string(#ptr " = ") + got_ + ", expected " + (expected)); \ + } while (0) diff --git a/port/secude/tools/mkpse.cpp b/port/secude/tools/mkpse.cpp new file mode 100644 index 000000000..d9552f2b3 --- /dev/null +++ b/port/secude/tools/mkpse.cpp @@ -0,0 +1,35 @@ +// Creates the CrypTool key store (CA PSE, CA database and the sample keys +// shipped with the installer) in the format of the SECUDE compatibility layer. +#include +#include + +#include "secude_compat.h" + +extern "C" char *th_get_last_error_text(void); + +int main(int argc, char **argv) +{ + bool overwrite = false; + const char *root = nullptr; + for (int i = 1; i < argc; ++i) { + if (!std::strcmp(argv[i], "--overwrite")) + overwrite = true; + else if (!root && argv[i][0] != '-') + root = argv[i]; + else + root = nullptr, i = argc; + } + if (!root) { + std::fprintf(stderr, + "usage: %s [--overwrite] \n" + "creates /PSE (sample keys) and /PSE/PSECA (CA)\n", + argv[0]); + return 2; + } + if (secude_compat_create_sample_keystore(root, overwrite ? 1 : 0) != 0) { + std::fprintf(stderr, "%s: %s\n", argv[0], th_get_last_error_text()); + return 1; + } + std::printf("key store created in %s (%s)\n", root, secude_compat_version()); + return 0; +} diff --git a/port/thirdparty/CMakeLists.txt b/port/thirdparty/CMakeLists.txt new file mode 100644 index 000000000..16a10cf27 --- /dev/null +++ b/port/thirdparty/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.20) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(CrypToolThirdParty LANGUAGES C CXX) + set(CRYPTOOL_THIRDPARTY_STANDALONE ON) +else() + set(CRYPTOOL_THIRDPARTY_STANDALONE OFF) +endif() + +if(NOT DEFINED REPO_ROOT) + get_filename_component(REPO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) +endif() +set(CT_REPO_ROOT "${REPO_ROOT}") +set(CT_THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +option(CRYPTOOL_THIRDPARTY_TESTS "Build the third-party smoke tests" ${CRYPTOOL_THIRDPARTY_STANDALONE}) +option(CRYPTOOL_THIRDPARTY_PIC "Build the third-party static libraries as position independent code" OFF) + +if(CRYPTOOL_THIRDPARTY_TESTS) + enable_testing() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(helpers) + +# Pre-standard C++ headers (iostream.h, fstream.h, iomanip.h, strstrea.h, new.h). +add_library(cryptool_compat_headers INTERFACE) +target_include_directories(cryptool_compat_headers INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/compat_include") +add_library(cryptool::compat_headers ALIAS cryptool_compat_headers) + +# Sources of the CrypTool application, scanned for #include spellings so the +# case-alias directories also cover the spellings used by the application. +file(GLOB CT_APP_SCAN_FILES + "${CT_REPO_ROOT}/CrypTool/*.cpp" "${CT_REPO_ROOT}/CrypTool/*.CPP" + "${CT_REPO_ROOT}/CrypTool/*.h" "${CT_REPO_ROOT}/CrypTool/*.H") + +set(CT_ALL_PARTS gmp miracl analyse ntl ec cracklib apfloat cvact aes openssl) +set(CRYPTOOL_THIRDPARTY_PARTS "${CT_ALL_PARTS}" CACHE STRING "Third-party components to configure") + +foreach(_part IN LISTS CT_ALL_PARTS) + if(_part IN_LIST CRYPTOOL_THIRDPARTY_PARTS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${_part}.cmake") + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${_part}.cmake") + endif() +endforeach() + +# Everything the CrypTool executable needs from this directory. +add_library(cryptool_thirdparty INTERFACE) +add_library(cryptool::thirdparty ALIAS cryptool_thirdparty) +foreach(_t IN ITEMS cryptool_analyse cryptool_miracl cryptool_ntl cryptool_ec cryptool_cracklib + apfloat_compat cryptool_gmp cvact_compat cryptool_aes_candidates cryptool_openssl_compat) + if(TARGET ${_t}) + target_link_libraries(cryptool_thirdparty INTERFACE ${_t}) + endif() +endforeach() diff --git a/port/thirdparty/aes_candidates/ct_aes_prelude.h b/port/thirdparty/aes_candidates/ct_aes_prelude.h new file mode 100644 index 000000000..6c8edd1a8 --- /dev/null +++ b/port/thirdparty/aes_candidates/ct_aes_prelude.h @@ -0,0 +1,30 @@ +#ifndef CT_AES_PRELUDE_H +#define CT_AES_PRELUDE_H + +/* Every system header the AES candidate sources use, included before + "long" is narrowed so that system declarations keep their real types. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__linux__) +#include +#endif + +#ifndef LittleEndian +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define LittleEndian 0 +#else +#define LittleEndian 1 +#endif +#endif +#ifndef ALIGN32 +#define ALIGN32 0 +#endif + +#endif diff --git a/port/thirdparty/aes_candidates/mars.c b/port/thirdparty/aes_candidates/mars.c new file mode 100644 index 000000000..d026054fb --- /dev/null +++ b/port/thirdparty/aes_candidates/mars.c @@ -0,0 +1,8 @@ +#include "ct_aes_prelude.h" + +/* The IBM MARS code assumes a 32-bit long (WORD32). */ +#define long int +#include "Mars/mars-opt.c" +#undef long + +const size_t ct_aes_mars_sizes[2] = {sizeof(keyInstanceMars), sizeof(cipherInstanceMars)}; diff --git a/port/thirdparty/aes_candidates/rc6.c b/port/thirdparty/aes_candidates/rc6.c new file mode 100644 index 000000000..b5c39727c --- /dev/null +++ b/port/thirdparty/aes_candidates/rc6.c @@ -0,0 +1,8 @@ +#include "ct_aes_prelude.h" + +/* The RC6 reference code assumes a 32-bit long. */ +#define long int +#include "RC6/rc6.c" +#undef long + +const size_t ct_aes_rc6_sizes[2] = {sizeof(keyInstanceRC6), sizeof(cipherInstanceRC6)}; diff --git a/port/thirdparty/aes_candidates/rijndael_sizes.c b/port/thirdparty/aes_candidates/rijndael_sizes.c new file mode 100644 index 000000000..d17a8d7c3 --- /dev/null +++ b/port/thirdparty/aes_candidates/rijndael_sizes.c @@ -0,0 +1,5 @@ +#include "ct_aes_prelude.h" + +#include "Rijndael/rijndael-api-fst.h" + +const size_t ct_aes_rijndael_sizes[2] = {sizeof(keyInstanceRijndael), sizeof(cipherInstanceRijndael)}; diff --git a/port/thirdparty/aes_candidates/serpent.c b/port/thirdparty/aes_candidates/serpent.c new file mode 100644 index 000000000..a40056ec3 --- /dev/null +++ b/port/thirdparty/aes_candidates/serpent.c @@ -0,0 +1,27 @@ +#include "ct_aes_prelude.h" + +/* SERPENT.C converts its (narrowed) words with "%08lx"; keep the conversions + on a real unsigned long. */ +static int ct_serpent_sscanf(const char *str, const char *fmt, unsigned int *out) +{ + unsigned long value; + int n = sscanf(str, fmt, &value); + if (n == 1) + *out = (unsigned int)value; + return n; +} + +static int ct_serpent_sprintf(char *buf, const char *fmt, unsigned int value) +{ + return sprintf(buf, fmt, (unsigned long)value); +} + +#define sscanf ct_serpent_sscanf +#define sprintf ct_serpent_sprintf + +/* The Serpent submission code assumes a 32-bit long. */ +#define long int +#include "Serpent/SERPENT.C" +#undef long + +const size_t ct_aes_serpent_sizes[2] = {sizeof(keyInstanceSerpent), sizeof(cipherInstanceSerpent)}; diff --git a/port/thirdparty/aes_candidates/twofish.c b/port/thirdparty/aes_candidates/twofish.c new file mode 100644 index 000000000..017ddcd3a --- /dev/null +++ b/port/thirdparty/aes_candidates/twofish.c @@ -0,0 +1,5 @@ +#include "ct_aes_prelude.h" + +#include "Twofish/TWOFISH2.C" + +const size_t ct_aes_twofish_sizes[2] = {sizeof(keyInstanceTwofish), sizeof(cipherInstanceTwofish)}; diff --git a/port/thirdparty/aes_candidates/wrapper.h.in b/port/thirdparty/aes_candidates/wrapper.h.in new file mode 100644 index 000000000..531b2e0cb --- /dev/null +++ b/port/thirdparty/aes_candidates/wrapper.h.in @@ -0,0 +1,13 @@ +/* Generated: @CT_WRAPPER_NAME@ for the CrypTool port (original: @CT_WRAPPER_ORIGINAL@). */ +#ifndef @CT_WRAPPER_GUARD@ +#define @CT_WRAPPER_GUARD@ + +#include "ct_aes_prelude.h" + +#pragma push_macro("long") +#undef long +@CT_WRAPPER_NARROW_LONG@ +#include "@CT_WRAPPER_ORIGINAL@" +#pragma pop_macro("long") + +#endif diff --git a/port/thirdparty/apfloat_compat/include/ap.h b/port/thirdparty/apfloat_compat/include/ap.h new file mode 100644 index 000000000..42a8dbd1c --- /dev/null +++ b/port/thirdparty/apfloat_compat/include/ap.h @@ -0,0 +1,18 @@ +// Source-compatible subset of apfloat 2.41's ap.h, backed by GMP (see apint.h). +#include +#include +#include + +#if !defined(__AP_H) +#define __AP_H + +#include + +#define APFLOAT_COMPAT 1 +#define APFLOAT_COMPAT_VERSION "2.41-compat" + +bool apinit (void); +void apdeinit (void); +void apbase (int digit); + +#endif // __AP_H diff --git a/port/thirdparty/apfloat_compat/include/apint.h b/port/thirdparty/apfloat_compat/include/apint.h new file mode 100644 index 000000000..5df918c0c --- /dev/null +++ b/port/thirdparty/apfloat_compat/include/apint.h @@ -0,0 +1,147 @@ +// Source-compatible subset of apfloat 2.41's apint, backed by GMP's mpz_class. +// Division and remainder truncate toward zero; conversions from double and +// strings with a fractional part round toward negative infinity (floor). +#ifndef __cplusplus +#error Must use C++ for the type apint. +#endif + +#if !defined(__APINT_H) +#define __APINT_H + +#include +#include +#include +#include + +#include + +#include "ap.h" + +class apint +{ + template + using if_integral = typename std::enable_if::value, int>::type; + +public: + apint () {} + apint (int newval) : val (static_cast (newval)) {} + apint (unsigned newval) : val (static_cast (newval)) {} + apint (long newval) : val (newval) {} + apint (unsigned long newval) : val (newval) {} + apint (long long newval) { setll (newval); } + apint (unsigned long long newval) { setull (newval); } + apint (double newval); + apint (const char *newval) { setstr (newval); } + apint (const std::string &newval) { setstr (newval.c_str ()); } + explicit apint (const mpz_class &newval) : val (newval) {} + + apint &operator= (int d) { val = static_cast (d); return *this; } + apint &operator= (unsigned d) { val = static_cast (d); return *this; } + apint &operator= (long d) { val = d; return *this; } + apint &operator= (unsigned long d) { val = d; return *this; } + apint &operator= (long long d) { setll (d); return *this; } + apint &operator= (unsigned long long d) { setull (d); return *this; } + apint &operator= (double d) { return *this = apint (d); } + apint &operator= (const char *d) { setstr (d); return *this; } + apint &operator= (const std::string &d) { setstr (d.c_str ()); return *this; } + + friend apint operator+ (const apint &d1, const apint &d2) { return apint (mpz_class (d1.val + d2.val)); } + friend apint operator- (const apint &d1, const apint &d2) { return apint (mpz_class (d1.val - d2.val)); } + friend apint operator* (const apint &d1, const apint &d2) { return apint (mpz_class (d1.val * d2.val)); } + friend apint operator/ (const apint &d1, const apint &d2); + friend apint operator% (const apint &d1, const apint &d2); + friend apint operator<< (const apint &d1, size_t d2); + friend apint operator>> (const apint &d1, size_t d2); + + friend bool operator== (const apint &d1, const apint &d2) { return d1.val == d2.val; } + friend bool operator!= (const apint &d1, const apint &d2) { return d1.val != d2.val; } + friend bool operator>= (const apint &d1, const apint &d2) { return d1.val >= d2.val; } + friend bool operator<= (const apint &d1, const apint &d2) { return d1.val <= d2.val; } + friend bool operator> (const apint &d1, const apint &d2) { return d1.val > d2.val; } + friend bool operator< (const apint &d1, const apint &d2) { return d1.val < d2.val; } + + template = 0> friend apint operator+ (const apint &d1, T d2) { return d1 + apint (d2); } + template = 0> friend apint operator+ (T d1, const apint &d2) { return apint (d1) + d2; } + template = 0> friend apint operator- (const apint &d1, T d2) { return d1 - apint (d2); } + template = 0> friend apint operator- (T d1, const apint &d2) { return apint (d1) - d2; } + template = 0> friend apint operator* (const apint &d1, T d2) { return d1 * apint (d2); } + template = 0> friend apint operator* (T d1, const apint &d2) { return apint (d1) * d2; } + template = 0> friend apint operator/ (const apint &d1, T d2) { return d1 / apint (d2); } + template = 0> friend apint operator/ (T d1, const apint &d2) { return apint (d1) / d2; } + template = 0> friend apint operator% (const apint &d1, T d2) { return d1 % apint (d2); } + template = 0> friend apint operator% (T d1, const apint &d2) { return apint (d1) % d2; } + + template = 0> friend bool operator== (const apint &d1, T d2) { return d1 == apint (d2); } + template = 0> friend bool operator== (T d1, const apint &d2) { return apint (d1) == d2; } + template = 0> friend bool operator!= (const apint &d1, T d2) { return d1 != apint (d2); } + template = 0> friend bool operator!= (T d1, const apint &d2) { return apint (d1) != d2; } + template = 0> friend bool operator>= (const apint &d1, T d2) { return d1 >= apint (d2); } + template = 0> friend bool operator>= (T d1, const apint &d2) { return apint (d1) >= d2; } + template = 0> friend bool operator<= (const apint &d1, T d2) { return d1 <= apint (d2); } + template = 0> friend bool operator<= (T d1, const apint &d2) { return apint (d1) <= d2; } + template = 0> friend bool operator> (const apint &d1, T d2) { return d1 > apint (d2); } + template = 0> friend bool operator> (T d1, const apint &d2) { return apint (d1) > d2; } + template = 0> friend bool operator< (const apint &d1, T d2) { return d1 < apint (d2); } + template = 0> friend bool operator< (T d1, const apint &d2) { return apint (d1) < d2; } + + friend bool operator== (const apint &d1, double d2) { return cmpd (d1.val, d2) == 0; } + friend bool operator== (double d1, const apint &d2) { return cmpd (d2.val, d1) == 0; } + friend bool operator!= (const apint &d1, double d2) { return cmpd (d1.val, d2) != 0; } + friend bool operator!= (double d1, const apint &d2) { return cmpd (d2.val, d1) != 0; } + friend bool operator>= (const apint &d1, double d2) { return cmpd (d1.val, d2) >= 0; } + friend bool operator>= (double d1, const apint &d2) { return cmpd (d2.val, d1) <= 0; } + friend bool operator<= (const apint &d1, double d2) { return cmpd (d1.val, d2) <= 0; } + friend bool operator<= (double d1, const apint &d2) { return cmpd (d2.val, d1) >= 0; } + friend bool operator> (const apint &d1, double d2) { return cmpd (d1.val, d2) > 0; } + friend bool operator> (double d1, const apint &d2) { return cmpd (d2.val, d1) < 0; } + friend bool operator< (const apint &d1, double d2) { return cmpd (d1.val, d2) < 0; } + friend bool operator< (double d1, const apint &d2) { return cmpd (d2.val, d1) > 0; } + + friend std::ostream &operator<< (std::ostream &, const apint &); + friend std::istream &operator>> (std::istream &, apint &); + + apint &operator++ () { ++val; return *this; } + apint &operator-- () { --val; return *this; } + apint operator++ (int) { apint t (*this); ++val; return t; } + apint operator-- (int) { apint t (*this); --val; return t; } + apint &operator+= (const apint &d) { val += d.val; return *this; } + apint &operator-= (const apint &d) { val -= d.val; return *this; } + apint &operator*= (const apint &d) { val *= d.val; return *this; } + apint &operator/= (const apint &d) { return *this = *this / d; } + apint &operator%= (const apint &d) { return *this = *this % d; } + apint &operator<<= (size_t d) { return *this = *this << d; } + apint &operator>>= (size_t d) { return *this = *this >> d; } + apint operator+ () const { return *this; } + apint operator- () const { return apint (mpz_class (-val)); } + + int sign (void) const { return sgn (val); } + void sign (int newsign); + + std::string toString (int base = 0) const; + + mpz_class val; + +private: + void setll (long long v); + void setull (unsigned long long v); + void setstr (const char *s); + static int cmpd (const mpz_class &a, double b) { return mpz_cmp_d (a.get_mpz_t (), b); } +}; + +typedef struct apdiv_struct +{ + apint quot; + apint rem; +} apdiv_t; + +apint pow (apint base, unsigned long exp); +apint pow (apint base, unsigned exp); +apint pow (apint base, long exp); +apint pow (apint base, int exp); +apint abs (apint x); +apdiv_t div (apint numer, apint denom); +apint gcd (apint a, apint b); +apint lcm (apint a, apint b); +apint powmod (apint base, apint exp, apint modulus); + +#endif // __APINT_H diff --git a/port/thirdparty/apfloat_compat/src/apint.cpp b/port/thirdparty/apfloat_compat/src/apint.cpp new file mode 100644 index 000000000..8827b5646 --- /dev/null +++ b/port/thirdparty/apfloat_compat/src/apint.cpp @@ -0,0 +1,277 @@ +#include "apint.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +std::atomic g_base{10}; + +constexpr long kMaxStringExponent = 100000000L; + +int digit_value(unsigned char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return INT_MAX; +} + +void set_magnitude(mpz_class &out, unsigned long long v) +{ + mpz_import(out.get_mpz_t(), 1, 1, sizeof v, 0, 0, &v); +} + +void require_nonzero(const apint &d) +{ + if (sgn(d.val) == 0) + throw std::domain_error("apint: division by zero"); +} + +} // namespace + +bool apinit(void) +{ + g_base = 10; + return true; +} + +void apdeinit(void) +{ +} + +void apbase(int digit) +{ + if (digit >= 2 && digit <= 36) + g_base = digit; +} + +apint::apint(double newval) +{ + if (std::isfinite(newval)) + mpz_set_d(val.get_mpz_t(), std::floor(newval)); +} + +void apint::setll(long long v) +{ + if (v < 0) { + set_magnitude(val, 0ULL - static_cast(v)); + val = -val; + } else { + set_magnitude(val, static_cast(v)); + } +} + +void apint::setull(unsigned long long v) +{ + set_magnitude(val, v); +} + +// Parses [ws][sign]digits[.digits][e[sign]digits] in the current base and +// rounds toward negative infinity, like apint(char *) = floor(apfloat(char *)). +void apint::setstr(const char *s) +{ + val = 0; + if (!s) + return; + const int base = g_base; + const unsigned char *p = reinterpret_cast(s); + while (std::isspace(*p)) + ++p; + bool negative = false; + if (*p == '+' || *p == '-') + negative = (*p++ == '-'); + + std::string digits; + long fraction_digits = 0; + bool seen_point = false; + for (;; ++p) { + if (*p == '.' && !seen_point) { + seen_point = true; + continue; + } + if (digit_value(*p) >= base) + break; + digits.push_back(static_cast(std::tolower(*p))); + if (seen_point) + ++fraction_digits; + } + if (digits.empty()) + return; + + long exponent = 0; + if (base <= 10 && (*p == 'e' || *p == 'E')) { + const unsigned char *q = p + 1; + bool exp_negative = false; + if (*q == '+' || *q == '-') + exp_negative = (*q++ == '-'); + if (std::isdigit(*q)) { + while (std::isdigit(*q)) { + if (exponent < kMaxStringExponent) + exponent = exponent * 10 + (*q - '0'); + ++q; + } + if (exp_negative) + exponent = -exponent; + } + } + + mpz_class mantissa; + if (mantissa.set_str(digits, base) != 0) + return; + if (negative) + mantissa = -mantissa; + + const long shift = exponent - fraction_digits; + if (shift >= 0) { + mpz_class scale; + mpz_ui_pow_ui(scale.get_mpz_t(), static_cast(base), static_cast(shift)); + val = mantissa * scale; + } else { + mpz_class scale; + mpz_ui_pow_ui(scale.get_mpz_t(), static_cast(base), static_cast(-shift)); + mpz_fdiv_q(val.get_mpz_t(), mantissa.get_mpz_t(), scale.get_mpz_t()); + } +} + +void apint::sign(int newsign) +{ + if (newsign == 0) + val = 0; + else if ((newsign < 0) != (sgn(val) < 0)) + val = -val; +} + +std::string apint::toString(int base) const +{ + if (base < 2 || base > 36) + base = g_base; + std::string out(mpz_sizeinbase(val.get_mpz_t(), base) + 2, '\0'); + mpz_get_str(&out[0], base, val.get_mpz_t()); + out.resize(std::char_traits::length(out.c_str())); + return out; +} + +apint operator/ (const apint &d1, const apint &d2) +{ + require_nonzero(d2); + apint r; + mpz_tdiv_q(r.val.get_mpz_t(), d1.val.get_mpz_t(), d2.val.get_mpz_t()); + return r; +} + +apint operator% (const apint &d1, const apint &d2) +{ + require_nonzero(d2); + apint r; + mpz_tdiv_r(r.val.get_mpz_t(), d1.val.get_mpz_t(), d2.val.get_mpz_t()); + return r; +} + +apint operator<< (const apint &d1, size_t d2) +{ + apint r; + mpz_mul_2exp(r.val.get_mpz_t(), d1.val.get_mpz_t(), static_cast(d2)); + return r; +} + +apint operator>> (const apint &d1, size_t d2) +{ + apint r; + mpz_tdiv_q_2exp(r.val.get_mpz_t(), d1.val.get_mpz_t(), static_cast(d2)); + return r; +} + +std::ostream &operator<< (std::ostream &str, const apint &d) +{ + return str << d.toString(); +} + +std::istream &operator>> (std::istream &str, apint &d) +{ + std::string token; + if (str >> token) + d = token; + return str; +} + +apint pow (apint base, unsigned long exp) +{ + apint r; + mpz_pow_ui(r.val.get_mpz_t(), base.val.get_mpz_t(), exp); + return r; +} + +apint pow (apint base, unsigned exp) +{ + return pow(base, static_cast(exp)); +} + +apint pow (apint base, long exp) +{ + if (exp >= 0) + return pow(base, static_cast(exp)); + require_nonzero(base); + if (base == 1) + return apint(1); + if (base == -1) + return apint((exp & 1) ? -1 : 1); + return apint(0); +} + +apint pow (apint base, int exp) +{ + return pow(base, static_cast(exp)); +} + +apint abs (apint x) +{ + mpz_abs(x.val.get_mpz_t(), x.val.get_mpz_t()); + return x; +} + +apdiv_t div (apint numer, apint denom) +{ + require_nonzero(denom); + apdiv_t r; + mpz_tdiv_qr(r.quot.val.get_mpz_t(), r.rem.val.get_mpz_t(), numer.val.get_mpz_t(), denom.val.get_mpz_t()); + return r; +} + +apint gcd (apint a, apint b) +{ + apint r; + mpz_gcd(r.val.get_mpz_t(), a.val.get_mpz_t(), b.val.get_mpz_t()); + return r; +} + +apint lcm (apint a, apint b) +{ + apint r; + mpz_lcm(r.val.get_mpz_t(), a.val.get_mpz_t(), b.val.get_mpz_t()); + return r; +} + +apint powmod (apint base, apint exp, apint modulus) +{ + require_nonzero(modulus); + apint r; + if (sgn(exp.val) < 0) { + mpz_class inv; + if (!mpz_invert(inv.get_mpz_t(), base.val.get_mpz_t(), modulus.val.get_mpz_t())) + throw std::domain_error("apint: powmod base not invertible"); + mpz_class e = -exp.val; + mpz_powm(r.val.get_mpz_t(), inv.get_mpz_t(), e.get_mpz_t(), modulus.val.get_mpz_t()); + return r; + } + mpz_powm(r.val.get_mpz_t(), base.val.get_mpz_t(), exp.val.get_mpz_t(), modulus.val.get_mpz_t()); + return r; +} diff --git a/port/thirdparty/cmake/aes.cmake b/port/thirdparty/cmake/aes.cmake new file mode 100644 index 000000000..619dbffd3 --- /dev/null +++ b/port/thirdparty/cmake/aes.cmake @@ -0,0 +1,102 @@ +# AES candidate ciphers compiled directly into CrypTool by CrypTool.vcxproj +# (..\AES\{Mars,RC6,Rijndael,Serpent,Twofish}). MARS, RC6 and Serpent assume a +# 32-bit long; the wrapper translation units in aes_candidates/ narrow long to +# int for those files only, and the generated public headers apply the same +# narrowing so the application sees identical struct layouts. The application +# should include "mars.h", "RC6.h", "Rijndael-api-fst.h", "Serpent.h" and +# "Twofish.h" from this target instead of the ..\AES\... paths. + +# The directory is "aes" in git but "AES" in the Visual Studio project paths. +set(CT_AES_DIR "") +file(GLOB _ct_aes_root_entries RELATIVE "${CT_REPO_ROOT}" "${CT_REPO_ROOT}/*") +foreach(_ct_entry IN LISTS _ct_aes_root_entries) + string(TOLOWER "${_ct_entry}" _ct_entry_lower) + if(_ct_entry_lower STREQUAL "aes" AND IS_DIRECTORY "${CT_REPO_ROOT}/${_ct_entry}") + set(CT_AES_DIR "${CT_REPO_ROOT}/${_ct_entry}") + endif() +endforeach() +if(NOT CT_AES_DIR) + message(FATAL_ERROR "AES candidate sources not found under ${CT_REPO_ROOT}") +endif() +set(CT_AES_SUPPORT_DIR "${CT_THIRDPARTY_DIR}/aes_candidates") +set(CT_AES_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/aes_candidates") +set(CT_AES_WRAPPER_DIR "${CT_AES_GEN_DIR}/include") +set(CT_AES_PUBLIC_ALIAS_DIR "${CT_AES_GEN_DIR}/aliases") +set(CT_AES_SOURCE_ALIAS_DIR "${CT_AES_GEN_DIR}/source_aliases") + +configure_file("${CT_AES_SUPPORT_DIR}/ct_aes_prelude.h" "${CT_AES_WRAPPER_DIR}/ct_aes_prelude.h" COPYONLY) + +function(_ct_aes_wrapper name original narrow) + set(CT_WRAPPER_NAME "${name}") + set(CT_WRAPPER_ORIGINAL "${CT_AES_DIR}/${original}") + string(MAKE_C_IDENTIFIER "CT_AES_WRAPPER_${name}" CT_WRAPPER_GUARD) + string(TOUPPER "${CT_WRAPPER_GUARD}" CT_WRAPPER_GUARD) + if(narrow) + set(CT_WRAPPER_NARROW_LONG "#define long int") + else() + set(CT_WRAPPER_NARROW_LONG "") + endif() + configure_file("${CT_AES_SUPPORT_DIR}/wrapper.h.in" "${CT_AES_WRAPPER_DIR}/${name}" @ONLY) +endfunction() + +_ct_aes_wrapper(mars.h Mars/mars.h TRUE) +_ct_aes_wrapper(RC6.h RC6/rc6.h TRUE) +_ct_aes_wrapper(Rijndael-api-fst.h Rijndael/rijndael-api-fst.h FALSE) +_ct_aes_wrapper(Serpent.h Serpent/SERPENT.H TRUE) +_ct_aes_wrapper(Twofish.h Twofish/Twofish.h FALSE) + +set(CT_AES_C_SOURCES + "${CT_AES_DIR}/Mars/mars-opt.c" "${CT_AES_DIR}/RC6/rc6.c" + "${CT_AES_DIR}/Rijndael/rijndael-alg-fst.c" "${CT_AES_DIR}/Rijndael/rijndael-api-fst.c" + "${CT_AES_DIR}/Serpent/SERPENT.C" "${CT_AES_DIR}/Twofish/TWOFISH2.C") +file(GLOB CT_AES_C_HEADERS + "${CT_AES_DIR}/Mars/*.h" "${CT_AES_DIR}/RC6/*.h" "${CT_AES_DIR}/Rijndael/*.h" + "${CT_AES_DIR}/Serpent/*.H" "${CT_AES_DIR}/Serpent/*.h" "${CT_AES_DIR}/Twofish/*.H" + "${CT_AES_DIR}/Twofish/*.h") + +# Spellings the original sources use for their own headers (e.g. "Mars.h", +# "serpent.h", "platform.h"); Twofish.h needs "platform.h" in consumers too. +ct_case_aliases( + OUT_DIR "${CT_AES_SOURCE_ALIAS_DIR}" + HEADER_DIRS "${CT_AES_DIR}/Mars" "${CT_AES_DIR}/RC6" "${CT_AES_DIR}/Serpent" "${CT_AES_DIR}/Twofish" + SCAN_FILES ${CT_AES_C_SOURCES} ${CT_AES_C_HEADERS} + SCANNED_ONLY) +ct_case_aliases( + OUT_DIR "${CT_AES_PUBLIC_ALIAS_DIR}" + HEADER_DIRS "${CT_AES_WRAPPER_DIR}" + EXCLUDE ct_aes_prelude.h) +ct_case_aliases( + OUT_DIR "${CT_AES_PUBLIC_ALIAS_DIR}" + HEADER_DIRS "${CT_AES_DIR}/Twofish" + SCAN_FILES "${CT_AES_DIR}/Twofish/Twofish.h" + SCANNED_ONLY) + +add_library(cryptool_aes_candidates STATIC + "${CT_AES_SUPPORT_DIR}/mars.c" + "${CT_AES_SUPPORT_DIR}/rc6.c" + "${CT_AES_DIR}/Rijndael/rijndael-alg-fst.c" + "${CT_AES_DIR}/Rijndael/rijndael-api-fst.c" + "${CT_AES_SUPPORT_DIR}/rijndael_sizes.c" + "${CT_AES_SUPPORT_DIR}/serpent.c" + "${CT_AES_SUPPORT_DIR}/twofish.c") +add_library(cryptool::aes_candidates ALIAS cryptool_aes_candidates) +ct_thirdparty_target(cryptool_aes_candidates) +set_target_properties(cryptool_aes_candidates PROPERTIES C_STANDARD 90 C_EXTENSIONS ON) +# rijndael-alg-fst.h defines "int ROUNDS;" in every including file (MSVC merges these). +if(NOT MSVC) + target_compile_options(cryptool_aes_candidates PRIVATE -fcommon) +endif() +target_include_directories(cryptool_aes_candidates PRIVATE + "${CT_AES_SUPPORT_DIR}" + "${CT_AES_DIR}" + "${CT_AES_SOURCE_ALIAS_DIR}") +target_include_directories(cryptool_aes_candidates SYSTEM PUBLIC + "${CT_AES_WRAPPER_DIR}" + "${CT_AES_PUBLIC_ALIAS_DIR}") + +ct_add_smoke_test(test_aes_candidates + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_aes_candidates.cpp" + LIBS cryptool_aes_candidates) +if(TARGET test_aes_candidates) + set_target_properties(test_aes_candidates PROPERTIES CXX_STANDARD 17 CXX_EXTENSIONS OFF) +endif() diff --git a/port/thirdparty/cmake/analyse.cmake b/port/thirdparty/cmake/analyse.cmake new file mode 100644 index 000000000..5d2fe12a3 --- /dev/null +++ b/port/thirdparty/cmake/analyse.cmake @@ -0,0 +1,43 @@ +# libanalyse as built by libanalyse/LibAnalyse.vcxproj. CrypTool's stdafx.h +# includes "libanalyse\la_string.h" and "libanalyse\analyse.h"; consumers get a +# generated directory providing libanalyse/
instead of the repository +# root (which would expose e.g. the repo's OpenSSL 1.0 headers). + +set(CT_ANALYSE_DIR "${CT_REPO_ROOT}/libanalyse") +set(CT_ANALYSE_ALIAS_DIR "${CT_THIRDPARTY_ALIAS_ROOT}/analyse") +set(CT_ANALYSE_ROOT_DIR "${CT_THIRDPARTY_ALIAS_ROOT}/analyse_root") + +set(CT_ANALYSE_SOURCES + Chi2.cpp Cipher.cpp Converter.cpp Des.cpp FFT.CPP FreqTable.cpp LFSR.CPP + MYMATH.CPP NGram.cpp OStream.cpp Permutation.cpp SBox.cpp StaticObjects.cpp + String.cpp Symbol.cpp SymbolArray.cpp) +list(TRANSFORM CT_ANALYSE_SOURCES PREPEND "${CT_ANALYSE_DIR}/") +set_source_files_properties(${CT_ANALYSE_SOURCES} PROPERTIES LANGUAGE CXX) + +file(GLOB CT_ANALYSE_HEADERS "${CT_ANALYSE_DIR}/*.h" "${CT_ANALYSE_DIR}/*.H") +# Only the case-mismatched spellings libanalyse itself uses (a blanket +# lowercase alias such as resource.h could shadow application headers). +ct_case_aliases( + OUT_DIR "${CT_ANALYSE_ALIAS_DIR}" + HEADER_DIRS "${CT_ANALYSE_DIR}" + SCAN_FILES ${CT_ANALYSE_SOURCES} ${CT_ANALYSE_HEADERS} + SCANNED_ONLY) +ct_case_aliases( + OUT_DIR "${CT_ANALYSE_ROOT_DIR}/libanalyse" + HEADER_DIRS "${CT_ANALYSE_DIR}" + INCLUDE_EXACT) + +add_library(cryptool_analyse STATIC ${CT_ANALYSE_SOURCES}) +add_library(cryptool::analyse ALIAS cryptool_analyse) +ct_thirdparty_target(cryptool_analyse) +target_include_directories(cryptool_analyse SYSTEM PUBLIC + "${CT_ANALYSE_ALIAS_DIR}" + "${CT_ANALYSE_ROOT_DIR}") +target_link_libraries(cryptool_analyse PUBLIC cryptool_compat_headers) +set_target_properties(cryptool_analyse PROPERTIES CXX_STANDARD 17 CXX_EXTENSIONS OFF) +target_compile_options(cryptool_analyse PRIVATE + $<$:-Wno-register>) + +ct_add_smoke_test(test_analyse + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_analyse.cpp" + LIBS cryptool_analyse) diff --git a/port/thirdparty/cmake/apfloat.cmake b/port/thirdparty/cmake/apfloat.cmake new file mode 100644 index 000000000..11e03edc9 --- /dev/null +++ b/port/thirdparty/cmake/apfloat.cmake @@ -0,0 +1,31 @@ +# apfloat_compat: GMP-backed replacement for the prebuilt apfloat 2.41 Windows +# libraries in apfloat/. Consumers use this include directory instead of apfloat/. + +if(NOT TARGET cryptool_gmp) + include("${CMAKE_CURRENT_LIST_DIR}/gmp.cmake") +endif() + +add_library(apfloat_compat STATIC + "${CT_THIRDPARTY_DIR}/apfloat_compat/src/apint.cpp" + "${CT_THIRDPARTY_DIR}/apfloat_compat/include/ap.h" + "${CT_THIRDPARTY_DIR}/apfloat_compat/include/apint.h") +add_library(cryptool::apfloat ALIAS apfloat_compat) +target_include_directories(apfloat_compat PUBLIC "${CT_THIRDPARTY_DIR}/apfloat_compat/include") +target_link_libraries(apfloat_compat PUBLIC cryptool_gmp) +target_compile_features(apfloat_compat PUBLIC cxx_std_11) +set_target_properties(apfloat_compat PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + POSITION_INDEPENDENT_CODE ${CRYPTOOL_THIRDPARTY_PIC} + FOLDER "thirdparty") + +ct_add_smoke_test(test_apfloat + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_apfloat.cpp" + LIBS apfloat_compat) +if(TARGET test_apfloat) + set_target_properties(test_apfloat PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) + find_package(Threads) + if(Threads_FOUND) + target_link_libraries(test_apfloat PRIVATE Threads::Threads) + endif() +endif() diff --git a/port/thirdparty/cmake/cracklib.cmake b/port/thirdparty/cmake/cracklib.cmake new file mode 100644 index 000000000..0bead98f4 --- /dev/null +++ b/port/thirdparty/cmake/cracklib.cmake @@ -0,0 +1,28 @@ +# cryptool_cracklib: cracklib 2.7 (Win32 flavour used by CrypTool) as a static C library. +# No public include directory: CrypTool declares the API itself in passwordchecker.h. +# Runtime data: ${CT_CRACKLIB_DICTIONARY}.{pwd,pwi,hwm} must be shipped as words/cracklib_dict.* + +set(_ct_cracklib_dir "${CT_REPO_ROOT}/cracklib-2.7/cracklib_Win32") +set(CT_CRACKLIB_DICTIONARY_DIR "${CT_REPO_ROOT}/setup/template/words") +set(CT_CRACKLIB_DICTIONARY "${CT_CRACKLIB_DICTIONARY_DIR}/cracklib_dict") + +add_library(cryptool_cracklib STATIC + "${_ct_cracklib_dir}/fascist.c" + "${_ct_cracklib_dir}/packlib.c" + "${_ct_cracklib_dir}/rules.c" + "${_ct_cracklib_dir}/stringlib.c") +add_library(cryptool::cracklib ALIAS cryptool_cracklib) +target_compile_definitions(cryptool_cracklib PRIVATE IN_CRACKLIB) +# K&R function definitions: stay on gnu99 (they are invalid in C23). +set_target_properties(cryptool_cracklib PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON C_EXTENSIONS ON) +ct_thirdparty_target(cryptool_cracklib) + +ct_add_smoke_test(test_cracklib + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_cracklib.cpp" "${CT_THIRDPARTY_DIR}/tests/test_cracklib_layout.c" + LIBS cryptool_cracklib + DEFINES "CT_CRACKLIB_DICT=\"${CT_CRACKLIB_DICTIONARY}\"" + "CT_CRACKLIB_PACKER_H=\"${_ct_cracklib_dir}/packer.h\"") +if(TARGET test_cracklib) + set_target_properties(test_cracklib PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON + C_STANDARD 99 C_EXTENSIONS ON) +endif() diff --git a/port/thirdparty/cmake/cvact.cmake b/port/thirdparty/cmake/cvact.cmake new file mode 100644 index 000000000..f920b44dc --- /dev/null +++ b/port/thirdparty/cmake/cvact.cmake @@ -0,0 +1,34 @@ +# cvact_compat: replacement for the proprietary cv act library (libCVact), backed by OpenSSL 3. +if(NOT OpenSSL_FOUND AND APPLE AND NOT OPENSSL_ROOT_DIR AND NOT DEFINED ENV{OPENSSL_ROOT_DIR}) + foreach(_ct_ossl_hint /opt/homebrew/opt/openssl@3 /usr/local/opt/openssl@3) + if(EXISTS "${_ct_ossl_hint}/include/openssl/evp.h") + set(OPENSSL_ROOT_DIR "${_ct_ossl_hint}") + break() + endif() + endforeach() +endif() +find_package(OpenSSL 3 REQUIRED COMPONENTS Crypto) + +set(CT_CVACT_DIR "${CMAKE_CURRENT_LIST_DIR}/../cvact_compat") + +add_library(cvact_compat STATIC + "${CT_CVACT_DIR}/src/Algorithm.cpp" + "${CT_CVACT_DIR}/src/Blob.cpp" + "${CT_CVACT_DIR}/src/BlockCipherKey.cpp" + "${CT_CVACT_DIR}/src/Date.cpp" + "${CT_CVACT_DIR}/src/IESKey.cpp" + "${CT_CVACT_DIR}/src/Key.cpp" + "${CT_CVACT_DIR}/src/Tools.cpp") +add_library(cryptool::cvact_compat ALIAS cvact_compat) +target_include_directories(cvact_compat PUBLIC "${CT_CVACT_DIR}/include") +target_link_libraries(cvact_compat PUBLIC OpenSSL::Crypto) +target_compile_features(cvact_compat PUBLIC cxx_std_11 PRIVATE cxx_std_17) +target_compile_definitions(cvact_compat PRIVATE OPENSSL_API_COMPAT=30000 OPENSSL_NO_DEPRECATED) +set_target_properties(cvact_compat PROPERTIES + CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ${CRYPTOOL_THIRDPARTY_PIC} + FOLDER "thirdparty") + +ct_add_smoke_test(test_cvact + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_cvact.cpp" + LIBS cvact_compat) diff --git a/port/thirdparty/cmake/ec.cmake b/port/thirdparty/cmake/ec.cmake new file mode 100644 index 000000000..51b3634e2 --- /dev/null +++ b/port/thirdparty/cmake/ec.cmake @@ -0,0 +1,42 @@ +# libec as built by libec/LibEc.vcxproj. As on Windows it is compiled without +# LINK_SECUDE: SECUDE routines are called through the ECSecudeLib function +# table, which CrypToolApp fills from its SECUDE binding at start-up, so only +# the SECUDE headers are needed here. secude_compat (port/secude) is linked +# when that target exists, whichever directory defines it. + +set(CT_EC_DIR "${CT_REPO_ROOT}/libec") +set(CT_EC_ALIAS_DIR "${CT_THIRDPARTY_ALIAS_ROOT}/ec") + +set(CT_EC_SOURCES + ECsecude.c EMSA1.C Ecssa.c s_bithdl.c s_ecDSA.c s_ecNR.c s_ecconv.c s_ecmath.c + s_ecpX9c.c s_ecpara.c s_ecparp.c s_ecpcur.c s_ecppta.c s_ecpptc.c s_ecpptp.c + s_ecprpt.c s_ecvali.c s_prng.c) +list(TRANSFORM CT_EC_SOURCES PREPEND "${CT_EC_DIR}/sources/") +set_source_files_properties(${CT_EC_SOURCES} PROPERTIES LANGUAGE C) + +file(GLOB CT_EC_HEADERS "${CT_EC_DIR}/include/*") +ct_case_aliases( + OUT_DIR "${CT_EC_ALIAS_DIR}" + HEADER_DIRS "${CT_EC_DIR}/include" + SCAN_FILES ${CT_EC_SOURCES} ${CT_EC_HEADERS} ${CT_APP_SCAN_FILES}) + +set(CT_SECUDE_INCLUDE_DIR "${CT_REPO_ROOT}/secude" CACHE PATH + "Directory containing the SECUDE headers (secure.h, arithmet.h, secude/...)") + +add_library(cryptool_ec STATIC ${CT_EC_SOURCES}) +add_library(cryptool::ec ALIAS cryptool_ec) +ct_thirdparty_target(cryptool_ec) +target_include_directories(cryptool_ec SYSTEM PUBLIC + "${CT_EC_DIR}/include" + "${CT_EC_ALIAS_DIR}" + "${CT_SECUDE_INCLUDE_DIR}") +set_target_properties(cryptool_ec PROPERTIES C_STANDARD 90 C_EXTENSIONS ON) +target_link_libraries(cryptool_ec PUBLIC $) + +ct_add_smoke_test(test_ec + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_ec.cpp" + LIBS cryptool_ec + DEFINES "CT_HAVE_SECUDE_COMPAT=$") +if(TARGET test_ec) + set_tests_properties(test_ec PROPERTIES SKIP_RETURN_CODE 77) +endif() diff --git a/port/thirdparty/cmake/gmp.cmake b/port/thirdparty/cmake/gmp.cmake new file mode 100644 index 000000000..4f592a7c2 --- /dev/null +++ b/port/thirdparty/cmake/gmp.cmake @@ -0,0 +1,69 @@ +# cryptool_gmp: system GMP (+ gmpxx) replacing the bundled MPIR binaries in libgmp/. +# Consumers must not put ${REPO_ROOT}/libgmp on their include path (MPIR headers). + +if(TARGET cryptool_gmp) + return() +endif() + +set(_ct_gmp_hints "") +if(APPLE) + if(NOT DEFINED CT_HOMEBREW_PREFIX) + find_program(CT_BREW_EXECUTABLE brew) + if(CT_BREW_EXECUTABLE) + execute_process(COMMAND "${CT_BREW_EXECUTABLE}" --prefix + OUTPUT_VARIABLE _ct_brew_prefix OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET RESULT_VARIABLE _ct_brew_rc) + if(_ct_brew_rc EQUAL 0 AND _ct_brew_prefix) + set(CT_HOMEBREW_PREFIX "${_ct_brew_prefix}" CACHE PATH "Homebrew prefix") + endif() + endif() + endif() + if(CT_HOMEBREW_PREFIX) + list(APPEND _ct_gmp_hints "${CT_HOMEBREW_PREFIX}/opt/gmp" "${CT_HOMEBREW_PREFIX}") + endif() +endif() + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_check_modules(CT_PC_GMP QUIET IMPORTED_TARGET GLOBAL gmp) + pkg_check_modules(CT_PC_GMPXX QUIET IMPORTED_TARGET GLOBAL gmpxx) +endif() + +add_library(cryptool_gmp INTERFACE) +add_library(cryptool::gmp ALIAS cryptool_gmp) + +if(CT_PC_GMP_FOUND AND CT_PC_GMPXX_FOUND) + target_link_libraries(cryptool_gmp INTERFACE PkgConfig::CT_PC_GMPXX PkgConfig::CT_PC_GMP) + set(CT_GMP_VERSION "${CT_PC_GMP_VERSION}") +else() + find_path(CT_GMP_INCLUDE_DIR NAMES gmp.h HINTS ${_ct_gmp_hints} PATH_SUFFIXES include) + find_path(CT_GMPXX_INCLUDE_DIR NAMES gmpxx.h HINTS ${_ct_gmp_hints} PATH_SUFFIXES include) + find_library(CT_GMP_LIBRARY NAMES gmp HINTS ${_ct_gmp_hints} PATH_SUFFIXES lib) + find_library(CT_GMPXX_LIBRARY NAMES gmpxx HINTS ${_ct_gmp_hints} PATH_SUFFIXES lib) + if(NOT CT_GMP_INCLUDE_DIR OR NOT CT_GMPXX_INCLUDE_DIR OR NOT CT_GMP_LIBRARY OR NOT CT_GMPXX_LIBRARY) + message(FATAL_ERROR "GMP with C++ support (gmp.h, gmpxx.h, libgmp, libgmpxx) not found. " + "Install libgmp-dev (Debian/Ubuntu) or 'brew install gmp' (macOS), or set CMAKE_PREFIX_PATH.") + endif() + target_include_directories(cryptool_gmp SYSTEM INTERFACE "${CT_GMP_INCLUDE_DIR}" "${CT_GMPXX_INCLUDE_DIR}") + target_link_libraries(cryptool_gmp INTERFACE "${CT_GMPXX_LIBRARY}" "${CT_GMP_LIBRARY}") + set(CT_GMP_VERSION "") + file(STRINGS "${CT_GMP_INCLUDE_DIR}/gmp.h" _ct_gmp_ver REGEX "^#define __GNU_MP_VERSION(_MINOR|_PATCHLEVEL)? +[0-9]+") + foreach(_l IN LISTS _ct_gmp_ver) + if(_l MATCHES "([0-9]+)$") + list(APPEND CT_GMP_VERSION "${CMAKE_MATCH_1}") + endif() + endforeach() + list(JOIN CT_GMP_VERSION "." CT_GMP_VERSION) +endif() + +if(CT_GMP_VERSION AND CT_GMP_VERSION VERSION_LESS 6.0) + message(WARNING "GMP ${CT_GMP_VERSION} found; GMP >= 6.0 is expected") +endif() +message(STATUS "cryptool_gmp: GMP ${CT_GMP_VERSION}") + +ct_add_smoke_test(test_gmp + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_gmp.cpp" + LIBS cryptool_gmp) +if(TARGET test_gmp) + set_target_properties(test_gmp PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) +endif() diff --git a/port/thirdparty/cmake/helpers.cmake b/port/thirdparty/cmake/helpers.cmake new file mode 100644 index 000000000..f4b7e9620 --- /dev/null +++ b/port/thirdparty/cmake/helpers.cmake @@ -0,0 +1,105 @@ +include_guard(GLOBAL) + +set(CT_THIRDPARTY_ALIAS_ROOT "${CMAKE_CURRENT_BINARY_DIR}/case_aliases") + +# Silences warnings and relaxes aliasing for legacy third-party code. +function(ct_thirdparty_target target) + if(MSVC) + target_compile_options(${target} PRIVATE /w) + else() + target_compile_options(${target} PRIVATE -w -fno-strict-aliasing) + endif() + set_target_properties(${target} PROPERTIES + POSITION_INDEPENDENT_CODE ${CRYPTOOL_THIRDPARTY_PIC} + FOLDER "thirdparty") +endfunction() + +# Creates a directory of forwarding headers so that #include spellings that +# only differ in case from the files on disk resolve on case-sensitive file +# systems. Every header gets an all-lowercase alias (unless SCANNED_ONLY); in +# addition every spelling found in the #include directives of SCAN_FILES that +# case-insensitively matches a header in HEADER_DIRS gets its own alias. +# INCLUDE_EXACT also forwards the exact on-disk names (for prefix directories). +# ct_case_aliases(OUT_DIR HEADER_DIRS ... [SCAN_FILES ...] +# [EXCLUDE ...] [SCANNED_ONLY] [INCLUDE_EXACT]) +function(ct_case_aliases) + cmake_parse_arguments(A "SCANNED_ONLY;INCLUDE_EXACT" "OUT_DIR" "HEADER_DIRS;SCAN_FILES;EXCLUDE" ${ARGN}) + file(MAKE_DIRECTORY "${A_OUT_DIR}") + set(_lower_names "") + foreach(_dir IN LISTS A_HEADER_DIRS) + file(GLOB _headers RELATIVE "${_dir}" "${_dir}/*") + foreach(_h IN LISTS _headers) + if(IS_DIRECTORY "${_dir}/${_h}" OR NOT _h MATCHES "\\.([hH]|[hH][pP][pP]|[hH][hH]|[iI][nN][lL])$") + continue() + endif() + string(TOLOWER "${_h}" _lh) + if(_lh IN_LIST A_EXCLUDE) + continue() + endif() + if(NOT DEFINED "_map_${_lh}") + set("_map_${_lh}" "${_dir}/${_h}") + list(APPEND _lower_names "${_lh}") + endif() + endforeach() + endforeach() + + set(_spellings "") + if(NOT A_SCANNED_ONLY) + list(APPEND _spellings ${_lower_names}) + endif() + if(A_INCLUDE_EXACT) + foreach(_ln IN LISTS _lower_names) + get_filename_component(_exact "${_map_${_ln}}" NAME) + list(APPEND _spellings "${_exact}") + endforeach() + endif() + foreach(_f IN LISTS A_SCAN_FILES) + file(STRINGS "${_f}" _lines REGEX "^[ \t]*#[ \t]*include[ \t]*[<\"]") + foreach(_l IN LISTS _lines) + if(_l MATCHES "^[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"/\\\\]+)[>\"]") + list(APPEND _spellings "${CMAKE_MATCH_1}") + endif() + endforeach() + endforeach() + list(REMOVE_DUPLICATES _spellings) + + foreach(_n IN LISTS _spellings) + string(TOLOWER "${_n}" _ln) + if(NOT DEFINED "_map_${_ln}") + continue() + endif() + set(_target "${_map_${_ln}}") + get_filename_component(_actual "${_target}" NAME) + if(_actual STREQUAL _n AND NOT A_INCLUDE_EXACT) + continue() + endif() + _ct_write_if_different("${A_OUT_DIR}/${_n}" + "/* generated case alias */\n#include \"${_target}\"\n") + endforeach() +endfunction() + +function(_ct_write_if_different path content) + if(EXISTS "${path}") + file(READ "${path}" _old) + if(_old STREQUAL content) + return() + endif() + endif() + file(WRITE "${path}" "${content}") +endfunction() + +# Registers a smoke test executable with CTest. +# ct_add_smoke_test( SOURCES ... LIBS ... [DEFINES ...] [ARGS ...]) +function(ct_add_smoke_test name) + if(NOT CRYPTOOL_THIRDPARTY_TESTS) + return() + endif() + cmake_parse_arguments(A "" "" "SOURCES;LIBS;DEFINES;ARGS" ${ARGN}) + add_executable(${name} ${A_SOURCES}) + target_link_libraries(${name} PRIVATE ${A_LIBS}) + if(A_DEFINES) + target_compile_definitions(${name} PRIVATE ${A_DEFINES}) + endif() + set_target_properties(${name} PROPERTIES FOLDER "thirdparty/tests") + add_test(NAME ${name} COMMAND ${name} ${A_ARGS}) +endfunction() diff --git a/port/thirdparty/cmake/miracl.cmake b/port/thirdparty/cmake/miracl.cmake new file mode 100644 index 000000000..f9bc9e301 --- /dev/null +++ b/port/thirdparty/cmake/miracl.cmake @@ -0,0 +1,51 @@ +# MIRACL (Shamus Software, ~2000) as built by libmiracl/LibMiracl.vcxproj: +# the C core plus the Big class. CrypTool compiles its own copies of the other +# C++ wrappers (MONTY, ELLIPTIC, FLASH, COMFLASH, POLY, FPOLY, POLYMOD) and +# libmiracl/source/CRT.CPP; CRT.CPP is included here as well because it is the +# only wrapper CrypTool takes from libmiracl/source. + +set(CT_MIRACL_DIR "${CT_REPO_ROOT}/libmiracl") +set(CT_MIRACL_ALIAS_DIR "${CT_THIRDPARTY_ALIAS_ROOT}/miracl") + +set(CT_MIRACL_C_SOURCES + MRAES.C MRALLOC.C MRARTH0.C MRARTH1.C MRARTH2.C MRARTH3.C MRBRICK.C MRBUILD.C + MRCOMBA.C MRCORE.C MRCRT.C MRCURVE.C MRDOUBLE.C MREBRICK.C MRECGF2M.C MRFAST.C + MRFLASH.C MRFLSH1.C MRFLSH2.C MRFLSH3.C MRFLSH4.C MRFRND.C MRGCD.C MRIO1.C + MRIO2.C MRJACK.C MRKCM.C MRLUCAS.C MRMONTY.C MRPI.C MRPOWER.C MRPRIME.C + MRRAND.C MRROUND.C MRSCRT.C MRSHS.C MRSHS256.C MRSHS512.C MRSMALL.C MRSTRONG.C + MRXGCD.C) +# MRMULDV.C (MSVC inline assembly) is replaced by the C versions in MRCORE.C (MR_NOASM). +set(CT_MIRACL_CXX_SOURCES BIG.CPP CRT.CPP) + +list(TRANSFORM CT_MIRACL_C_SOURCES PREPEND "${CT_MIRACL_DIR}/source/") +list(TRANSFORM CT_MIRACL_CXX_SOURCES PREPEND "${CT_MIRACL_DIR}/source/") +set_source_files_properties(${CT_MIRACL_C_SOURCES} PROPERTIES LANGUAGE C) +set_source_files_properties(${CT_MIRACL_CXX_SOURCES} PROPERTIES LANGUAGE CXX) + +ct_case_aliases( + OUT_DIR "${CT_MIRACL_ALIAS_DIR}" + HEADER_DIRS "${CT_THIRDPARTY_DIR}/miracl" "${CT_MIRACL_DIR}/include" + SCAN_FILES ${CT_MIRACL_C_SOURCES} ${CT_MIRACL_CXX_SOURCES} ${CT_APP_SCAN_FILES}) + +add_library(cryptool_miracl STATIC ${CT_MIRACL_C_SOURCES} ${CT_MIRACL_CXX_SOURCES}) +add_library(cryptool::miracl ALIAS cryptool_miracl) +ct_thirdparty_target(cryptool_miracl) +# The portable mirdef.h must shadow libmiracl/include/MIRDEF.H (Win32/__int64). +target_include_directories(cryptool_miracl SYSTEM PUBLIC + "${CT_THIRDPARTY_DIR}/miracl" + "${CT_MIRACL_ALIAS_DIR}" + "${CT_MIRACL_DIR}/include") +target_link_libraries(cryptool_miracl PUBLIC cryptool_compat_headers) +set_target_properties(cryptool_miracl PROPERTIES + C_STANDARD 90 C_EXTENSIONS ON + CXX_STANDARD 17 CXX_EXTENSIONS OFF) +if(NOT WIN32) + find_library(CT_LIBM m) + if(CT_LIBM) + target_link_libraries(cryptool_miracl PUBLIC ${CT_LIBM}) + endif() +endif() + +ct_add_smoke_test(test_miracl + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_miracl.cpp" + LIBS cryptool_miracl) diff --git a/port/thirdparty/cmake/ntl.cmake b/port/thirdparty/cmake/ntl.cmake new file mode 100644 index 000000000..4e557a0df --- /dev/null +++ b/port/thirdparty/cmake/ntl.cmake @@ -0,0 +1,98 @@ +# NTL 5.5.2 as bundled in libNTL/ (pristine sources, the .c files renamed to .cpp). +# CrypTool relies on the NTL_vector_decl/NTL_matrix_decl macros that were removed +# in NTL 6, so the bundled version is built instead of a system NTL. + +if(NOT CMAKE_C_COMPILER_LOADED) + enable_language(C) +endif() + +set(CT_NTL_DIR "${CT_REPO_ROOT}/libNTL") +set(CT_NTL_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/ntl_generated") + +# libNTL/include/NTL/mach_desc.h is NTL's mach_desc.win (32-bit long). The real +# description of the build host is produced by NTL's own MakeDesc program. +if(CMAKE_CROSSCOMPILING AND NOT CRYPTOOL_NTL_MACH_DESC) + message(FATAL_ERROR "cryptool_ntl: cross compiling; run NTL's MakeDesc on the target and pass " + "-DCRYPTOOL_NTL_MACH_DESC=") +endif() + +set(CT_NTL_MACH_DESC "${CT_NTL_GENERATED_DIR}/NTL/mach_desc.h") +if(CRYPTOOL_NTL_MACH_DESC) + configure_file("${CRYPTOOL_NTL_MACH_DESC}" "${CT_NTL_MACH_DESC}" COPYONLY) +elseif(NOT EXISTS "${CT_NTL_MACH_DESC}") + set(_ntl_makedesc_dir "${CMAKE_CURRENT_BINARY_DIR}/ntl_makedesc") + set(_ntl_makedesc_exe "${_ntl_makedesc_dir}/MakeDesc${CMAKE_EXECUTABLE_SUFFIX}") + if(MSVC) + set(_ntl_makedesc_flags "") + set(_ntl_makedesc_libs "") + else() + set(_ntl_makedesc_flags -w -O0 -ffp-contract=off) + set(_ntl_makedesc_libs m) + endif() + try_compile(_ntl_makedesc_ok "${_ntl_makedesc_dir}/build" + SOURCES "${CT_THIRDPARTY_DIR}/ntl/MakeDesc.c" "${CT_THIRDPARTY_DIR}/ntl/MakeDescAux.c" + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${CT_NTL_DIR}/include" + COMPILE_DEFINITIONS ${_ntl_makedesc_flags} + LINK_LIBRARIES ${_ntl_makedesc_libs} + OUTPUT_VARIABLE _ntl_makedesc_log + COPY_FILE "${_ntl_makedesc_exe}") + if(NOT _ntl_makedesc_ok) + message(FATAL_ERROR "cryptool_ntl: building NTL's MakeDesc failed:\n${_ntl_makedesc_log}") + endif() + file(MAKE_DIRECTORY "${CT_NTL_GENERATED_DIR}/NTL") + execute_process(COMMAND "${_ntl_makedesc_exe}" + WORKING_DIRECTORY "${CT_NTL_GENERATED_DIR}/NTL" + RESULT_VARIABLE _ntl_makedesc_rc + ERROR_VARIABLE _ntl_makedesc_err + OUTPUT_QUIET) + if(NOT _ntl_makedesc_rc EQUAL 0 OR NOT EXISTS "${CT_NTL_MACH_DESC}") + file(REMOVE "${CT_NTL_MACH_DESC}") + message(FATAL_ERROR "cryptool_ntl: NTL's MakeDesc failed:\n${_ntl_makedesc_err}") + endif() + string(REGEX MATCH "bits per long = [0-9]+" _ntl_bpl "${_ntl_makedesc_err}") + message(STATUS "cryptool_ntl: generated NTL/mach_desc.h (${_ntl_bpl})") +endif() + +set(CT_NTL_SOURCES + FFT.cpp FacVec.cpp GF2.cpp GF2E.cpp GF2EX.cpp GF2EXFactoring.cpp GF2X.cpp GF2X1.cpp + GF2XFactoring.cpp GF2XVec.cpp G_LLL_FP.cpp G_LLL_QP.cpp G_LLL_RR.cpp G_LLL_XD.cpp + GetTime.cpp HNF.cpp LLL.cpp LLL_FP.cpp LLL_QP.cpp LLL_RR.cpp LLL_XD.cpp RR.cpp + WordVector.cpp ZZ.cpp ZZVec.cpp ZZX.cpp ZZX1.cpp ZZXCharPoly.cpp ZZXFactoring.cpp + ZZ_p.cpp ZZ_pE.cpp ZZ_pEX.cpp ZZ_pEXFactoring.cpp ZZ_pX.cpp ZZ_pX1.cpp + ZZ_pXCharPoly.cpp ZZ_pXFactoring.cpp ctools.cpp fileio.cpp lip.cpp lzz_p.cpp + lzz_pE.cpp lzz_pEX.cpp lzz_pEXFactoring.cpp lzz_pX.cpp lzz_pX1.cpp lzz_pXCharPoly.cpp + lzz_pXFactoring.cpp mat_GF2.cpp mat_GF2E.cpp mat_RR.cpp mat_ZZ.cpp mat_ZZ_p.cpp + mat_ZZ_pE.cpp mat_lzz_p.cpp mat_lzz_pE.cpp mat_poly_ZZ.cpp mat_poly_ZZ_p.cpp + mat_poly_lzz_p.cpp pair_GF2EX_long.cpp pair_GF2X_long.cpp pair_ZZX_long.cpp + pair_ZZ_pEX_long.cpp pair_ZZ_pX_long.cpp pair_lzz_pEX_long.cpp pair_lzz_pX_long.cpp + quad_float.cpp tools.cpp vec_GF2.cpp vec_GF2E.cpp vec_GF2XVec.cpp vec_RR.cpp + vec_ZZ.cpp vec_ZZVec.cpp vec_ZZ_p.cpp vec_ZZ_pE.cpp vec_double.cpp vec_long.cpp + vec_lzz_p.cpp vec_lzz_pE.cpp vec_quad_float.cpp vec_ulong.cpp vec_vec_GF2.cpp + vec_vec_GF2E.cpp vec_vec_RR.cpp vec_vec_ZZ.cpp vec_vec_ZZ_p.cpp vec_vec_ZZ_pE.cpp + vec_vec_long.cpp vec_vec_lzz_p.cpp vec_vec_lzz_pE.cpp vec_vec_ulong.cpp + vec_xdouble.cpp xdouble.cpp) +list(TRANSFORM CT_NTL_SOURCES PREPEND "${CT_NTL_DIR}/src/") + +add_library(cryptool_ntl STATIC ${CT_NTL_SOURCES}) +add_library(cryptool::ntl ALIAS cryptool_ntl) +ct_thirdparty_target(cryptool_ntl) +# The generated directory must precede libNTL/include so that +# resolves to the generated header (also on case-insensitive file systems). +target_include_directories(cryptool_ntl BEFORE PUBLIC + "$" + "$") +target_compile_features(cryptool_ntl PUBLIC cxx_std_11) +set_target_properties(cryptool_ntl PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) +if(NOT MSVC) + # quad_float (LLL_QP/G_LLL_QP) needs exact IEEE double rounding; FMA contraction + # (gcc's default on arm64) breaks its error-free transforms (NTL's QuadTest fails). + target_compile_options(cryptool_ntl PRIVATE -ffp-contract=off) + target_link_libraries(cryptool_ntl PUBLIC m) +endif() + +ct_add_smoke_test(test_ntl + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_ntl.cpp" + LIBS cryptool_ntl) +if(TARGET test_ntl) + set_target_properties(test_ntl PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) +endif() diff --git a/port/thirdparty/cmake/openssl.cmake b/port/thirdparty/cmake/openssl.cmake new file mode 100644 index 000000000..7df2b5c65 --- /dev/null +++ b/port/thirdparty/cmake/openssl.cmake @@ -0,0 +1,57 @@ +# cryptool_openssl_compat: replaces the bundled OpenSSL 1.0.1 headers/libeay32 used by +# CrypTool's HashingOperations.cpp ("OpenSSL//md2.h" ... "OpenSSL//sha.h", included +# inside namespace __SSL) and DlgAbout.cpp ("crypto.h" inside namespace OPENSSL). +# MD4/MD5/SHA-1/SHA-256/SHA-512/RIPEMD-160 forward to OpenSSL 3's libcrypto; +# MD2 and SHA-0 (absent from OpenSSL 3) are implemented here. +# +# The include directories are deliberately NOT marked SYSTEM: CrypTool's +# "OpenSSL//x.h" must resolve to these headers before OpenSSL 3's (imported, +# hence -isystem) include directory, which on case-insensitive file systems +# also matches "OpenSSL/". The compat headers keep OpenSSL 3's include guards +# and declare a superset of the real headers, so a real include +# that resolves here still works. + +if(NOT TARGET OpenSSL::Crypto) + if(APPLE AND NOT OPENSSL_ROOT_DIR AND NOT DEFINED ENV{OPENSSL_ROOT_DIR}) + find_program(CT_BREW_EXECUTABLE brew) + if(CT_BREW_EXECUTABLE) + execute_process(COMMAND "${CT_BREW_EXECUTABLE}" --prefix openssl@3 + OUTPUT_VARIABLE _ct_ossl_prefix OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET RESULT_VARIABLE _ct_ossl_rc) + if(_ct_ossl_rc EQUAL 0 AND EXISTS "${_ct_ossl_prefix}/include/openssl/evp.h") + set(OPENSSL_ROOT_DIR "${_ct_ossl_prefix}") + endif() + endif() + endif() + find_package(OpenSSL 3 REQUIRED COMPONENTS Crypto) +endif() + +set(CT_OPENSSL_COMPAT_DIR "${CT_THIRDPARTY_DIR}/openssl_compat") + +add_library(cryptool_openssl_compat STATIC + "${CT_OPENSSL_COMPAT_DIR}/src/ct_md2.c" + "${CT_OPENSSL_COMPAT_DIR}/src/ct_sha0.c") +add_library(cryptool::openssl_compat ALIAS cryptool_openssl_compat) +target_include_directories(cryptool_openssl_compat PUBLIC + "${CT_OPENSSL_COMPAT_DIR}/include" + "${CT_OPENSSL_COMPAT_DIR}/include_bare") +target_link_libraries(cryptool_openssl_compat PUBLIC OpenSSL::Crypto) +set_target_properties(cryptool_openssl_compat PROPERTIES + C_STANDARD 99 C_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ${CRYPTOOL_THIRDPARTY_PIC} + FOLDER "thirdparty") + +if(CRYPTOOL_THIRDPARTY_TESTS) + # Real OpenSSL 3 headers only (no compat include dir), for layout comparison. + add_library(test_openssl_compat_layout OBJECT "${CT_THIRDPARTY_DIR}/tests/test_openssl_compat_layout.c") + target_link_libraries(test_openssl_compat_layout PRIVATE OpenSSL::Crypto) + target_compile_definitions(test_openssl_compat_layout PRIVATE OPENSSL_SUPPRESS_DEPRECATED) + set_target_properties(test_openssl_compat_layout PROPERTIES C_STANDARD 99 FOLDER "thirdparty/tests") +endif() +ct_add_smoke_test(test_openssl_compat + SOURCES "${CT_THIRDPARTY_DIR}/tests/test_openssl_compat.cpp" + $ + LIBS cryptool_openssl_compat) +if(TARGET test_openssl_compat) + set_target_properties(test_openssl_compat PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) +endif() diff --git a/port/thirdparty/compat_include/fstream.h b/port/thirdparty/compat_include/fstream.h new file mode 100644 index 000000000..7b92f0597 --- /dev/null +++ b/port/thirdparty/compat_include/fstream.h @@ -0,0 +1,8 @@ +#ifndef CRYPTOOL_COMPAT_FSTREAM_H +#define CRYPTOOL_COMPAT_FSTREAM_H + +#include +#include +using namespace std; + +#endif diff --git a/port/thirdparty/compat_include/iomanip.h b/port/thirdparty/compat_include/iomanip.h new file mode 100644 index 000000000..421ed63cb --- /dev/null +++ b/port/thirdparty/compat_include/iomanip.h @@ -0,0 +1,8 @@ +#ifndef CRYPTOOL_COMPAT_IOMANIP_H +#define CRYPTOOL_COMPAT_IOMANIP_H + +#include +#include +using namespace std; + +#endif diff --git a/port/thirdparty/compat_include/iostream.h b/port/thirdparty/compat_include/iostream.h new file mode 100644 index 000000000..4cef57cf5 --- /dev/null +++ b/port/thirdparty/compat_include/iostream.h @@ -0,0 +1,9 @@ +#ifndef CRYPTOOL_COMPAT_IOSTREAM_H +#define CRYPTOOL_COMPAT_IOSTREAM_H + +// Legacy code selects on non-MSVC compilers; the MSVC branch it +// replaces includes and imports namespace std, so do the same here. +#include +using namespace std; + +#endif diff --git a/port/thirdparty/compat_include/new.h b/port/thirdparty/compat_include/new.h new file mode 100644 index 000000000..1f87c2d4d --- /dev/null +++ b/port/thirdparty/compat_include/new.h @@ -0,0 +1,8 @@ +#ifndef CRYPTOOL_COMPAT_NEW_H +#define CRYPTOOL_COMPAT_NEW_H + +#ifdef __cplusplus +#include +#endif + +#endif diff --git a/port/thirdparty/compat_include/strstrea.h b/port/thirdparty/compat_include/strstrea.h new file mode 100644 index 000000000..f1d2a5503 --- /dev/null +++ b/port/thirdparty/compat_include/strstrea.h @@ -0,0 +1,8 @@ +#ifndef CRYPTOOL_COMPAT_STRSTREA_H +#define CRYPTOOL_COMPAT_STRSTREA_H + +#include +#include +using namespace std; + +#endif diff --git a/port/thirdparty/compat_include/strstream.h b/port/thirdparty/compat_include/strstream.h new file mode 100644 index 000000000..0ea17b19b --- /dev/null +++ b/port/thirdparty/compat_include/strstream.h @@ -0,0 +1,8 @@ +#ifndef CRYPTOOL_COMPAT_STRSTREAM_H +#define CRYPTOOL_COMPAT_STRSTREAM_H + +#include +#include +using namespace std; + +#endif diff --git a/port/thirdparty/cvact_compat/include/actAlgorithm.h b/port/thirdparty/cvact_compat/include/actAlgorithm.h new file mode 100644 index 000000000..4f834e6de --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actAlgorithm.h @@ -0,0 +1,57 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_Algorithm_h +#define ACT_Algorithm_h + +#include "actBasics.h" + +namespace act +{ + class IAlgorithm; + class IKey; + class Blob; + + class Algorithm + { + public: + Algorithm(IAlgorithm *alg); + Algorithm(const IKey *key, mode_t mode); + Algorithm(const IKey *key, mode_t mode, const Blob &data); + // Hash ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "RIPEMD160") + // or random generator ("BBS", "FIPS186", "DevRandom") by name. + Algorithm(const char *name); + + void Write(const Blob &indata); + void Write(const byte *indata, size_t insize); + void Finalize(); + size_t Read(Blob &outdata, size_t max = 0); + size_t Read(byte *outbuffer, size_t buffersize); + size_t GetAvailableSize() const; + status_t GetStatus() const; + + Algorithm &operator<<(const Blob &indata) { Write(indata); return *this; } + Algorithm &operator<<(Algorithm &(*manipulator)(Algorithm &alg)) { return manipulator(*this); } + Algorithm &operator>>(Blob &outdata) { Read(outdata); return *this; } + + ~Algorithm(); + + operator IAlgorithm *(); + operator const IAlgorithm *() const; + IAlgorithm *GetPointer(); + const IAlgorithm *GetPointer() const; + IAlgorithm *ReleasePointer(); + + private: + Algorithm(const Algorithm &alg); + Algorithm &operator=(const Algorithm &alg); + + IAlgorithm *mAlg; + }; + + inline Algorithm &final(Algorithm &alg) + { + alg.Finalize(); + return alg; + } +} // namespace act + +#endif // ACT_Algorithm_h diff --git a/port/thirdparty/cvact_compat/include/actBasics.h b/port/thirdparty/cvact_compat/include/actBasics.h new file mode 100644 index 000000000..22a661beb --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actBasics.h @@ -0,0 +1,36 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_Basics_h +#define ACT_Basics_h + +#include +#include + +namespace act +{ + typedef unsigned long ulong; + typedef unsigned int uint; + typedef unsigned short ushort; + typedef unsigned char uchar; + typedef unsigned char byte; + typedef unsigned short word; + typedef unsigned long dword; + + using std::size_t; + using std::ptrdiff_t; + + typedef int paramid_t; + typedef int status_t; + typedef int mode_t; + typedef int export_t; + + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; + typedef std::uint64_t uint64; +#ifndef U64 +#define U64(x) x##ULL +#endif + + const export_t DEFAULT = 0; +} // namespace act + +#endif // ACT_Basics_h diff --git a/port/thirdparty/cvact_compat/include/actBlob.h b/port/thirdparty/cvact_compat/include/actBlob.h new file mode 100644 index 000000000..c3d20319e --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actBlob.h @@ -0,0 +1,145 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +// Blob behaves like std::vector; released memory is wiped. The +// storage always keeps one zero byte behind the last element, so &blob[blob.size()] +// is addressable and the contents can be read as a C string. +#ifndef ACT_BLOB_H +#define ACT_BLOB_H + +#include "actBasics.h" +#include "actException.h" + +#include +#include +#include +#include +#include + +namespace act +{ + void SecureZero(void *p, size_t n) noexcept; + + class Blob + { + public: + typedef unsigned char byte; + typedef byte &reference; + typedef const byte &const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef byte value_type; + typedef byte *pointer; + typedef const byte *const_pointer; + typedef byte *iterator; + typedef const byte *const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static pointer get_base(iterator it) { return it; } + static const_pointer get_base(const_iterator it) { return it; } + + explicit Blob(const char *str); + explicit Blob(std::string &str); + Blob() noexcept; + Blob(size_type n, byte v = byte(0)); + Blob(const Blob &x); + Blob(Blob &&x) noexcept; + + template::value>::type> + Blob(InputIt f, InputIt l) : Blob() + { + insert(end(), f, l); + } + + ~Blob(); + + Blob &operator=(const Blob &x); + Blob &operator=(Blob &&x) noexcept; + + template::value>::type> + void assign(InputIt f, InputIt l) + { + Blob tmp(f, l); + swap(tmp); + } + void assign(size_type n, byte x = byte(0)); + + iterator begin() noexcept { return mFirst; } + const_iterator begin() const noexcept { return mFirst; } + iterator end() noexcept { return mFirst + mSize; } + const_iterator end() const noexcept { return mFirst + mSize; } + reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + size_type size() const noexcept { return mSize; } + size_type max_size() const noexcept { return size_type(-1) / 2; } + void resize(size_type n, byte x = byte(0)); + size_type capacity() const noexcept { return mCap; } + bool empty() const noexcept { return mSize == 0; } + void reserve(size_type n); + + const_reference operator[](size_type p) const { return mFirst[p]; } + reference operator[](size_type p) { return mFirst[p]; } + const_reference at(size_type p) const; + reference at(size_type p); + reference front() { return mFirst[0]; } + const_reference front() const { return mFirst[0]; } + reference back() { return mFirst[mSize - 1]; } + const_reference back() const { return mFirst[mSize - 1]; } + + void push_back(byte x); + void pop_back(); + iterator insert(iterator p, byte x = byte(0)); + void insert(iterator p, size_type m, byte x); + + template::value>::type> + void insert(iterator p, InputIt f, InputIt l) + { + std::vector tmp; + for (; f != l; ++f) + tmp.push_back(static_cast(*f)); + insert_raw(p, tmp.empty() ? 0 : &tmp[0], tmp.size()); + if (!tmp.empty()) + SecureZero(&tmp[0], tmp.size()); + } + + void append(const Blob &x); + void append(size_type m, byte x); + template::value>::type> + void append(InputIt f, InputIt l) + { + insert(end(), f, l); + } + + iterator erase(iterator p); + iterator erase(iterator f, iterator l); + void clear() noexcept; + void swap(Blob &x) noexcept; + + bool _eq(const Blob &x) const; + bool _lt(const Blob &x) const; + + private: + iterator insert_raw(iterator p, const byte *src, size_type m); + iterator make_gap(iterator p, size_type m); + void reallocate(size_type cap); + void release() noexcept; + void outofrange() const; + + byte *mFirst; + size_type mSize; + size_type mCap; + }; + + std::ostream &operator<<(std::ostream &os, const Blob &blob); + + inline bool operator==(const Blob &x, const Blob &y) { return x._eq(y); } + inline bool operator!=(const Blob &x, const Blob &y) { return !x._eq(y); } + inline bool operator<(const Blob &x, const Blob &y) { return x._lt(y); } + inline bool operator>=(const Blob &x, const Blob &y) { return !x._lt(y); } + inline bool operator<=(const Blob &x, const Blob &y) { return x._eq(y) || x._lt(y); } + inline bool operator>(const Blob &x, const Blob &y) { return !(x._eq(y) || x._lt(y)); } +} // namespace act + +#endif // ACT_BLOB_H diff --git a/port/thirdparty/cvact_compat/include/actDate.h b/port/thirdparty/cvact_compat/include/actDate.h new file mode 100644 index 000000000..004a6d206 --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actDate.h @@ -0,0 +1,94 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +// Dates are UTC; Encode() yields a DER UTCTime, EncodeToGeneralizedTime() a DER +// GeneralizedTime. +#ifndef ACT_Date_h +#define ACT_Date_h + +#include + +#include "actBasics.h" + +namespace act +{ + class Blob; + + class Date + { + public: + Date(); + Date(int day, int month, int year); + Date(int day, int month, int year, int hour, int minute, int sec); + Date(const Blob &der); + Date(const unsigned char *ch, const unsigned int size); + + Date &SetToday(); + + int GetDay() const { return m_day; } + int GetMonth() const { return m_month; } + int GetYear() const { return m_year; } + int GetHour() const { return m_hour; } + int GetMinute() const { return m_min; } + int GetSecond() const { return m_sec; } + + void IgnoreTime(bool b); + + const Date &operator=(const Date &); + bool operator>(const Date &) const; + bool operator>=(const Date &) const; + bool operator<(const Date &) const; + bool operator<=(const Date &) const; + bool operator==(const Date &) const; + bool operator!=(const Date &) const; + + const Date &AddMonths(int m); + const Date &SubMonths(int m); + const Date &AddYears(int y); + const Date &SubYears(int y); + const Date &AddDays(int d); + const Date &SubDays(int d); + const Date &AddHours(int h); + const Date &SubHours(int h); + const Date &AddMinutes(int m); + const Date &SubMinutes(int m); + const Date &AddSecond(int m); + const Date &SubSecond(int m); + + int DayOfWeek() const; // 0: Sunday ... 6: Saturday + int IsLeap(int y) const; + int DaysPerMonth(int m, int y) const; + long GetDifference(const Date &d2) const; // in days + long GetJulian() const; + long GetJulian(int d, int m, int y) const; + void ConvertFromJulian(long jd, int &d, int &m, int &y); + + Blob Encode() const; + Blob EncodeToGeneralizedTime() const; + operator Blob() const; + + // Day of month of the which-th (1-based, 5 = last) given weekday in month/year. + int GetDayFromWeekDay(int weekday, int year, int month, int which); + + static void copyDatetm(act::Date a, struct tm &b); + static void copytmDate(struct tm a, act::Date &b); + + private: + int m_day, m_month, m_year; + int m_hour, m_min, m_sec; + bool m_ignore_time; + + Date &SetYear(int year) { m_year = year; return *this; } + Date &SetMonth(int month) { m_month = month; return *this; } + Date &SetDay(int day) { m_day = day; return *this; } + Date &SetHour(int hour) { m_hour = hour; return *this; } + Date &SetMinute(int minute) { m_min = minute; return *this; } + Date &SetSecond(int sec) { m_sec = sec; return *this; } + bool IsValid() const; + void AdjustDays(); + void Decode(const unsigned char *ch, size_t size); + long long SecondsSinceEpochDay() const; + void SetFromSeconds(long long s); + int Compare(const Date &other) const; + }; +} // namespace act + +#endif // ACT_Date_h diff --git a/port/thirdparty/cvact_compat/include/actDefaultRNG.h b/port/thirdparty/cvact_compat/include/actDefaultRNG.h new file mode 100644 index 000000000..035356392 --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actDefaultRNG.h @@ -0,0 +1,14 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_DefaultRNG_h +#define ACT_DefaultRNG_h + +namespace act +{ + class IRNGAlg; + + typedef IRNGAlg *(*CreateRNGPtr)(); + extern CreateRNGPtr CreateFastRNG; + extern CreateRNGPtr CreateStrongRNG; +} // namespace act + +#endif // ACT_DefaultRNG_h diff --git a/port/thirdparty/cvact_compat/include/actException.h b/port/thirdparty/cvact_compat/include/actException.h new file mode 100644 index 000000000..a75e37b62 --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actException.h @@ -0,0 +1,132 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_EXCEPTION_H +#define ACT_EXCEPTION_H + +#include +#include +#include + +namespace act +{ + class FileAndLine + { + public: + FileAndLine(const char *file = 0, int line = 0) noexcept : m_line(line), m_file(file) {} + FileAndLine(const FileAndLine &other) noexcept : m_line(other.line()), m_file(other.file()) {} + virtual ~FileAndLine() {} + + virtual int line() const noexcept { return m_line; } + virtual const char *file() const noexcept { return m_file; } + + FileAndLine &operator=(const FileAndLine &other) noexcept + { + m_line = other.line(); + m_file = other.file(); + return *this; + } + + private: + int m_line; + const char *m_file; + }; + + // Messages are not copied: only string literals or otherwise static strings may be passed. + class Exception + { + public: + explicit Exception(const char *msg = 0, const char *where = 0) noexcept : m_what(msg), m_where(where) {} + + template().what()), + typename = decltype(std::declval().where()), + typename = typename std::enable_if::value>::type> + Exception(const T &other) : m_what(other.what()), m_where(other.where()) {} + + virtual ~Exception() noexcept {} + + virtual const char *what() const noexcept { return m_what != 0 ? m_what : ""; } + virtual const char *where() const noexcept { return m_where != 0 ? m_where : ""; } + + private: + const char *m_what; + const char *m_where; + }; + +#define ACT_COMPAT_EXCEPTION(name, base) \ + class name : public base \ + { \ + public: \ + name(const char *msg = 0, const char *where = 0) : base(msg, where) {} \ + }; + + ACT_COMPAT_EXCEPTION(BadException, Exception) + ACT_COMPAT_EXCEPTION(NullPointerException, BadException) + ACT_COMPAT_EXCEPTION(OutOfRangeException, BadException) + + ACT_COMPAT_EXCEPTION(LogicalException, Exception) + ACT_COMPAT_EXCEPTION(ASN1Exception, LogicalException) + ACT_COMPAT_EXCEPTION(NoSuchDLLException, LogicalException) + ACT_COMPAT_EXCEPTION(PasswordException, LogicalException) + ACT_COMPAT_EXCEPTION(AlgorithmException, LogicalException) + ACT_COMPAT_EXCEPTION(InvalidAlgorithmParameterException, AlgorithmException) + ACT_COMPAT_EXCEPTION(NoSuchAlgorithmException, AlgorithmException) + ACT_COMPAT_EXCEPTION(ArithmeticException, LogicalException) + ACT_COMPAT_EXCEPTION(CertificateException, LogicalException) + ACT_COMPAT_EXCEPTION(CertificateEncodingException, CertificateException) + ACT_COMPAT_EXCEPTION(CertificateExpiredException, CertificateException) + ACT_COMPAT_EXCEPTION(CertificateNotYetValidException, CertificateException) + ACT_COMPAT_EXCEPTION(CertificateParsingException, CertificateException) + ACT_COMPAT_EXCEPTION(KeyException, LogicalException) + ACT_COMPAT_EXCEPTION(InvalidKeyException, KeyException) + ACT_COMPAT_EXCEPTION(KeyManagementException, KeyException) + ACT_COMPAT_EXCEPTION(MessageDigestException, LogicalException) + ACT_COMPAT_EXCEPTION(PaddingException, LogicalException) + ACT_COMPAT_EXCEPTION(SignatureException, LogicalException) + ACT_COMPAT_EXCEPTION(SubsystemException, LogicalException) + ACT_COMPAT_EXCEPTION(NoSuchSubsystemException, SubsystemException) + + ACT_COMPAT_EXCEPTION(RuntimeException, Exception) + ACT_COMPAT_EXCEPTION(BadAllocException, RuntimeException) + +#undef ACT_COMPAT_EXCEPTION + + class SmartcardException : public LogicalException + { + public: + SmartcardException(const char *msg = 0, const char *where = 0, long code = 0) + : LogicalException(msg, where), m_code(code) {} + + virtual long code() const noexcept { return m_code; } + + private: + long m_code; + }; + +#define ACT_COMPAT_SC_EXCEPTION(name) \ + class name : public SmartcardException \ + { \ + public: \ + name(const char *msg = 0, const char *where = 0, long code = 0) : SmartcardException(msg, where, code) {} \ + }; + + ACT_COMPAT_SC_EXCEPTION(InvalidPinException) + ACT_COMPAT_SC_EXCEPTION(PinLockedException) + ACT_COMPAT_SC_EXCEPTION(PinExpiredException) + ACT_COMPAT_SC_EXCEPTION(PinLenRangeException) + ACT_COMPAT_SC_EXCEPTION(InvalidCardException) + ACT_COMPAT_SC_EXCEPTION(CardOutOfMemoryException) + +#undef ACT_COMPAT_SC_EXCEPTION + + class NotImplementedException : public FileAndLine, public RuntimeException + { + public: + explicit NotImplementedException(const char *msg = 0, const char *where = 0) + : RuntimeException(msg, where) {} + + NotImplementedException(const char *msg, const char *where, const char *file, int line) + : FileAndLine(file, line), RuntimeException(msg, where) {} + }; +} // namespace act + +#endif // ACT_EXCEPTION_H diff --git a/port/thirdparty/cvact_compat/include/actIAlgorithm.h b/port/thirdparty/cvact_compat/include/actIAlgorithm.h new file mode 100644 index 000000000..09d5b7dae --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actIAlgorithm.h @@ -0,0 +1,26 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_IALGORITHM_H +#define ACT_IALGORITHM_H + +#include "actBasics.h" + +namespace act +{ + class Blob; + + class IAlgorithm + { + public: + virtual void Write(const Blob &input) = 0; + virtual void Write(const byte *input, size_t insize) = 0; + virtual void Finalize() = 0; + virtual size_t GetAvailableSize() const = 0; + // Moves up to max (0: all) available output bytes into output, replacing its contents. + virtual size_t Read(Blob &output, size_t max = 0) = 0; + virtual size_t Read(byte *outbuffer, size_t buffersize) = 0; + virtual status_t GetStatus() const = 0; + virtual ~IAlgorithm() {} + }; +} // namespace act + +#endif // ACT_IALGORITHM_H diff --git a/port/thirdparty/cvact_compat/include/actIKey.h b/port/thirdparty/cvact_compat/include/actIKey.h new file mode 100644 index 000000000..a9ef45b3d --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actIKey.h @@ -0,0 +1,33 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_IKEY_H +#define ACT_IKEY_H + +#include "actBasics.h" +#include "actBlob.h" + +namespace act +{ + class IAlgorithm; + class IRNGAlg; + + class IKey + { + public: + virtual IKey *Clone() const = 0; + virtual void Import(const Blob &keyblob) = 0; + virtual void Export(Blob &keyblob, export_t type = DEFAULT) const = 0; + virtual void SetParam(paramid_t id, const Blob &blob) = 0; + virtual void SetParam(paramid_t id, int val) = 0; + virtual void SetParam(paramid_t id, const char *cstr) = 0; + virtual int GetParam(paramid_t id) const = 0; + virtual void GetParam(paramid_t id, Blob &blob) const = 0; + virtual void Generate(IRNGAlg *prng = 0) = 0; + virtual void Derive(const Blob &data, const Blob &salt = Blob()) = 0; + virtual IAlgorithm *CreateAlgorithm(mode_t Mode) const = 0; + virtual IAlgorithm *CreateAlgorithm(mode_t Mode, const Blob &data) const = 0; + virtual void *GetCreatePointer() const = 0; + virtual ~IKey() {} + }; +} // namespace act + +#endif // ACT_IKEY_H diff --git a/port/thirdparty/cvact_compat/include/actIRNGAlg.h b/port/thirdparty/cvact_compat/include/actIRNGAlg.h new file mode 100644 index 000000000..6e127d3a1 --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actIRNGAlg.h @@ -0,0 +1,26 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_IRNGAlg_h +#define ACT_IRNGAlg_h + +#include "actIAlgorithm.h" + +namespace act +{ + class Blob; + + class IRNGAlg : public IAlgorithm + { + public: + virtual IRNGAlg *Clone() const = 0; + virtual void Import(const Blob &keyblob) = 0; + virtual void Export(Blob &keyblob) const = 0; + virtual void SetParam(paramid_t id, const Blob &blob) = 0; + virtual void SetParam(paramid_t id, int val) = 0; + virtual void SetParam(paramid_t id, const char *cstr) = 0; + virtual int GetParam(paramid_t id) const = 0; + virtual void GetParam(paramid_t id, Blob &blob) const = 0; + virtual void *GetCreatePointer() const = 0; + }; +} // namespace act + +#endif // ACT_IRNGAlg_h diff --git a/port/thirdparty/cvact_compat/include/actInit.h b/port/thirdparty/cvact_compat/include/actInit.h new file mode 100644 index 000000000..a8588904e --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actInit.h @@ -0,0 +1,18 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef actInit_h +#define actInit_h + +#include "actBasics.h" +#include "actDefaultRNG.h" +#include "actRNGKit.h" + +namespace act +{ + const char *GetVersion(); + bool GetIsInit() noexcept; + void SetIsInit(bool bIsInit) noexcept; + + void Init(bool bAlwaysInit = false); +} // namespace act + +#endif // actInit_h diff --git a/port/thirdparty/cvact_compat/include/actKey.h b/port/thirdparty/cvact_compat/include/actKey.h new file mode 100644 index 000000000..2e2c7c97b --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actKey.h @@ -0,0 +1,53 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +// Supported key types: "IES" (EC-IES over prime curves) and "BlockCipher". +#ifndef ACT_KEY_H +#define ACT_KEY_H + +#include "actBasics.h" +#include "actBlob.h" + +namespace act +{ + class IRNGAlg; + class IAlgorithm; + class IKey; + + class Key + { + public: + Key(); + Key(const Key &key); + Key(IKey *keyptr); + Key(const Blob &keyblob); + Key(const char *keytype); + + void Import(const Blob &keyblob); + void Export(Blob &keyblob, export_t type = DEFAULT) const; + + void SetParam(paramid_t id, const Blob &blob); + void SetParam(paramid_t id, int val); + void SetParam(paramid_t id, const char *cstr); + int GetParam(paramid_t id) const; + void GetParam(paramid_t id, Blob &blob) const; + + void Generate(IAlgorithm *prng = 0); + void Derive(const Blob &data, const Blob &salt = Blob()); + + IAlgorithm *CreateAlgorithm(mode_t Mode) const; + IAlgorithm *CreateAlgorithm(mode_t Mode, const Blob &data) const; + + IKey *GetPointer(); + const IKey *GetPointer() const; + operator IKey *(); + operator const IKey *() const; + IKey *ReleasePointer(); + + Key &operator=(const Key &key); + ~Key(); + + private: + IKey *mKey; + }; +} // namespace act + +#endif // ACT_KEY_H diff --git a/port/thirdparty/cvact_compat/include/actMode.h b/port/thirdparty/cvact_compat/include/actMode.h new file mode 100644 index 000000000..625929c13 --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actMode.h @@ -0,0 +1,213 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_MODE_H +#define ACT_MODE_H + +namespace act +{ + enum + { + ENCRYPT=100, + DECRYPT, + SIGN, + VERIFY, + MAC, + PRIVATE =200, + PUBLIC, + SECRET, + DOMAINPARAMS, + PKCS8_TYPE, + CIPHER = 300, + PADDING, + DERIVATOR, + BCMODE, + KEYSIZE, + RAWKEY, + IV, + BLOCKSIZE, + CHAINING_VALUE, + CHAINING_BITCOUNT, + EFFECTIVE_KEYSIZE, + SHAREDDATA_1, + SHAREDDATA_2, + KEYDATALEN, + ITERATIONCOUNT, + ENCODER=400, + PRIVATEKEY, + PUBLICKEY, + PUBLICSIZE, + KEY, + SIGNATURE, + AGREEMENT, + MODULO=500, + PRIME_P, + PRIME_Q, + MODULOSIZE, + PRIME_P_SIZE, + PRIME_Q_SIZE, + CRT_EXPONENT_1, + CRT_EXPONENT_2, + CRT_COEFFICIENT, + CURVE=600, + PUBLIC_X, + PUBLIC_Y, + STATICPUBLIC_X, + STATICPUBLIC_Y, + EPHEMERALPUBLIC_X, + EPHEMERALPUBLIC_Y, + CURVEPARAM, + PUBLICKEY_EXPORT_TYPE, + BASEPOINT_EXPORT_TYPE, + COMPRESSED, + UNCOMPRESSED, + HYBRID, + IMPLICITLYCA, + GF2CURVE, + PRIMECURVE, + RING = 700, + RINGORDER, + RINGGENERATOR, + COFACTOR, + COMPATIBLE, + NEWEPHEMERAL, + CHECKDOMAINPARAMS, + STATICPRIVATEKEY, + STATICPUBLICKEY, + EPHEMERALPRIVATEKEY, + EPHEMERALPUBLICKEY, + PIN = 800, + CARDTYPE, + CARDPORTTYPE, + PORTNR, + DLLNAME, + READERNAME, + CHANGEMASTERPIN, + CHANGEPIN, + USERPIN, + MASTERPIN, + PINPAD, + USERNAME, + INFOTEXT, + SIGNKEY, + ENCKEY, + SIGNCERTIFICATE, + ENCCERTIFICATE, + ROOTCERTIFICATE, + LOCK_KEY, + DHKEY, + DHCERTIFICATE, + PERSONALIZED, + READERNAMES, + AID, + NULLPIN, + SELECTKEY, + ALLCERTIFICATE, + APPLICATION, + KEYUSAGE, + MECHANISM, + CERTIFICATE, + KEYTYPE, + LABEL, + ID, + CTAPI_PORT = 900, + PCSC_PORT, + CARDOS_CARD = 1000, + TCOS_CARD, + CVACT_CARD, + PKCS11_CARD, + MICARDOEC_CARD, + STARCOSPK_CARD, + ETRUST_CARD, + CARDOSM4_CARD, + MICARDOP21_CARD, + HASH=1100, + SALT, + SALT_LENGTH, + EMLEN, + X = 1200, + MULTIPLIER, + VERSION = 1300, + ISSUER, + SUBJECT, + SERIALNR, + ISSUER_DER, + SUBJECT_DER, + ISSUER_UID, + SUBJECT_UID, + NOTBEFORE_DER, + NOTAFTER_DER, + THISUPDATE_DER, + NEXTUPDATE_DER, + TBS, + SECGp112r1=0x1000, + SECGp112r2, + SECGp128r1, + SECGp128r2, + SECGp160r1, + SECGp160r2, + SECGp160k1, + ANSIp192r1, + ANSIp192r2, + ANSIp192r3, + NISTp192r1, + SECGp192r1, + SECGp192k1, + NISTp224r1, + SECGp224r1, + SECGp224k1, + ANSIp239r1, + ANSIp239r2, + ANSIp239r3, + ANSIp256r1, + NISTp256r1, + SECGp256r1, + SECGp256k1, + NISTp384r1, + NISTp521r1, + SECGz113r1=0x2000, + SECGz113r2, + SECGz131r1, + SECGz131r2, + ANSIz163r1, + ANSIz163r2, + ANSIz163r3, + NISTz163r1, + NISTz163k1, + SECGz163r1, + SECGz163r2, + SECGz163k1, + ANSIz176w1, + ANSIz191r1, + ANSIz191r2, + ANSIz191r3, + SECGz193r1, + SECGz193r2, + ANSIz208w1, + NISTz233r1, + NISTz233k1, + SECGz233r1, + SECGz233k1, + ANSIz239r1, + ANSIz239r2, + ANSIz239r3, + SECGz239k1, + ANSIz272w1, + NISTz283r1, + NISTz283k1, + SECGz283r1, + SECGz283k1, + ANSIz304w1, + ANSIz359r1, + ANSIz368w1, + NISTz409r1, + NISTz409k1, + SECGz409r1, + SECGz409k1, + ANSIz431r1, + NISTz571r1, + NISTz571k1, + SECGz571r1, + SECGz571k1 + }; +} // namespace act + +#endif // ACT_MODE_H diff --git a/port/thirdparty/cvact_compat/include/actRNGKit.h b/port/thirdparty/cvact_compat/include/actRNGKit.h new file mode 100644 index 000000000..5052722fd --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actRNGKit.h @@ -0,0 +1,15 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +// All generators are backed by the OpenSSL CSPRNG; written data is mixed in as seed. +#ifndef ACT_RNGKit_h +#define ACT_RNGKit_h + +namespace act +{ + class IRNGAlg; + + IRNGAlg *CreateDevRandomRNG(); + IRNGAlg *CreateBBS(); + IRNGAlg *CreateFIPS186(); +} // namespace act + +#endif // ACT_RNGKit_h diff --git a/port/thirdparty/cvact_compat/include/actState.h b/port/thirdparty/cvact_compat/include/actState.h new file mode 100644 index 000000000..c26351b15 --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actState.h @@ -0,0 +1,16 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_STATE_H +#define ACT_STATE_H + +namespace act +{ + const int READY = 0; + const int SIGNATURE_OK = 1; + const int IS_FINALIZED = 2; + const int DECRYPT_ERROR = 3; + const int CERTIFICATE_OK = 4; + const int CERTIFICATE_ERROR = 5; + const int VERIFY_ERROR = 6; +} // namespace act + +#endif // ACT_STATE_H diff --git a/port/thirdparty/cvact_compat/include/actTools.h b/port/thirdparty/cvact_compat/include/actTools.h new file mode 100644 index 000000000..5b92b311e --- /dev/null +++ b/port/thirdparty/cvact_compat/include/actTools.h @@ -0,0 +1,40 @@ +// Source-compatible replacement for the cv act library (subset used by CrypTool). +#ifndef ACT_TOOLS_H +#define ACT_TOOLS_H + +#include "actMode.h" +#include "actBlob.h" +#include "actIKey.h" + +namespace act +{ + // Encodes a binary object identifier, e.g. EncodeOID("1.2.840.10045.2.1"). + Blob EncodeOID(const char *oid); + + // Signed decimal or hexadecimal ("0x" / "-0x") number to big-endian two's complement. + Blob EncodeNumber(const char *number); + Blob EncodeNumber(int number); + + // Unsigned hexadecimal number (optional "0x" prefix) to Blob and back. + // blob2hex writes 2 * b.size() lowercase digits plus a terminating NUL. + Blob hex2blob(const char *hexnumber); + void blob2hex(const Blob &b, char *hexnumber); + + bool blob2file(const char *filename, const act::Blob &blob); + bool file2blob(const char *filename, Blob &blob); + + unsigned long CalculateCRC16(const act::byte *message, size_t message_len, + unsigned long crc_init_value = 0x0000); + unsigned long CalculateCRC16(const act::Blob &message, + unsigned long crc_init_value = 0x0000); + unsigned long CalculateCRC16CCITT(const act::byte *message, size_t message_len, + unsigned long crc_init_value = 0xFFFF); + unsigned long CalculateCRC16CCITT(const act::Blob &message, + unsigned long crc_init_value = 0xFFFF); + unsigned long CalculateCRC32(const act::byte *message, size_t message_len, + unsigned long crc_init_value = 0xFFFFFFFF); + unsigned long CalculateCRC32(const act::Blob &message, + unsigned long crc_init_value = 0xFFFFFFFF); +} // namespace act + +#endif // ACT_TOOLS_H diff --git a/port/thirdparty/cvact_compat/src/Algorithm.cpp b/port/thirdparty/cvact_compat/src/Algorithm.cpp new file mode 100644 index 000000000..b930c2f93 --- /dev/null +++ b/port/thirdparty/cvact_compat/src/Algorithm.cpp @@ -0,0 +1,232 @@ +#include "actInternal.h" +#include "actInit.h" +#include "actRNGKit.h" +#include "actDefaultRNG.h" + +#include +#include + +#include +#include + +namespace act +{ + namespace detail + { + size_t BufferedAlgorithm::Read(Blob &output, size_t max) + { + size_t n = mOut.size(); + if (max != 0 && max < n) + n = max; + output.assign(mOut.begin(), mOut.begin() + n); + mOut.erase(mOut.begin(), mOut.begin() + n); + return n; + } + + size_t BufferedAlgorithm::Read(byte *outbuffer, size_t buffersize) + { + size_t n = mOut.size() < buffersize ? mOut.size() : buffersize; + if (n != 0) + std::memcpy(outbuffer, mOut.begin(), n); + mOut.erase(mOut.begin(), mOut.begin() + n); + return n; + } + + class HashAlgorithm : public BufferedAlgorithm + { + public: + explicit HashAlgorithm(const EVP_MD *md) : mCtx(EVP_MD_CTX_new()) + { + if (mCtx == 0 || EVP_DigestInit_ex(mCtx, md, 0) != 1) + { + EVP_MD_CTX_free(mCtx); + throw AlgorithmException("hash initialisation failed", "HashAlgorithm"); + } + } + ~HashAlgorithm() { EVP_MD_CTX_free(mCtx); } + + void Write(const Blob &input) { Write(input.begin(), input.size()); } + void Write(const byte *input, size_t insize) + { + if (mStatus == IS_FINALIZED) + throw AlgorithmException("algorithm already finalized", "HashAlgorithm::Write"); + if (insize != 0 && EVP_DigestUpdate(mCtx, input, insize) != 1) + throw AlgorithmException("hash update failed", "HashAlgorithm::Write"); + } + void Finalize() + { + if (mStatus == IS_FINALIZED) + return; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int len = 0; + if (EVP_DigestFinal_ex(mCtx, md, &len) != 1) + throw AlgorithmException("hash finalisation failed", "HashAlgorithm::Finalize"); + mOut.insert(mOut.end(), md, md + len); + mStatus = IS_FINALIZED; + } + + private: + EVP_MD_CTX *mCtx; + }; + + IAlgorithm *CreateHashAlgorithm(const char *name) + { + static const struct { const char *act; const char *ossl; } names[] = { + {"MD5", "MD5"}, {"SHA1", "SHA1"}, {"SHA224", "SHA224"}, {"SHA256", "SHA256"}, + {"SHA384", "SHA384"}, {"SHA512", "SHA512"}, {"RIPEMD160", "RIPEMD160"}, + }; + for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) + { + if (std::strcmp(name, names[i].act) != 0) + continue; + EVP_MD *md = EVP_MD_fetch(0, names[i].ossl, 0); + if (md == 0) + break; + try + { + IAlgorithm *alg = new HashAlgorithm(md); + EVP_MD_free(md); + return alg; + } + catch (...) + { + EVP_MD_free(md); + throw; + } + } + return 0; + } + + class OpenSSLRng : public IRNGAlg + { + public: + explicit OpenSSLRng(CreateRNGPtr factory) : mFactory(factory) {} + + void Write(const Blob &input) { Write(input.begin(), input.size()); } + void Write(const byte *input, size_t insize) + { + if (insize != 0) + RAND_seed(input, static_cast(insize)); + } + void Finalize() {} + size_t GetAvailableSize() const { return 0; } + size_t Read(Blob &output, size_t max) + { + size_t n = max != 0 ? max : output.size(); + output.resize(n); + RandomBytes(output.begin(), n, 0); + return n; + } + size_t Read(byte *outbuffer, size_t buffersize) + { + RandomBytes(outbuffer, buffersize, 0); + return buffersize; + } + status_t GetStatus() const { return READY; } + + IRNGAlg *Clone() const { return new OpenSSLRng(mFactory); } + void Import(const Blob &keyblob) { Write(keyblob); } + void Export(Blob &keyblob) const { keyblob.clear(); } + void SetParam(paramid_t, const Blob &blob) { Write(blob); } + void SetParam(paramid_t, int) {} + void SetParam(paramid_t, const char *) {} + int GetParam(paramid_t) const { return 0; } + void GetParam(paramid_t, Blob &blob) const { blob.clear(); } + void *GetCreatePointer() const { return reinterpret_cast(mFactory); } + + private: + CreateRNGPtr mFactory; + }; + } // namespace detail + + IRNGAlg *CreateBBS() { return new detail::OpenSSLRng(&CreateBBS); } + IRNGAlg *CreateFIPS186() { return new detail::OpenSSLRng(&CreateFIPS186); } + IRNGAlg *CreateDevRandomRNG() { return new detail::OpenSSLRng(&CreateDevRandomRNG); } + + CreateRNGPtr CreateFastRNG = &CreateFIPS186; + CreateRNGPtr CreateStrongRNG = &CreateBBS; + + namespace + { + bool g_isInit = false; + } + + const char *GetVersion() + { + return "cvact_compat 1.4.6 (OpenSSL backend)"; + } + + bool GetIsInit() noexcept { return g_isInit; } + void SetIsInit(bool bIsInit) noexcept { g_isInit = bIsInit; } + + void Init(bool bAlwaysInit) + { + if (g_isInit && !bAlwaysInit) + return; + CreateFastRNG = &CreateFIPS186; + CreateStrongRNG = &CreateBBS; + g_isInit = true; + } + + Algorithm::Algorithm(IAlgorithm *alg) : mAlg(alg) + { + if (mAlg == 0) + throw NullPointerException("null algorithm", "Algorithm::Algorithm"); + } + + Algorithm::Algorithm(const IKey *key, mode_t mode) : mAlg(0) + { + if (key == 0) + throw NullPointerException("null key", "Algorithm::Algorithm"); + mAlg = key->CreateAlgorithm(mode); + if (mAlg == 0) + throw InvalidAlgorithmParameterException("mode not supported by key", "Algorithm::Algorithm"); + } + + Algorithm::Algorithm(const IKey *key, mode_t mode, const Blob &data) : mAlg(0) + { + if (key == 0) + throw NullPointerException("null key", "Algorithm::Algorithm"); + mAlg = key->CreateAlgorithm(mode, data); + if (mAlg == 0) + throw InvalidAlgorithmParameterException("mode not supported by key", "Algorithm::Algorithm"); + } + + Algorithm::Algorithm(const char *name) : mAlg(0) + { + if (name == 0) + throw NullPointerException("null algorithm name", "Algorithm::Algorithm"); + if (std::strcmp(name, "BBS") == 0) + mAlg = CreateBBS(); + else if (std::strcmp(name, "FIPS186") == 0) + mAlg = CreateFIPS186(); + else if (std::strcmp(name, "DevRandom") == 0) + mAlg = CreateDevRandomRNG(); + else + mAlg = detail::CreateHashAlgorithm(name); + if (mAlg == 0) + throw NoSuchAlgorithmException("unknown algorithm", "Algorithm::Algorithm"); + } + + Algorithm::~Algorithm() { delete mAlg; } + + void Algorithm::Write(const Blob &indata) { mAlg->Write(indata); } + void Algorithm::Write(const byte *indata, size_t insize) { mAlg->Write(indata, insize); } + void Algorithm::Finalize() { mAlg->Finalize(); } + size_t Algorithm::Read(Blob &outdata, size_t max) { return mAlg->Read(outdata, max); } + size_t Algorithm::Read(byte *outbuffer, size_t buffersize) { return mAlg->Read(outbuffer, buffersize); } + size_t Algorithm::GetAvailableSize() const { return mAlg->GetAvailableSize(); } + status_t Algorithm::GetStatus() const { return mAlg->GetStatus(); } + + Algorithm::operator IAlgorithm *() { return mAlg; } + Algorithm::operator const IAlgorithm *() const { return mAlg; } + IAlgorithm *Algorithm::GetPointer() { return mAlg; } + const IAlgorithm *Algorithm::GetPointer() const { return mAlg; } + + IAlgorithm *Algorithm::ReleasePointer() + { + IAlgorithm *p = mAlg; + mAlg = 0; + return p; + } +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/Blob.cpp b/port/thirdparty/cvact_compat/src/Blob.cpp new file mode 100644 index 000000000..2c8731c7e --- /dev/null +++ b/port/thirdparty/cvact_compat/src/Blob.cpp @@ -0,0 +1,279 @@ +#include "actBlob.h" + +#include + +#include +#include +#include +#include + +namespace act +{ + namespace + { + // Shared terminator for blobs without own storage; never written to by Blob itself. + byte g_empty[1] = {0}; + } + + void SecureZero(void *p, size_t n) noexcept + { + if (p != 0 && n != 0) + OPENSSL_cleanse(p, n); + } + + Blob::Blob() noexcept : mFirst(g_empty), mSize(0), mCap(0) {} + + Blob::Blob(const char *str) : Blob() + { + if (str != 0) + insert_raw(end(), reinterpret_cast(str), std::strlen(str)); + } + + Blob::Blob(std::string &str) : Blob() + { + insert_raw(end(), reinterpret_cast(str.data()), str.size()); + } + + Blob::Blob(size_type n, byte v) : Blob() + { + insert(end(), n, v); + } + + Blob::Blob(const Blob &x) : Blob() + { + insert_raw(end(), x.mFirst, x.mSize); + } + + Blob::Blob(Blob &&x) noexcept : Blob() + { + swap(x); + } + + Blob::~Blob() + { + release(); + } + + Blob &Blob::operator=(const Blob &x) + { + if (this != &x) + { + if (x.mSize <= mCap) + { + if (x.mSize != 0) + std::memmove(mFirst, x.mFirst, x.mSize); + if (mSize > x.mSize) + SecureZero(mFirst + x.mSize, mSize - x.mSize); + mSize = x.mSize; + if (mCap != 0) + mFirst[mSize] = 0; + } + else + { + Blob tmp(x); + swap(tmp); + } + } + return *this; + } + + Blob &Blob::operator=(Blob &&x) noexcept + { + if (this != &x) + { + release(); + swap(x); + } + return *this; + } + + void Blob::assign(size_type n, byte x) + { + clear(); + insert(end(), n, x); + } + + void Blob::release() noexcept + { + if (mCap != 0) + { + SecureZero(mFirst, mCap + 1); + std::free(mFirst); + } + mFirst = g_empty; + mSize = 0; + mCap = 0; + } + + void Blob::reallocate(size_type cap) + { + byte *p = static_cast(std::malloc(cap + 1)); + if (p == 0) + throw BadAllocException("out of memory", "Blob::reallocate"); + if (mSize != 0) + std::memcpy(p, mFirst, mSize); + std::memset(p + mSize, 0, cap + 1 - mSize); + size_type size = mSize; + release(); + mFirst = p; + mSize = size; + mCap = cap; + } + + void Blob::reserve(size_type n) + { + if (n > mCap) + reallocate(n); + } + + Blob::iterator Blob::make_gap(iterator p, size_type m) + { + size_type off = static_cast(p - mFirst); + if (off > mSize) + outofrange(); + if (m == 0) + return mFirst + off; + if (mSize + m > mCap) + { + size_type cap = mCap * 2; + if (cap < mSize + m) + cap = mSize + m; + if (cap < 16) + cap = 16; + reallocate(cap); + } + std::memmove(mFirst + off + m, mFirst + off, mSize - off); + mSize += m; + mFirst[mSize] = 0; + return mFirst + off; + } + + Blob::iterator Blob::insert_raw(iterator p, const byte *src, size_type m) + { + iterator q = make_gap(p, m); + if (m != 0) + std::memcpy(q, src, m); + return q; + } + + Blob::iterator Blob::insert(iterator p, byte x) + { + return insert_raw(p, &x, 1); + } + + void Blob::insert(iterator p, size_type m, byte x) + { + iterator q = make_gap(p, m); + if (m != 0) + std::memset(q, x, m); + } + + void Blob::resize(size_type n, byte x) + { + if (n > mSize) + insert(end(), n - mSize, x); + else if (n < mSize) + erase(begin() + n, end()); + } + + Blob::const_reference Blob::at(size_type p) const + { + if (p >= mSize) + outofrange(); + return mFirst[p]; + } + + Blob::reference Blob::at(size_type p) + { + if (p >= mSize) + outofrange(); + return mFirst[p]; + } + + void Blob::push_back(byte x) + { + insert_raw(end(), &x, 1); + } + + void Blob::pop_back() + { + if (mSize != 0) + erase(end() - 1); + } + + void Blob::append(const Blob &x) + { + if (&x == this) + { + Blob tmp(x); + insert_raw(end(), tmp.mFirst, tmp.mSize); + } + else + insert_raw(end(), x.mFirst, x.mSize); + } + + void Blob::append(size_type m, byte x) + { + insert(end(), m, x); + } + + Blob::iterator Blob::erase(iterator p) + { + return erase(p, p + 1); + } + + Blob::iterator Blob::erase(iterator f, iterator l) + { + size_type off = static_cast(f - mFirst); + size_type last = static_cast(l - mFirst); + if (off > last || last > mSize) + outofrange(); + size_type m = last - off; + if (m != 0) + { + std::memmove(mFirst + off, mFirst + last, mSize - last); + SecureZero(mFirst + mSize - m, m); + mSize -= m; + } + return mFirst + off; + } + + void Blob::clear() noexcept + { + if (mCap != 0) + SecureZero(mFirst, mSize); + mSize = 0; + } + + void Blob::swap(Blob &x) noexcept + { + std::swap(mFirst, x.mFirst); + std::swap(mSize, x.mSize); + std::swap(mCap, x.mCap); + } + + bool Blob::_eq(const Blob &x) const + { + return mSize == x.mSize && (mSize == 0 || std::memcmp(mFirst, x.mFirst, mSize) == 0); + } + + bool Blob::_lt(const Blob &x) const + { + size_type n = mSize < x.mSize ? mSize : x.mSize; + int c = n == 0 ? 0 : std::memcmp(mFirst, x.mFirst, n); + return c < 0 || (c == 0 && mSize < x.mSize); + } + + void Blob::outofrange() const + { + throw OutOfRangeException("invalid Blob subscript", "Blob::outofrange"); + } + + std::ostream &operator<<(std::ostream &os, const Blob &blob) + { + static const char digits[] = "0123456789abcdef"; + for (Blob::const_iterator it = blob.begin(); it != blob.end(); ++it) + os << digits[*it >> 4] << digits[*it & 0x0f]; + return os; + } +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/BlockCipherKey.cpp b/port/thirdparty/cvact_compat/src/BlockCipherKey.cpp new file mode 100644 index 000000000..ff923f0c6 --- /dev/null +++ b/port/thirdparty/cvact_compat/src/BlockCipherKey.cpp @@ -0,0 +1,408 @@ +// "BlockCipher" key: AES (alias Rijndael) or TripleDES in ECB/CBC/CFB/OFB/CTR mode, +// PKCS#5 padding (or NOPAD) for ECB/CBC. Without an explicit IV a random IV is +// generated on encryption and prepended to the ciphertext; decryption without an +// explicit IV takes the IV from the first block of the ciphertext. +#include "actInternal.h" + +#include + +#include +#include + +namespace act +{ + namespace detail + { + namespace + { + struct CipherInfo + { + const char *name; + size_t blockSize; + size_t keySizes[3]; + }; + + const CipherInfo kCiphers[] = { + {"AES", 16, {16, 24, 32}}, + {"TripleDES", 8, {16, 24, 0}}, + }; + + const CipherInfo *FindCipher(const std::string &name) + { + std::string n = name == "Rijndael" ? "AES" : name; + for (size_t i = 0; i < sizeof(kCiphers) / sizeof(kCiphers[0]); ++i) + if (n == kCiphers[i].name) + return &kCiphers[i]; + return 0; + } + + bool IsSupportedMode(const std::string &mode) + { + return mode == "ECB" || mode == "CBC" || mode == "CFB" || mode == "OFB" || mode == "CTR"; + } + + std::string EvpCipherName(const CipherInfo &info, const std::string &mode, size_t keySize) + { + if (std::strcmp(info.name, "AES") == 0) + return "AES-" + std::to_string(keySize * 8) + "-" + mode; + return std::string(keySize == 16 ? "DES-EDE-" : "DES-EDE3-") + mode; + } + + std::string ToString(const Blob &b) + { + return std::string(reinterpret_cast(b.begin()), b.size()); + } + + class BlockCipherAlgorithm : public BufferedAlgorithm + { + public: + BlockCipherAlgorithm(const std::string &evpName, const Blob &key, const Blob &iv, + bool explicitIV, bool encrypt, bool padding) + : mCtx(EVP_CIPHER_CTX_new()), mCipher(EVP_CIPHER_fetch(0, evpName.c_str(), 0)), + mKey(key), mEncrypt(encrypt), mPadding(padding), mStarted(false), mIVLen(0) + { + if (mCtx == 0 || mCipher == 0) + { + Cleanup(); + throw NoSuchAlgorithmException("cipher not available", "BlockCipherAlgorithm"); + } + try + { + mIVLen = static_cast(EVP_CIPHER_get_iv_length(mCipher)); + if (mIVLen == 0 || explicitIV) + { + if (mIVLen != 0 && iv.size() != mIVLen) + throw InvalidAlgorithmParameterException("invalid IV length", "BlockCipherAlgorithm"); + Start(iv); + } + else if (mEncrypt) + { + Blob random(mIVLen); + RandomBytes(random.begin(), random.size(), 0); + mOut.append(random); + Start(random); + } + } + catch (...) + { + Cleanup(); + throw; + } + } + + ~BlockCipherAlgorithm() { Cleanup(); } + + void Write(const Blob &input) { Write(input.begin(), input.size()); } + + void Write(const byte *input, size_t insize) + { + if (mStatus == IS_FINALIZED) + throw AlgorithmException("algorithm already finalized", "BlockCipherAlgorithm::Write"); + if (!mStarted) + { + size_t take = mIVLen - mPendingIV.size(); + if (take > insize) + take = insize; + mPendingIV.insert(mPendingIV.end(), input, input + take); + input += take; + insize -= take; + if (mPendingIV.size() < mIVLen) + return; + Start(mPendingIV); + } + if (insize == 0) + return; + size_t pos = mOut.size(); + mOut.resize(pos + insize + EVP_MAX_BLOCK_LENGTH); + int outl = 0; + if (EVP_CipherUpdate(mCtx, mOut.begin() + pos, &outl, input, static_cast(insize)) != 1) + { + mOut.resize(pos); + throw AlgorithmException("cipher update failed", "BlockCipherAlgorithm::Write"); + } + mOut.resize(pos + static_cast(outl)); + } + + void Finalize() + { + if (mStatus == IS_FINALIZED) + return; + if (!mStarted) + { + mStatus = DECRYPT_ERROR; + throw AlgorithmException("ciphertext too short", "BlockCipherAlgorithm::Finalize"); + } + size_t pos = mOut.size(); + mOut.resize(pos + EVP_MAX_BLOCK_LENGTH); + int outl = 0; + if (EVP_CipherFinal_ex(mCtx, mOut.begin() + pos, &outl) != 1) + { + mOut.clear(); + mStatus = DECRYPT_ERROR; + throw PaddingException("bad padding, wrong key or wrong data length", "BlockCipherAlgorithm::Finalize"); + } + mOut.resize(pos + static_cast(outl)); + mStatus = IS_FINALIZED; + } + + private: + void Start(const Blob &iv) + { + if (EVP_CipherInit_ex2(mCtx, mCipher, mKey.begin(), iv.empty() ? 0 : iv.begin(), + mEncrypt ? 1 : 0, 0) != 1 + || EVP_CIPHER_CTX_set_padding(mCtx, mPadding ? 1 : 0) != 1) + throw AlgorithmException("cipher initialisation failed", "BlockCipherAlgorithm"); + mStarted = true; + } + + void Cleanup() + { + EVP_CIPHER_CTX_free(mCtx); + EVP_CIPHER_free(mCipher); + mCtx = 0; + mCipher = 0; + } + + EVP_CIPHER_CTX *mCtx; + EVP_CIPHER *mCipher; + Blob mKey; + Blob mPendingIV; + bool mEncrypt; + bool mPadding; + bool mStarted; + size_t mIVLen; + }; + + IKey *NewBlockCipherKey(); + + class BlockCipherKey : public IKey + { + public: + BlockCipherKey() + : mCipher("AES"), mMode("CBC"), mPadding("PKCS5"), mDerivator("KDF1"), mHash("SHA512"), + mKeySize(10), mHasKey(false), mHasIV(false) {} + + IKey *Clone() const { return new BlockCipherKey(*this); } + + void Import(const Blob &keyblob) { SetParam(RAWKEY, keyblob); } + + void Export(Blob &keyblob, export_t type) const + { + if (type != DEFAULT && type != SECRET) + throw InvalidKeyException("unsupported export type", "BlockCipherKey::Export"); + GetParam(RAWKEY, keyblob); + } + + void SetParam(paramid_t id, const Blob &blob) + { + switch (id) + { + case RAWKEY: + if (!IsSupportedKeySize(blob.size())) + throw InvalidKeyException("unsupported key size", "BlockCipherKey::SetParam"); + mRawKey = blob; + mKeySize = static_cast(blob.size()); + mHasKey = true; + break; + case IV: + if (blob.size() != Info().blockSize) + throw InvalidAlgorithmParameterException("invalid IV length", "BlockCipherKey::SetParam"); + mIV = blob; + mHasIV = true; + break; + case CIPHER: + case BCMODE: + case PADDING: + case DERIVATOR: + case HASH: + SetParam(id, ToString(blob).c_str()); + break; + default: + throw InvalidKeyException("unsupported parameter", "BlockCipherKey::SetParam"); + } + } + + void SetParam(paramid_t id, int val) + { + if (id != KEYSIZE || val <= 0) + throw InvalidKeyException("unsupported parameter", "BlockCipherKey::SetParam"); + mKeySize = val; + } + + void SetParam(paramid_t id, const char *cstr) + { + if (cstr == 0) + throw NullPointerException("null parameter", "BlockCipherKey::SetParam"); + std::string value(cstr); + switch (id) + { + case CIPHER: + if (FindCipher(value) == 0) + throw NoSuchAlgorithmException("unsupported block cipher", "BlockCipherKey::SetParam"); + mCipher = value == "Rijndael" ? "AES" : value; + mRawKey.clear(); + mHasKey = false; + mIV.clear(); + mHasIV = false; + break; + case BCMODE: + if (!IsSupportedMode(value)) + throw NoSuchAlgorithmException("unsupported block cipher mode", "BlockCipherKey::SetParam"); + mMode = value; + break; + case PADDING: + if (value != "PKCS5" && value != "NOPAD") + throw NoSuchAlgorithmException("unsupported padding", "BlockCipherKey::SetParam"); + mPadding = value; + break; + case DERIVATOR: + if (value != "KDF1" && value != "KDF2" && value != "X963KDF") + throw NoSuchAlgorithmException("unsupported derivator", "BlockCipherKey::SetParam"); + mDerivator = value; + break; + case HASH: + Digest(value.c_str(), Blob()); + mHash = value; + break; + default: + throw InvalidKeyException("unsupported parameter", "BlockCipherKey::SetParam"); + } + } + + int GetParam(paramid_t id) const + { + switch (id) + { + case KEYSIZE: + return mHasKey ? static_cast(mRawKey.size()) : static_cast(EffectiveKeySize()); + case BLOCKSIZE: + return static_cast(Info().blockSize); + default: + throw InvalidKeyException("unsupported parameter", "BlockCipherKey::GetParam"); + } + } + + void GetParam(paramid_t id, Blob &blob) const + { + switch (id) + { + case RAWKEY: + if (!mHasKey) + throw InvalidKeyException("no key available", "BlockCipherKey::GetParam"); + blob = mRawKey; + break; + case IV: + blob = mIV; + break; + case CIPHER: blob = Blob(mCipher.c_str()); break; + case BCMODE: blob = Blob(mMode.c_str()); break; + case PADDING: blob = Blob(mPadding.c_str()); break; + case DERIVATOR: blob = Blob(mDerivator.c_str()); break; + case HASH: blob = Blob(mHash.c_str()); break; + default: + throw InvalidKeyException("unsupported parameter", "BlockCipherKey::GetParam"); + } + } + + void Generate(IRNGAlg *prng) + { + Blob key(EffectiveKeySize()); + RandomBytes(key.begin(), key.size(), prng); + SetParam(RAWKEY, key); + } + + // KDF1 (IEEE 1363): Hash(data || salt); KDF2/X963KDF: ANSI X9.63 KDF with salt as SharedInfo. + void Derive(const Blob &data, const Blob &salt) + { + size_t len = EffectiveKeySize(); + Blob key; + if (mDerivator == "KDF1") + { + Blob input(data); + input.append(salt); + key = Digest(mHash.c_str(), input); + SecureZero(input.begin(), input.size()); + if (key.size() < len) + throw InvalidAlgorithmParameterException("KDF1 output too short for key size", "BlockCipherKey::Derive"); + key.resize(len); + } + else + key = X963Kdf(mHash.c_str(), data, salt, len); + SetParam(RAWKEY, key); + } + + IAlgorithm *CreateAlgorithm(mode_t Mode) const + { + IAlgorithm *alg = Create(Mode, mIV, mHasIV); + if (Mode == ENCRYPT) + { + mIV.clear(); + mHasIV = false; + } + return alg; + } + + IAlgorithm *CreateAlgorithm(mode_t Mode, const Blob &data) const + { + return Create(Mode, data, true); + } + + void *GetCreatePointer() const { return reinterpret_cast(&NewBlockCipherKey); } + + private: + const CipherInfo &Info() const { return *FindCipher(mCipher); } + + bool IsSupportedKeySize(size_t n) const + { + const CipherInfo &info = Info(); + for (size_t i = 0; i < 3; ++i) + if (info.keySizes[i] != 0 && info.keySizes[i] == n) + return true; + return false; + } + + size_t EffectiveKeySize() const + { + const CipherInfo &info = Info(); + size_t largest = 0; + for (size_t i = 0; i < 3; ++i) + { + size_t s = info.keySizes[i]; + if (s == 0) + continue; + if (s >= static_cast(mKeySize)) + return s; + largest = s; + } + return largest; + } + + IAlgorithm *Create(mode_t Mode, const Blob &iv, bool explicitIV) const + { + if (Mode != ENCRYPT && Mode != DECRYPT) + throw InvalidAlgorithmParameterException("unsupported mode", "BlockCipherKey::CreateAlgorithm"); + if (!mHasKey) + throw InvalidKeyException("no key available", "BlockCipherKey::CreateAlgorithm"); + bool padding = (mMode == "CBC" || mMode == "ECB") && mPadding == "PKCS5"; + return new BlockCipherAlgorithm(EvpCipherName(Info(), mMode, mRawKey.size()), + mRawKey, iv, explicitIV, Mode == ENCRYPT, padding); + } + + std::string mCipher; + std::string mMode; + std::string mPadding; + std::string mDerivator; + std::string mHash; + int mKeySize; + Blob mRawKey; + mutable Blob mIV; + bool mHasKey; + mutable bool mHasIV; + }; + + IKey *NewBlockCipherKey() { return new BlockCipherKey(); } + } // namespace + + IKey *CreateBlockCipherKey() { return NewBlockCipherKey(); } + } // namespace detail +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/Date.cpp b/port/thirdparty/cvact_compat/src/Date.cpp new file mode 100644 index 000000000..0de93bea1 --- /dev/null +++ b/port/thirdparty/cvact_compat/src/Date.cpp @@ -0,0 +1,311 @@ +#include "actDate.h" + +#include "actBlob.h" +#include "actException.h" + +#include +#include +#include + +namespace act +{ + namespace + { + long long FloorDiv(long long a, long long b) + { + long long q = a / b; + if ((a % b != 0) && ((a < 0) != (b < 0))) + --q; + return q; + } + + int Digits(const unsigned char *p, int n, bool &ok) + { + int v = 0; + for (int i = 0; i < n; ++i) + { + if (p[i] < '0' || p[i] > '9') + ok = false; + v = v * 10 + (p[i] - '0'); + } + return v; + } + } + + Date::Date() : m_day(1), m_month(1), m_year(1970), m_hour(0), m_min(0), m_sec(0), m_ignore_time(false) + { + SetToday(); + } + + Date::Date(int day, int month, int year) + : m_day(day), m_month(month), m_year(year), m_hour(0), m_min(0), m_sec(0), m_ignore_time(false) + { + if (!IsValid()) + throw BadException("invalid date", "Date::Date"); + } + + Date::Date(int day, int month, int year, int hour, int minute, int sec) + : m_day(day), m_month(month), m_year(year), m_hour(hour), m_min(minute), m_sec(sec), m_ignore_time(false) + { + if (!IsValid()) + throw BadException("invalid date", "Date::Date"); + } + + Date::Date(const Blob &der) + : m_day(1), m_month(1), m_year(1970), m_hour(0), m_min(0), m_sec(0), m_ignore_time(false) + { + Decode(der.begin(), der.size()); + } + + Date::Date(const unsigned char *ch, const unsigned int size) + : m_day(1), m_month(1), m_year(1970), m_hour(0), m_min(0), m_sec(0), m_ignore_time(false) + { + Decode(ch, size); + } + + void Date::Decode(const unsigned char *ch, size_t size) + { + if (ch == 0) + throw NullPointerException("null date encoding", "Date::Decode"); + if (size >= 2 && (ch[0] == 0x17 || ch[0] == 0x18) && ch[1] == size - 2) + { + ch += 2; + size -= 2; + } + bool ok = true; + if (size == 13 && ch[12] == 'Z') + { + int yy = Digits(ch, 2, ok); + m_year = yy < 50 ? 2000 + yy : 1900 + yy; + ch += 2; + } + else if (size == 15 && ch[14] == 'Z') + { + m_year = Digits(ch, 4, ok); + ch += 4; + } + else + throw ASN1Exception("unsupported time encoding", "Date::Decode"); + m_month = Digits(ch, 2, ok); + m_day = Digits(ch + 2, 2, ok); + m_hour = Digits(ch + 4, 2, ok); + m_min = Digits(ch + 6, 2, ok); + m_sec = Digits(ch + 8, 2, ok); + if (!ok || !IsValid()) + throw ASN1Exception("invalid time encoding", "Date::Decode"); + } + + Date &Date::SetToday() + { + std::time_t now = std::time(0); + struct tm t; +#if defined(_WIN32) + gmtime_s(&t, &now); +#else + gmtime_r(&now, &t); +#endif + copytmDate(t, *this); + return *this; + } + + void Date::IgnoreTime(bool b) + { + m_ignore_time = b; + } + + const Date &Date::operator=(const Date &other) + { + m_day = other.m_day; + m_month = other.m_month; + m_year = other.m_year; + m_hour = other.m_hour; + m_min = other.m_min; + m_sec = other.m_sec; + m_ignore_time = other.m_ignore_time; + return *this; + } + + int Date::Compare(const Date &other) const + { + long a = GetJulian(); + long b = other.GetJulian(); + if (a != b) + return a < b ? -1 : 1; + if (m_ignore_time || other.m_ignore_time) + return 0; + long sa = m_hour * 3600L + m_min * 60L + m_sec; + long sb = other.m_hour * 3600L + other.m_min * 60L + other.m_sec; + return sa < sb ? -1 : (sa > sb ? 1 : 0); + } + + bool Date::operator>(const Date &d) const { return Compare(d) > 0; } + bool Date::operator>=(const Date &d) const { return Compare(d) >= 0; } + bool Date::operator<(const Date &d) const { return Compare(d) < 0; } + bool Date::operator<=(const Date &d) const { return Compare(d) <= 0; } + bool Date::operator==(const Date &d) const { return Compare(d) == 0; } + bool Date::operator!=(const Date &d) const { return Compare(d) != 0; } + + const Date &Date::AddMonths(int m) + { + long long total = static_cast(m_year) * 12 + (m_month - 1) + m; + m_year = static_cast(FloorDiv(total, 12)); + m_month = static_cast(total - static_cast(m_year) * 12) + 1; + AdjustDays(); + return *this; + } + + const Date &Date::SubMonths(int m) { return AddMonths(-m); } + const Date &Date::AddYears(int y) { m_year += y; AdjustDays(); return *this; } + const Date &Date::SubYears(int y) { return AddYears(-y); } + const Date &Date::AddDays(int d) { SetFromSeconds(SecondsSinceEpochDay() + 86400LL * d); return *this; } + const Date &Date::SubDays(int d) { return AddDays(-d); } + const Date &Date::AddHours(int h) { SetFromSeconds(SecondsSinceEpochDay() + 3600LL * h); return *this; } + const Date &Date::SubHours(int h) { return AddHours(-h); } + const Date &Date::AddMinutes(int m) { SetFromSeconds(SecondsSinceEpochDay() + 60LL * m); return *this; } + const Date &Date::SubMinutes(int m) { return AddMinutes(-m); } + const Date &Date::AddSecond(int m) { SetFromSeconds(SecondsSinceEpochDay() + m); return *this; } + const Date &Date::SubSecond(int m) { return AddSecond(-m); } + + int Date::DayOfWeek() const + { + return static_cast((GetJulian() + 1) % 7); + } + + int Date::IsLeap(int y) const + { + return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 ? 1 : 0; + } + + int Date::DaysPerMonth(int m, int y) const + { + static const int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (m < 1 || m > 12) + return 0; + return m == 2 ? 28 + IsLeap(y) : days[m - 1]; + } + + long Date::GetDifference(const Date &d2) const + { + return GetJulian() - d2.GetJulian(); + } + + long Date::GetJulian() const + { + return GetJulian(m_day, m_month, m_year); + } + + long Date::GetJulian(int d, int m, int y) const + { + long a = (14 - m) / 12; + long yy = y + 4800L - a; + long mm = m + 12L * a - 3; + return d + (153 * mm + 2) / 5 + 365 * yy + yy / 4 - yy / 100 + yy / 400 - 32045; + } + + void Date::ConvertFromJulian(long jd, int &d, int &m, int &y) + { + long a = jd + 32044; + long b = (4 * a + 3) / 146097; + long c = a - 146097 * b / 4; + long dd = (4 * c + 3) / 1461; + long e = c - 1461 * dd / 4; + long mm = (5 * e + 2) / 153; + d = static_cast(e - (153 * mm + 2) / 5 + 1); + m = static_cast(mm + 3 - 12 * (mm / 10)); + y = static_cast(100 * b + dd - 4800 + mm / 10); + } + + long long Date::SecondsSinceEpochDay() const + { + return static_cast(GetJulian()) * 86400LL + m_hour * 3600LL + m_min * 60LL + m_sec; + } + + void Date::SetFromSeconds(long long s) + { + long long days = FloorDiv(s, 86400); + long long rest = s - days * 86400; + ConvertFromJulian(static_cast(days), m_day, m_month, m_year); + m_hour = static_cast(rest / 3600); + m_min = static_cast((rest / 60) % 60); + m_sec = static_cast(rest % 60); + } + + Blob Date::Encode() const + { + if (m_year < 1950 || m_year >= 2050) + return EncodeToGeneralizedTime(); + char buf[16]; + std::snprintf(buf, sizeof(buf), "%02d%02d%02d%02d%02d%02dZ", + m_year % 100, m_month, m_day, m_hour, m_min, m_sec); + Blob out; + out.push_back(0x17); + out.push_back(static_cast(std::strlen(buf))); + out.insert(out.end(), buf, buf + std::strlen(buf)); + return out; + } + + Blob Date::EncodeToGeneralizedTime() const + { + char buf[20]; + std::snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", + m_year, m_month, m_day, m_hour, m_min, m_sec); + Blob out; + out.push_back(0x18); + out.push_back(static_cast(std::strlen(buf))); + out.insert(out.end(), buf, buf + std::strlen(buf)); + return out; + } + + Date::operator Blob() const + { + return Encode(); + } + + int Date::GetDayFromWeekDay(int weekday, int year, int month, int which) + { + int first = static_cast((GetJulian(1, month, year) + 1) % 7); + int day = 1 + ((weekday - first) % 7 + 7) % 7; + int last = DaysPerMonth(month, year); + day += 7 * (which > 0 ? which - 1 : 0); + while (day > last) + day -= 7; + return day; + } + + bool Date::IsValid() const + { + return m_month >= 1 && m_month <= 12 && m_day >= 1 && m_day <= DaysPerMonth(m_month, m_year) + && m_hour >= 0 && m_hour <= 23 && m_min >= 0 && m_min <= 59 && m_sec >= 0 && m_sec <= 59; + } + + void Date::AdjustDays() + { + int last = DaysPerMonth(m_month, m_year); + if (m_day > last) + m_day = last; + } + + void Date::copyDatetm(act::Date a, struct tm &b) + { + std::memset(&b, 0, sizeof(b)); + b.tm_year = a.m_year - 1900; + b.tm_mon = a.m_month - 1; + b.tm_mday = a.m_day; + b.tm_hour = a.m_hour; + b.tm_min = a.m_min; + b.tm_sec = a.m_sec; + b.tm_wday = a.DayOfWeek(); + b.tm_yday = static_cast(a.GetJulian() - a.GetJulian(1, 1, a.m_year)); + b.tm_isdst = 0; + } + + void Date::copytmDate(struct tm a, act::Date &b) + { + b.m_year = a.tm_year + 1900; + b.m_month = a.tm_mon + 1; + b.m_day = a.tm_mday; + b.m_hour = a.tm_hour; + b.m_min = a.tm_min; + b.m_sec = a.tm_sec > 59 ? 59 : a.tm_sec; + } +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/IESKey.cpp b/port/thirdparty/cvact_compat/src/IESKey.cpp new file mode 100644 index 000000000..83b2feb7b --- /dev/null +++ b/port/thirdparty/cvact_compat/src/IESKey.cpp @@ -0,0 +1,846 @@ +// "IES" key: EC-IES over prime curves (agreement ECDH, MAC HashMAC). +// +// Ciphertext = R || C || T with +// R ephemeral (sender) public key, uncompressed X9.62 point 04 || X || Y +// Z x-coordinate of d * Q (classic ECDH, no cofactor multiplication), field length +// K = ANSI X9.63 KDF with SHA-1 over (R || Z), SharedInfo = SHAREDDATA_1, +// length |M| + 20; K = EK (|M| bytes) || MK (20 bytes) +// C = M xor EK +// T = HMAC-SHA1(MK, C || SHAREDDATA_2), 20 bytes +// Public keys are exported as DER SubjectPublicKeyInfo (id-ecPublicKey, named curve), +// private keys as DER ECPrivateKey (RFC 5915). +#include "actInternal.h" + +#include +#include +#include + +#include +#include + +namespace act +{ + namespace detail + { + namespace + { + const char *const kKdfHash = "SHA1"; + const char *const kMacHash = "SHA1"; + const size_t kMacKeyLen = 20; + const size_t kTagLen = 20; + + struct CurveDef + { + int id; + int nid; + const char *p, *a, *b, *gx, *gy, *n; + }; + + // Explicit parameters are a fallback for OpenSSL builds without these named + // curves; they match the curve definitions in CrypTool's libec. + const CurveDef kCurves[] = { + {SECGp160r1, NID_secp160r1, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "4A96B5688EF573284664698968C38BB913CBFC82", + "23A628553168947D59DCC912042351377AC5FB32", + "100000000000000000001F4C8F927AED3CA752257"}, + {SECGp160r2, NID_secp160r2, 0, 0, 0, 0, 0, 0}, + {SECGp160k1, NID_secp160k1, 0, 0, 0, 0, 0, 0}, + {ANSIp192r1, NID_X9_62_prime192v1, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"}, + {ANSIp192r2, NID_X9_62_prime192v2, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", + "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", + "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", + "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31"}, + {ANSIp192r3, NID_X9_62_prime192v3, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", + "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", + "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", + "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13"}, + {NISTp192r1, NID_X9_62_prime192v1, 0, 0, 0, 0, 0, 0}, + {SECGp192r1, NID_X9_62_prime192v1, 0, 0, 0, 0, 0, 0}, + {SECGp192k1, NID_secp192k1, 0, 0, 0, 0, 0, 0}, + {NISTp224r1, NID_secp224r1, 0, 0, 0, 0, 0, 0}, + {SECGp224r1, NID_secp224r1, 0, 0, 0, 0, 0, 0}, + {SECGp224k1, NID_secp224k1, 0, 0, 0, 0, 0, 0}, + {ANSIp239r1, NID_X9_62_prime239v1, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", + "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", + "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B"}, + {ANSIp239r2, NID_X9_62_prime239v2, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", + "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", + "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", + "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063"}, + {ANSIp239r3, NID_X9_62_prime239v3, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", + "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", + "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551"}, + {ANSIp256r1, NID_X9_62_prime256v1, + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"}, + {NISTp256r1, NID_X9_62_prime256v1, 0, 0, 0, 0, 0, 0}, + {SECGp256r1, NID_X9_62_prime256v1, 0, 0, 0, 0, 0, 0}, + {SECGp256k1, NID_secp256k1, 0, 0, 0, 0, 0, 0}, + {NISTp384r1, NID_secp384r1, 0, 0, 0, 0, 0, 0}, + {NISTp521r1, NID_secp521r1, 0, 0, 0, 0, 0, 0}, + }; + + const CurveDef *FindCurve(int id) + { + for (size_t i = 0; i < sizeof(kCurves) / sizeof(kCurves[0]); ++i) + if (kCurves[i].id == id) + return &kCurves[i]; + return 0; + } + + BnPtr HexBn(const char *hex) + { + BIGNUM *bn = 0; + if (!BN_hex2bn(&bn, hex)) + throw BadAllocException("BN_hex2bn failed", "IESKey"); + return BnPtr(bn); + } + + GroupPtr ExplicitGroup(const CurveDef &def) + { + BnCtxPtr ctx = NewBnCtx(); + BnPtr p = HexBn(def.p), a = HexBn(def.a), b = HexBn(def.b); + BnPtr gx = HexBn(def.gx), gy = HexBn(def.gy), n = HexBn(def.n); + BnPtr h = NewBn(); + BN_one(h.get()); + GroupPtr group(EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get())); + if (!group) + return GroupPtr(); + PointPtr g(EC_POINT_new(group.get())); + if (!g || EC_POINT_set_affine_coordinates(group.get(), g.get(), gx.get(), gy.get(), ctx.get()) != 1 + || EC_GROUP_set_generator(group.get(), g.get(), n.get(), h.get()) != 1) + return GroupPtr(); + EC_GROUP_set_curve_name(group.get(), def.nid); + return group; + } + + // Group for a curve id; ExplicitGroup() is used when preferExplicit is set or + // the named curve is not built into the OpenSSL library. + GroupPtr MakeGroup(const CurveDef &def, bool preferExplicit = false) + { + GroupPtr group; + if (!preferExplicit) + group.reset(EC_GROUP_new_by_curve_name(def.nid)); + if (!group && def.p != 0) + group = ExplicitGroup(def); + if (!group) + throw NoSuchAlgorithmException("elliptic curve not available", "IESKey"); + return group; + } + + Blob CurveOidTlv(int nid) + { + ASN1_OBJECT *obj = OBJ_nid2obj(nid); + int len = obj != 0 ? i2d_ASN1_OBJECT(obj, 0) : 0; + if (len <= 0) + throw NoSuchAlgorithmException("unknown curve OID", "IESKey"); + Blob out(static_cast(len)); + unsigned char *p = out.begin(); + i2d_ASN1_OBJECT(obj, &p); + return out; + } + + const byte kEcPublicKeyOid[] = {0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01}; + + size_t FieldLen(const EC_GROUP *group) + { + return static_cast((EC_GROUP_get_degree(group) + 7) / 8); + } + + Blob PointToOctets(const EC_GROUP *group, const EC_POINT *pt, BN_CTX *ctx) + { + size_t len = EC_POINT_point2oct(group, pt, POINT_CONVERSION_UNCOMPRESSED, 0, 0, ctx); + if (len == 0) + throw InvalidKeyException("invalid point", "IESKey"); + Blob out(len); + EC_POINT_point2oct(group, pt, POINT_CONVERSION_UNCOMPRESSED, out.begin(), len, ctx); + return out; + } + + PointPtr OctetsToPoint(const EC_GROUP *group, const byte *data, size_t len, BN_CTX *ctx) + { + PointPtr pt(EC_POINT_new(group)); + if (!pt || len == 0 || EC_POINT_oct2point(group, pt.get(), data, len, ctx) != 1 + || EC_POINT_is_at_infinity(group, pt.get()) || EC_POINT_is_on_curve(group, pt.get(), ctx) != 1) + return PointPtr(); + return pt; + } + + // Length of the encoded point at the start of data, 0 if not a point encoding. + size_t EncodedPointLen(const EC_GROUP *group, const byte *data, size_t len) + { + if (len == 0) + return 0; + size_t flen = FieldLen(group); + if (data[0] == 0x04) + return 1 + 2 * flen; + if (data[0] == 0x02 || data[0] == 0x03) + return 1 + flen; + return 0; + } + + Blob SharedSecret(const EC_GROUP *group, const BIGNUM *d, const EC_POINT *q, BN_CTX *ctx) + { + PointPtr s(EC_POINT_new(group)); + BnPtr x = NewBn(); + if (!s || EC_POINT_mul(group, s.get(), 0, q, d, ctx) != 1 || EC_POINT_is_at_infinity(group, s.get()) + || EC_POINT_get_affine_coordinates(group, s.get(), x.get(), 0, ctx) != 1) + throw InvalidKeyException("ECDH computation failed", "IESKey"); + return BnToPadded(x.get(), FieldLen(group)); + } + + void XorKdfStream(Blob &data, const Blob &key) + { + for (size_t i = 0; i < data.size(); ++i) + data[i] ^= key[i]; + } + + class IESEncrypt : public BufferedAlgorithm + { + public: + IESEncrypt(GroupPtr group, BnPtr ephemeralPriv, const Blob &ephemeralPub, PointPtr recipient, + const Blob &shared1, const Blob &shared2) + : mGroup(std::move(group)), mPriv(std::move(ephemeralPriv)), mR(ephemeralPub), + mRecipient(std::move(recipient)), mShared1(shared1), mShared2(shared2) {} + + void Write(const Blob &input) { mIn.append(input); } + void Write(const byte *input, size_t insize) { mIn.insert(mIn.end(), input, input + insize); } + + void Finalize() + { + if (mStatus == IS_FINALIZED) + return; + BnCtxPtr ctx = NewBnCtx(); + Blob kdfIn(mR); + kdfIn.append(SharedSecret(mGroup.get(), mPriv.get(), mRecipient.get(), ctx.get())); + Blob k = X963Kdf(kKdfHash, kdfIn, mShared1, mIn.size() + kMacKeyLen); + Blob c(mIn); + XorKdfStream(c, k); + Blob mk(k.begin() + mIn.size(), k.end()); + Blob macIn(c); + macIn.append(mShared2); + Blob tag = Hmac(kMacHash, mk, macIn); + mOut.append(mR); + mOut.append(c); + mOut.insert(mOut.end(), tag.begin(), tag.begin() + kTagLen); + mIn.clear(); + mStatus = IS_FINALIZED; + } + + private: + GroupPtr mGroup; + BnPtr mPriv; + Blob mR; + PointPtr mRecipient; + Blob mShared1, mShared2; + Blob mIn; + }; + + class IESDecrypt : public BufferedAlgorithm + { + public: + IESDecrypt(GroupPtr group, BnPtr priv, const Blob &shared1, const Blob &shared2) + : mGroup(std::move(group)), mPriv(std::move(priv)), mShared1(shared1), mShared2(shared2) {} + + void Write(const Blob &input) { mIn.append(input); } + void Write(const byte *input, size_t insize) { mIn.insert(mIn.end(), input, input + insize); } + + void Finalize() + { + if (mStatus == IS_FINALIZED) + return; + mStatus = DECRYPT_ERROR; + BnCtxPtr ctx = NewBnCtx(); + size_t rlen = EncodedPointLen(mGroup.get(), mIn.begin(), mIn.size()); + if (rlen == 0 || mIn.size() < rlen + kTagLen) + throw InvalidAlgorithmParameterException("invalid ECIES ciphertext", "IESDecrypt::Finalize"); + PointPtr r = OctetsToPoint(mGroup.get(), mIn.begin(), rlen, ctx.get()); + if (!r) + throw InvalidAlgorithmParameterException("invalid ephemeral public key", "IESDecrypt::Finalize"); + size_t clen = mIn.size() - rlen - kTagLen; + Blob kdfIn(mIn.begin(), mIn.begin() + rlen); + kdfIn.append(SharedSecret(mGroup.get(), mPriv.get(), r.get(), ctx.get())); + Blob k = X963Kdf(kKdfHash, kdfIn, mShared1, clen + kMacKeyLen); + Blob c(mIn.begin() + rlen, mIn.begin() + rlen + clen); + Blob mk(k.begin() + clen, k.end()); + Blob macIn(c); + macIn.append(mShared2); + Blob tag = Hmac(kMacHash, mk, macIn); + if (CRYPTO_memcmp(tag.begin(), mIn.begin() + rlen + clen, kTagLen) != 0) + throw AlgorithmException("ECIES MAC verification failed (wrong key or corrupted data)", + "IESDecrypt::Finalize"); + XorKdfStream(c, k); + mOut.append(c); + mIn.clear(); + mStatus = IS_FINALIZED; + } + + private: + GroupPtr mGroup; + BnPtr mPriv; + Blob mShared1, mShared2; + Blob mIn; + }; + + IKey *NewIESKey(); + + class IESKey : public IKey + { + public: + IESKey() : mCurve(SECGp160r1), mNewEphemeral(0) {} + + IESKey(const IESKey &o) + : mCurve(o.mCurve), mShared1(o.mShared1), mShared2(o.mShared2), mNewEphemeral(o.mNewEphemeral) + { + if (o.mGroup) + mGroup.reset(EC_GROUP_dup(o.mGroup.get())); + if (o.mPriv) + mPriv.reset(BN_dup(o.mPriv.get())); + if (o.mPub) + mPub.reset(EC_POINT_dup(o.mPub.get(), mGroup.get())); + if (o.mPendingX) + mPendingX.reset(BN_dup(o.mPendingX.get())); + if (o.mPendingY) + mPendingY.reset(BN_dup(o.mPendingY.get())); + } + + IKey *Clone() const { return new IESKey(*this); } + + void Import(const Blob &keyblob) + { + const byte *buf = keyblob.begin(); + size_t size = keyblob.size(), pos = 0; + DerItem top; + if (!DerRead(buf, size, pos, top)) + throw InvalidKeyException("invalid key blob", "IESKey::Import"); + if (top.tag == 0x06) + { + SetCurve(CurveFromOid(buf, size)); + return; + } + if (top.tag != 0x30) + throw InvalidKeyException("invalid key blob", "IESKey::Import"); + size_t ipos = 0; + DerItem first; + if (!DerRead(top.data, top.len, ipos, first)) + throw InvalidKeyException("invalid key blob", "IESKey::Import"); + if (first.tag == 0x30) + ImportSpki(top, first, ipos); + else if (first.tag == 0x02) + ImportEcPrivateKey(top, ipos); + else + throw InvalidKeyException("invalid key blob", "IESKey::Import"); + } + + void Export(Blob &keyblob, export_t type) const + { + keyblob.clear(); + switch (type) + { + case PUBLIC: + keyblob = Spki(); + break; + case DEFAULT: + case PRIVATE: + keyblob = EcPrivateKey(); + break; + case DOMAINPARAMS: + keyblob = CurveOidTlv(FindCurve(mCurve)->nid); + break; + default: + throw InvalidKeyException("unsupported export type", "IESKey::Export"); + } + } + + void SetParam(paramid_t id, const Blob &blob) + { + switch (id) + { + case PRIVATEKEY: + SetPrivate(BlobToBn(blob)); + break; + case PUBLIC_X: + mPendingX = BlobToBn(blob); + TryBuildPublic(); + break; + case PUBLIC_Y: + mPendingY = BlobToBn(blob); + TryBuildPublic(); + break; + case PUBLICKEY: + { + BnCtxPtr ctx = NewBnCtx(); + PointPtr pt = OctetsToPoint(Group(), blob.begin(), blob.size(), ctx.get()); + if (!pt) + throw InvalidKeyException("point not on curve", "IESKey::SetParam"); + mPriv.reset(); + mPub = std::move(pt); + break; + } + case SHAREDDATA_1: + mShared1 = blob; + break; + case SHAREDDATA_2: + mShared2 = blob; + break; + default: + throw InvalidKeyException("unsupported parameter", "IESKey::SetParam"); + } + } + + void SetParam(paramid_t id, int val) + { + switch (id) + { + case CURVE: + SetCurve(val); + break; + case NEWEPHEMERAL: + mNewEphemeral = val; + break; + case COMPATIBLE: + if (val == 0) + throw InvalidKeyException("cofactor ECDH not supported", "IESKey::SetParam"); + break; + default: + throw InvalidKeyException("unsupported parameter", "IESKey::SetParam"); + } + } + + void SetParam(paramid_t id, const char *cstr) + { + if (cstr == 0) + throw NullPointerException("null parameter", "IESKey::SetParam"); + switch (id) + { + case PRIVATEKEY: + case PUBLIC_X: + case PUBLIC_Y: + { + BnPtr bn = ParseNumber(cstr); + if (!bn || BN_is_negative(bn.get())) + throw InvalidKeyException("invalid number", "IESKey::SetParam"); + if (id == PRIVATEKEY) + SetPrivate(std::move(bn)); + else + { + (id == PUBLIC_X ? mPendingX : mPendingY) = std::move(bn); + TryBuildPublic(); + } + break; + } + case AGREEMENT: + if (std::strcmp(cstr, "ECDH") != 0) + throw NoSuchAlgorithmException("unsupported agreement", "IESKey::SetParam"); + break; + case MAC: + if (std::strcmp(cstr, "HashMAC") != 0) + throw NoSuchAlgorithmException("unsupported MAC", "IESKey::SetParam"); + break; + default: + throw InvalidKeyException("unsupported parameter", "IESKey::SetParam"); + } + } + + int GetParam(paramid_t id) const + { + switch (id) + { + case CURVE: + return mCurve; + case NEWEPHEMERAL: + return mNewEphemeral; + case COMPATIBLE: + return 1; + case KEYSIZE: + return EC_GROUP_get_degree(Group()); + default: + throw InvalidKeyException("unsupported parameter", "IESKey::GetParam"); + } + } + + void GetParam(paramid_t id, Blob &blob) const + { + switch (id) + { + case PRIVATEKEY: + if (!mPriv) + throw InvalidKeyException("no private key", "IESKey::GetParam"); + blob = BnToTwosComplement(mPriv.get()); + break; + case PUBLIC_X: + case PUBLIC_Y: + { + if (!mPub) + throw InvalidKeyException("no public key", "IESKey::GetParam"); + BnCtxPtr ctx = NewBnCtx(); + BnPtr x = NewBn(), y = NewBn(); + EC_POINT_get_affine_coordinates(Group(), mPub.get(), x.get(), y.get(), ctx.get()); + blob = BnToTwosComplement(id == PUBLIC_X ? x.get() : y.get()); + break; + } + case PUBLICKEY: + { + if (!mPub) + throw InvalidKeyException("no public key", "IESKey::GetParam"); + BnCtxPtr ctx = NewBnCtx(); + blob = PointToOctets(Group(), mPub.get(), ctx.get()); + break; + } + case SHAREDDATA_1: blob = mShared1; break; + case SHAREDDATA_2: blob = mShared2; break; + case AGREEMENT: blob = Blob("ECDH"); break; + case MAC: blob = Blob("HashMAC"); break; + default: + throw InvalidKeyException("unsupported parameter", "IESKey::GetParam"); + } + } + + void Generate(IRNGAlg *prng) + { + BnPtr d = RandomScalar(Group(), prng); + SetPrivate(std::move(d)); + } + + void Derive(const Blob &, const Blob &) + { + throw NotImplementedException("Derive is not supported by IES keys", "IESKey::Derive"); + } + + IAlgorithm *CreateAlgorithm(mode_t Mode) const + { + if (Mode == DECRYPT) + return CreateDecrypt(); + if (Mode == ENCRYPT) + { + if (!mPub) + throw InvalidKeyException("no public key", "IESKey::CreateAlgorithm"); + return CreateEncrypt(PointPtr(EC_POINT_dup(mPub.get(), Group())), true); + } + throw InvalidAlgorithmParameterException("unsupported mode", "IESKey::CreateAlgorithm"); + } + + IAlgorithm *CreateAlgorithm(mode_t Mode, const Blob &data) const + { + if (Mode == DECRYPT) + return CreateDecrypt(); + if (Mode != ENCRYPT) + throw InvalidAlgorithmParameterException("unsupported mode", "IESKey::CreateAlgorithm"); + return CreateEncrypt(ParsePeerPublicKey(data), mNewEphemeral != 0 || !mPriv); + } + + void *GetCreatePointer() const { return reinterpret_cast(&NewIESKey); } + + private: + EC_GROUP *Group() const + { + if (!mGroup) + mGroup = MakeGroup(*FindCurve(mCurve)); + return mGroup.get(); + } + + void SetCurve(int id) + { + const CurveDef *def = FindCurve(id); + if (def == 0) + throw NoSuchAlgorithmException("unsupported curve", "IESKey::SetParam"); + GroupPtr group = MakeGroup(*def); + mCurve = id; + mGroup = std::move(group); + mPriv.reset(); + mPub.reset(); + mPendingX.reset(); + mPendingY.reset(); + } + + int CurveFromOid(const byte *tlv, size_t len) const + { + for (size_t i = 0; i < sizeof(kCurves) / sizeof(kCurves[0]); ++i) + { + Blob oid = CurveOidTlv(kCurves[i].nid); + if (oid.size() == len && std::memcmp(oid.begin(), tlv, len) == 0) + return kCurves[i].id; + } + throw NoSuchAlgorithmException("unsupported curve", "IESKey::Import"); + } + + void SetPrivate(BnPtr d) + { + const BIGNUM *order = EC_GROUP_get0_order(Group()); + if (BN_is_zero(d.get()) || BN_is_negative(d.get()) || BN_cmp(d.get(), order) >= 0) + throw InvalidKeyException("private key out of range", "IESKey::SetParam"); + BnCtxPtr ctx = NewBnCtx(); + PointPtr pub(EC_POINT_new(Group())); + if (!pub || EC_POINT_mul(Group(), pub.get(), d.get(), 0, 0, ctx.get()) != 1) + throw InvalidKeyException("public key computation failed", "IESKey::SetParam"); + mPriv = std::move(d); + mPub = std::move(pub); + mPendingX.reset(); + mPendingY.reset(); + } + + void TryBuildPublic() + { + if (!mPendingX || !mPendingY) + return; + BnCtxPtr ctx = NewBnCtx(); + BnPtr p = NewBn(); + EC_GROUP_get_curve(Group(), p.get(), 0, 0, ctx.get()); + PointPtr pt(EC_POINT_new(Group())); + if (BN_is_negative(mPendingX.get()) || BN_is_negative(mPendingY.get()) + || BN_cmp(mPendingX.get(), p.get()) >= 0 || BN_cmp(mPendingY.get(), p.get()) >= 0 || !pt + || EC_POINT_set_affine_coordinates(Group(), pt.get(), mPendingX.get(), mPendingY.get(), ctx.get()) != 1 + || EC_POINT_is_on_curve(Group(), pt.get(), ctx.get()) != 1) + { + mPendingY.reset(); + throw InvalidKeyException("point not on curve", "IESKey::SetParam"); + } + mPriv.reset(); + mPub = std::move(pt); + } + + static BnPtr RandomScalar(const EC_GROUP *group, IRNGAlg *prng) + { + const BIGNUM *order = EC_GROUP_get0_order(group); + BnPtr range(BN_dup(order)); + BnPtr d = NewBn(); + if (!range || !BN_sub_word(range.get(), 1)) + throw BadAllocException("BN failure", "IESKey::Generate"); + if (prng == 0) + { + if (BN_priv_rand_range(d.get(), range.get()) != 1) + throw RuntimeException("random generation failed", "IESKey::Generate"); + } + else + { + Blob bytes(static_cast(BN_num_bytes(order)) + 8); + RandomBytes(bytes.begin(), bytes.size(), prng); + BnPtr r = BlobToBn(bytes); + BnCtxPtr ctx = NewBnCtx(); + BN_mod(d.get(), r.get(), range.get(), ctx.get()); + } + BN_add_word(d.get(), 1); + return d; + } + + PointPtr ParsePeerPublicKey(const Blob &data) const + { + BnCtxPtr ctx = NewBnCtx(); + size_t rlen = EncodedPointLen(Group(), data.begin(), data.size()); + if (rlen != 0 && rlen == data.size()) + { + PointPtr pt = OctetsToPoint(Group(), data.begin(), data.size(), ctx.get()); + if (!pt) + throw InvalidKeyException("peer public key not on curve", "IESKey::CreateAlgorithm"); + return pt; + } + IESKey peer; + peer.Import(data); + if (!peer.mPub) + throw InvalidAlgorithmParameterException("no peer public key", "IESKey::CreateAlgorithm"); + if (EC_GROUP_cmp(Group(), peer.Group(), ctx.get()) != 0) + throw InvalidAlgorithmParameterException("peer key uses a different curve", "IESKey::CreateAlgorithm"); + Blob oct = PointToOctets(peer.Group(), peer.mPub.get(), ctx.get()); + PointPtr pt = OctetsToPoint(Group(), oct.begin(), oct.size(), ctx.get()); + if (!pt) + throw InvalidKeyException("peer public key not on curve", "IESKey::CreateAlgorithm"); + return pt; + } + + IAlgorithm *CreateEncrypt(PointPtr recipient, bool newEphemeral) const + { + if (!recipient) + throw InvalidKeyException("invalid recipient key", "IESKey::CreateAlgorithm"); + BnCtxPtr ctx = NewBnCtx(); + BnPtr d; + PointPtr pub; + if (newEphemeral) + { + d = RandomScalar(Group(), 0); + pub.reset(EC_POINT_new(Group())); + if (!pub || EC_POINT_mul(Group(), pub.get(), d.get(), 0, 0, ctx.get()) != 1) + throw InvalidKeyException("ephemeral key generation failed", "IESKey::CreateAlgorithm"); + } + else + { + d.reset(BN_dup(mPriv.get())); + pub.reset(EC_POINT_dup(mPub.get(), Group())); + } + Blob r = PointToOctets(Group(), pub.get(), ctx.get()); + return new IESEncrypt(GroupPtr(EC_GROUP_dup(Group())), std::move(d), r, std::move(recipient), + mShared1, mShared2); + } + + IAlgorithm *CreateDecrypt() const + { + if (!mPriv) + throw InvalidKeyException("no private key", "IESKey::CreateAlgorithm"); + return new IESDecrypt(GroupPtr(EC_GROUP_dup(Group())), BnPtr(BN_dup(mPriv.get())), mShared1, mShared2); + } + + Blob Spki() const + { + if (!mPub) + throw InvalidKeyException("no public key", "IESKey::Export"); + BnCtxPtr ctx = NewBnCtx(); + Blob alg(kEcPublicKeyOid, kEcPublicKeyOid + sizeof(kEcPublicKeyOid)); + alg.append(CurveOidTlv(FindCurve(mCurve)->nid)); + Blob bits(1, 0); + bits.append(PointToOctets(Group(), mPub.get(), ctx.get())); + Blob content; + DerAppend(content, 0x30, alg); + DerAppend(content, 0x03, bits); + Blob out; + DerAppend(out, 0x30, content); + return out; + } + + Blob EcPrivateKey() const + { + if (!mPriv) + throw InvalidKeyException("no private key", "IESKey::Export"); + BnCtxPtr ctx = NewBnCtx(); + const BIGNUM *order = EC_GROUP_get0_order(Group()); + Blob content; + const byte version[] = {0x01}; + DerAppend(content, 0x02, version, 1); + DerAppend(content, 0x04, BnToPadded(mPriv.get(), static_cast(BN_num_bytes(order)))); + DerAppend(content, 0xA0, CurveOidTlv(FindCurve(mCurve)->nid)); + Blob bits(1, 0); + bits.append(PointToOctets(Group(), mPub.get(), ctx.get())); + Blob bitString; + DerAppend(bitString, 0x03, bits); + DerAppend(content, 0xA1, bitString); + Blob out; + DerAppend(out, 0x30, content); + return out; + } + + void ImportSpki(const DerItem &top, const DerItem &alg, size_t pos) + { + size_t apos = 0; + DerItem algOid, curveOid, bits; + if (!DerRead(alg.data, alg.len, apos, algOid) || algOid.tag != 0x06 + || algOid.len + 2 != sizeof(kEcPublicKeyOid) + || std::memcmp(algOid.data, kEcPublicKeyOid + 2, algOid.len) != 0) + throw InvalidKeyException("not an EC public key", "IESKey::Import"); + size_t oidStart = apos; + if (!DerRead(alg.data, alg.len, apos, curveOid) || curveOid.tag != 0x06) + throw InvalidKeyException("only named curves are supported", "IESKey::Import"); + if (!DerRead(top.data, top.len, pos, bits) || bits.tag != 0x03 || bits.len < 2 || bits.data[0] != 0) + throw InvalidKeyException("invalid public key encoding", "IESKey::Import"); + SetCurve(CurveFromOid(alg.data + oidStart, apos - oidStart)); + SetParam(PUBLICKEY, Blob(bits.data + 1, bits.data + bits.len)); + } + + void ImportEcPrivateKey(const DerItem &top, size_t pos) + { + DerItem key, item; + if (!DerRead(top.data, top.len, pos, key) || key.tag != 0x04) + throw InvalidKeyException("invalid private key encoding", "IESKey::Import"); + bool haveCurve = false; + while (pos < top.len) + { + if (!DerRead(top.data, top.len, pos, item)) + throw InvalidKeyException("invalid private key encoding", "IESKey::Import"); + if (item.tag == 0xA0) + { + SetCurve(CurveFromOid(item.data, item.len)); + haveCurve = true; + } + } + if (!haveCurve) + throw InvalidKeyException("private key without curve", "IESKey::Import"); + SetPrivate(BlobToBn(Blob(key.data, key.data + key.len))); + } + + int mCurve; + mutable GroupPtr mGroup; + BnPtr mPriv; + PointPtr mPub; + BnPtr mPendingX, mPendingY; + Blob mShared1, mShared2; + int mNewEphemeral; + }; + + IKey *NewIESKey() { return new IESKey(); } + } // namespace + + IKey *CreateIESKey() { return NewIESKey(); } + + IKey *ImportECKeyBlob(const Blob &keyblob) + { + IESKey *key = new IESKey(); + try + { + key->Import(keyblob); + } + catch (...) + { + delete key; + throw; + } + return key; + } + + // Test hook: true if the explicit fallback parameters of a curve equal OpenSSL's named curve. + bool CurveFallbackMatches(int id) + { + const CurveDef *def = FindCurve(id); + if (def == 0 || def->p == 0) + return false; + GroupPtr named(EC_GROUP_new_by_curve_name(def->nid)); + if (!named) + return true; + GroupPtr expl = MakeGroup(*def, true); + BnCtxPtr ctx = NewBnCtx(); + BnPtr v[2][7]; + const EC_GROUP *groups[2] = {named.get(), expl.get()}; + for (int g = 0; g < 2; ++g) + { + for (int i = 0; i < 7; ++i) + v[g][i] = NewBn(); + if (EC_GROUP_get_curve(groups[g], v[g][0].get(), v[g][1].get(), v[g][2].get(), ctx.get()) != 1 + || EC_POINT_get_affine_coordinates(groups[g], EC_GROUP_get0_generator(groups[g]), + v[g][3].get(), v[g][4].get(), ctx.get()) != 1 + || !BN_copy(v[g][5].get(), EC_GROUP_get0_order(groups[g])) + || !BN_copy(v[g][6].get(), EC_GROUP_get0_cofactor(groups[g]))) + return false; + } + for (int i = 0; i < 7; ++i) + if (BN_cmp(v[0][i].get(), v[1][i].get()) != 0) + return false; + return true; + } + } // namespace detail +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/Key.cpp b/port/thirdparty/cvact_compat/src/Key.cpp new file mode 100644 index 000000000..ad800bfc2 --- /dev/null +++ b/port/thirdparty/cvact_compat/src/Key.cpp @@ -0,0 +1,97 @@ +#include "actInternal.h" +#include "actKey.h" + +#include + +namespace act +{ + namespace + { + IKey *Checked(IKey *key) + { + if (key == 0) + throw NullPointerException("key object not initialised", "Key"); + return key; + } + } + + Key::Key() : mKey(0) {} + + Key::Key(const Key &key) : mKey(key.mKey != 0 ? key.mKey->Clone() : 0) {} + + Key::Key(IKey *keyptr) : mKey(keyptr) {} + + Key::Key(const Blob &keyblob) : mKey(detail::ImportECKeyBlob(keyblob)) {} + + Key::Key(const char *keytype) : mKey(0) + { + if (keytype == 0) + throw NullPointerException("null key type", "Key::Key"); + if (std::strcmp(keytype, "IES") == 0) + mKey = detail::CreateIESKey(); + else if (std::strcmp(keytype, "BlockCipher") == 0) + mKey = detail::CreateBlockCipherKey(); + else + throw NoSuchAlgorithmException("unsupported key type", "Key::Key"); + } + + Key::~Key() + { + delete mKey; + } + + Key &Key::operator=(const Key &key) + { + if (this != &key) + { + IKey *copy = key.mKey != 0 ? key.mKey->Clone() : 0; + delete mKey; + mKey = copy; + } + return *this; + } + + void Key::Import(const Blob &keyblob) + { + if (mKey == 0) + mKey = detail::ImportECKeyBlob(keyblob); + else + mKey->Import(keyblob); + } + + void Key::Export(Blob &keyblob, export_t type) const { Checked(mKey)->Export(keyblob, type); } + void Key::SetParam(paramid_t id, const Blob &blob) { Checked(mKey)->SetParam(id, blob); } + void Key::SetParam(paramid_t id, int val) { Checked(mKey)->SetParam(id, val); } + void Key::SetParam(paramid_t id, const char *cstr) { Checked(mKey)->SetParam(id, cstr); } + int Key::GetParam(paramid_t id) const { return Checked(mKey)->GetParam(id); } + void Key::GetParam(paramid_t id, Blob &blob) const { Checked(mKey)->GetParam(id, blob); } + + void Key::Generate(IAlgorithm *prng) + { + IRNGAlg *rng = 0; + if (prng != 0) + { + rng = dynamic_cast(prng); + if (rng == 0) + throw InvalidAlgorithmParameterException("not a random number generator", "Key::Generate"); + } + Checked(mKey)->Generate(rng); + } + + void Key::Derive(const Blob &data, const Blob &salt) { Checked(mKey)->Derive(data, salt); } + + IAlgorithm *Key::CreateAlgorithm(mode_t Mode) const { return Checked(mKey)->CreateAlgorithm(Mode); } + IAlgorithm *Key::CreateAlgorithm(mode_t Mode, const Blob &data) const { return Checked(mKey)->CreateAlgorithm(Mode, data); } + + IKey *Key::GetPointer() { return mKey; } + const IKey *Key::GetPointer() const { return mKey; } + Key::operator IKey *() { return mKey; } + Key::operator const IKey *() const { return mKey; } + + IKey *Key::ReleasePointer() + { + IKey *p = mKey; + mKey = 0; + return p; + } +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/Tools.cpp b/port/thirdparty/cvact_compat/src/Tools.cpp new file mode 100644 index 000000000..c24ec8ad8 --- /dev/null +++ b/port/thirdparty/cvact_compat/src/Tools.cpp @@ -0,0 +1,415 @@ +#include "actInternal.h" +#include "actTools.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace act +{ + namespace detail + { + BnPtr NewBn() + { + BnPtr bn(BN_new()); + if (!bn) + throw BadAllocException("BN_new failed", "detail::NewBn"); + return bn; + } + + BnCtxPtr NewBnCtx() + { + BnCtxPtr ctx(BN_CTX_new()); + if (!ctx) + throw BadAllocException("BN_CTX_new failed", "detail::NewBnCtx"); + return ctx; + } + + BnPtr ParseNumber(const char *text) + { + if (text == 0) + return BnPtr(); + std::string s; + for (const char *p = text; *p; ++p) + if (!std::isspace(static_cast(*p))) + s += *p; + bool negative = false; + size_t pos = 0; + if (pos < s.size() && (s[pos] == '-' || s[pos] == '+')) + { + negative = s[pos] == '-'; + ++pos; + } + bool hex = s.size() >= pos + 2 && s[pos] == '0' && (s[pos + 1] == 'x' || s[pos + 1] == 'X'); + if (hex) + pos += 2; + std::string digits = s.substr(pos); + if (digits.empty()) + return BnPtr(); + for (size_t i = 0; i < digits.size(); ++i) + { + unsigned char c = static_cast(digits[i]); + if (hex ? !std::isxdigit(c) : !std::isdigit(c)) + return BnPtr(); + } + BIGNUM *raw = 0; + int n = hex ? BN_hex2bn(&raw, digits.c_str()) : BN_dec2bn(&raw, digits.c_str()); + BnPtr bn(raw); + if (!bn || n != static_cast(digits.size())) + return BnPtr(); + BN_set_negative(bn.get(), negative ? 1 : 0); + return bn; + } + + Blob BnToTwosComplement(const BIGNUM *bn) + { + if (BN_is_zero(bn)) + return Blob(1, 0); + BnPtr mag(BN_dup(bn)); + if (!mag) + throw BadAllocException("BN_dup failed", "detail::BnToTwosComplement"); + BN_set_negative(mag.get(), 0); + int len = BN_num_bytes(mag.get()); + Blob out; + if (!BN_is_negative(bn)) + { + out.resize(static_cast(len)); + BN_bn2bin(mag.get(), &out[0]); + if (out[0] & 0x80) + out.insert(out.begin(), byte(0)); + return out; + } + BnPtr limit = NewBn(); + BN_set_bit(limit.get(), 8 * len - 1); + if (BN_cmp(mag.get(), limit.get()) > 0) + ++len; + BnPtr modulus = NewBn(); + BN_set_bit(modulus.get(), 8 * len); + BnPtr t = NewBn(); + BN_sub(t.get(), modulus.get(), mag.get()); + out.resize(static_cast(len)); + BN_bn2binpad(t.get(), &out[0], len); + return out; + } + + BnPtr BlobToBn(const Blob &b) + { + BnPtr bn(BN_bin2bn(b.empty() ? 0 : &b[0], static_cast(b.size()), 0)); + if (!bn) + throw BadAllocException("BN_bin2bn failed", "detail::BlobToBn"); + return bn; + } + + Blob BnToPadded(const BIGNUM *bn, size_t len) + { + Blob out(len); + if (len != 0 && BN_bn2binpad(bn, &out[0], static_cast(len)) < 0) + throw ArithmeticException("number too large", "detail::BnToPadded"); + return out; + } + + void RandomBytes(byte *out, size_t n, IRNGAlg *prng) + { + if (n == 0) + return; + if (prng != 0) + { + if (prng->Read(out, n) != n) + throw RuntimeException("random generator delivered too few bytes", "detail::RandomBytes"); + return; + } + if (RAND_bytes(out, static_cast(n)) != 1) + throw RuntimeException("RAND_bytes failed", "detail::RandomBytes"); + } + + void DerAppend(Blob &out, byte tag, const byte *content, size_t len) + { + out.push_back(tag); + if (len < 0x80) + out.push_back(static_cast(len)); + else + { + byte tmp[sizeof(size_t)]; + int n = 0; + for (size_t v = len; v != 0; v >>= 8) + tmp[n++] = static_cast(v & 0xff); + out.push_back(static_cast(0x80 | n)); + while (n > 0) + out.push_back(tmp[--n]); + } + out.insert(out.end(), content, content + len); + } + + void DerAppend(Blob &out, byte tag, const Blob &content) + { + DerAppend(out, tag, content.begin(), content.size()); + } + + bool DerRead(const byte *buf, size_t size, size_t &pos, DerItem &item) + { + if (pos + 2 > size) + return false; + item.tag = buf[pos++]; + size_t len = buf[pos++]; + if (len & 0x80) + { + size_t n = len & 0x7f; + if (n == 0 || n > 4 || pos + n > size) + return false; + len = 0; + for (size_t i = 0; i < n; ++i) + len = (len << 8) | buf[pos++]; + } + if (len > size - pos) + return false; + item.data = buf + pos; + item.len = len; + pos += len; + return true; + } + + Blob Digest(const char *name, const Blob &data) + { + unsigned char md[EVP_MAX_MD_SIZE]; + size_t mdlen = 0; + if (!EVP_Q_digest(0, name, 0, data.empty() ? 0 : data.begin(), data.size(), md, &mdlen)) + throw NoSuchAlgorithmException("hash algorithm not available", "detail::Digest"); + Blob out(md, md + mdlen); + SecureZero(md, sizeof(md)); + return out; + } + + Blob X963Kdf(const char *digest, const Blob &secret, const Blob &sharedInfo, size_t len) + { + Blob out(len); + if (len == 0) + return out; + EVP_KDF *kdf = EVP_KDF_fetch(0, "X963KDF", 0); + if (kdf == 0) + throw NoSuchAlgorithmException("X963KDF not available", "detail::X963Kdf"); + EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + if (ctx == 0) + throw BadAllocException("EVP_KDF_CTX_new failed", "detail::X963Kdf"); + OSSL_PARAM params[4]; + int n = 0; + params[n++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast(digest), 0); + params[n++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, + const_cast(secret.begin()), secret.size()); + if (!sharedInfo.empty()) + params[n++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, + const_cast(sharedInfo.begin()), sharedInfo.size()); + params[n] = OSSL_PARAM_construct_end(); + int ok = EVP_KDF_derive(ctx, &out[0], len, params); + EVP_KDF_CTX_free(ctx); + if (ok != 1) + throw AlgorithmException("X9.63 key derivation failed", "detail::X963Kdf"); + return out; + } + + Blob Hmac(const char *digest, const Blob &key, const Blob &data) + { + unsigned char mac[EVP_MAX_MD_SIZE]; + size_t maclen = 0; + static const unsigned char dummy = 0; + if (!EVP_Q_mac(0, "HMAC", 0, digest, 0, key.empty() ? &dummy : key.begin(), key.size(), + data.empty() ? &dummy : data.begin(), data.size(), mac, sizeof(mac), &maclen)) + throw AlgorithmException("HMAC computation failed", "detail::Hmac"); + return Blob(mac, mac + maclen); + } + } // namespace detail + + Blob EncodeOID(const char *oid) + { + if (oid == 0) + throw NullPointerException("null OID", "EncodeOID"); + std::vector arcs; + const char *p = oid; + while (*p) + { + if (!std::isdigit(static_cast(*p))) + throw BadException("invalid OID", "EncodeOID"); + unsigned long long v = 0; + while (std::isdigit(static_cast(*p))) + v = v * 10 + static_cast(*p++ - '0'); + arcs.push_back(v); + if (*p == '.') + { + ++p; + if (*p == 0) + throw BadException("invalid OID", "EncodeOID"); + } + else if (*p != 0) + throw BadException("invalid OID", "EncodeOID"); + } + if (arcs.size() < 2 || arcs[0] > 2 || (arcs[0] < 2 && arcs[1] > 39)) + throw BadException("invalid OID", "EncodeOID"); + std::vector values; + values.push_back(arcs[0] * 40 + arcs[1]); + values.insert(values.end(), arcs.begin() + 2, arcs.end()); + Blob out; + for (size_t i = 0; i < values.size(); ++i) + { + byte tmp[10]; + int n = 0; + unsigned long long v = values[i]; + do + { + tmp[n++] = static_cast(v & 0x7f); + v >>= 7; + } while (v != 0); + while (n > 0) + { + --n; + out.push_back(static_cast(tmp[n] | (n != 0 ? 0x80 : 0))); + } + } + return out; + } + + Blob EncodeNumber(const char *number) + { + detail::BnPtr bn = detail::ParseNumber(number); + if (!bn) + throw BadException("invalid number", "EncodeNumber"); + return detail::BnToTwosComplement(bn.get()); + } + + Blob EncodeNumber(int number) + { + return EncodeNumber(std::to_string(number).c_str()); + } + + Blob hex2blob(const char *hexnumber) + { + if (hexnumber == 0) + throw NullPointerException("null string", "hex2blob"); + std::string digits; + const char *p = hexnumber; + while (std::isspace(static_cast(*p))) + ++p; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + p += 2; + for (; *p; ++p) + { + unsigned char c = static_cast(*p); + if (std::isspace(c)) + continue; + if (!std::isxdigit(c)) + throw BadException("invalid hexadecimal digit", "hex2blob"); + digits += static_cast(c); + } + if (digits.size() % 2 != 0) + digits.insert(digits.begin(), '0'); + Blob out(digits.size() / 2); + for (size_t i = 0; i < out.size(); ++i) + { + char pair[3] = {digits[2 * i], digits[2 * i + 1], 0}; + out[i] = static_cast(std::strtoul(pair, 0, 16)); + } + return out; + } + + void blob2hex(const Blob &b, char *hexnumber) + { + if (hexnumber == 0) + throw NullPointerException("null buffer", "blob2hex"); + static const char digits[] = "0123456789abcdef"; + size_t j = 0; + for (size_t i = 0; i < b.size(); ++i) + { + hexnumber[j++] = digits[b[i] >> 4]; + hexnumber[j++] = digits[b[i] & 0x0f]; + } + hexnumber[j] = 0; + } + + bool blob2file(const char *filename, const act::Blob &blob) + { + if (filename == 0) + return false; + std::FILE *f = std::fopen(filename, "wb"); + if (f == 0) + return false; + bool ok = blob.empty() || std::fwrite(blob.begin(), 1, blob.size(), f) == blob.size(); + ok = std::fclose(f) == 0 && ok; + return ok; + } + + bool file2blob(const char *filename, Blob &blob) + { + blob.clear(); + if (filename == 0) + return false; + std::FILE *f = std::fopen(filename, "rb"); + if (f == 0) + return false; + byte buf[8192]; + size_t n; + while ((n = std::fread(buf, 1, sizeof(buf), f)) != 0) + blob.insert(blob.end(), buf, buf + n); + bool ok = !std::ferror(f); + std::fclose(f); + SecureZero(buf, sizeof(buf)); + return ok; + } + + unsigned long CalculateCRC16(const act::byte *message, size_t message_len, unsigned long crc_init_value) + { + unsigned long crc = crc_init_value & 0xffff; + for (size_t i = 0; i < message_len; ++i) + { + crc ^= message[i]; + for (int k = 0; k < 8; ++k) + crc = (crc & 1) ? (crc >> 1) ^ 0xa001 : crc >> 1; + } + return crc; + } + + unsigned long CalculateCRC16(const act::Blob &message, unsigned long crc_init_value) + { + return CalculateCRC16(message.begin(), message.size(), crc_init_value); + } + + unsigned long CalculateCRC16CCITT(const act::byte *message, size_t message_len, unsigned long crc_init_value) + { + unsigned long crc = crc_init_value & 0xffff; + for (size_t i = 0; i < message_len; ++i) + { + crc ^= static_cast(message[i]) << 8; + for (int k = 0; k < 8; ++k) + crc = (crc & 0x8000) ? ((crc << 1) ^ 0x1021) & 0xffff : (crc << 1) & 0xffff; + } + return crc; + } + + unsigned long CalculateCRC16CCITT(const act::Blob &message, unsigned long crc_init_value) + { + return CalculateCRC16CCITT(message.begin(), message.size(), crc_init_value); + } + + unsigned long CalculateCRC32(const act::byte *message, size_t message_len, unsigned long crc_init_value) + { + unsigned long crc = crc_init_value & 0xffffffffUL; + for (size_t i = 0; i < message_len; ++i) + { + crc ^= message[i]; + for (int k = 0; k < 8; ++k) + crc = (crc & 1) ? (crc >> 1) ^ 0xedb88320UL : crc >> 1; + } + return crc ^ 0xffffffffUL; + } + + unsigned long CalculateCRC32(const act::Blob &message, unsigned long crc_init_value) + { + return CalculateCRC32(message.begin(), message.size(), crc_init_value); + } +} // namespace act diff --git a/port/thirdparty/cvact_compat/src/actInternal.h b/port/thirdparty/cvact_compat/src/actInternal.h new file mode 100644 index 000000000..00377a328 --- /dev/null +++ b/port/thirdparty/cvact_compat/src/actInternal.h @@ -0,0 +1,85 @@ +#ifndef ACT_COMPAT_INTERNAL_H +#define ACT_COMPAT_INTERNAL_H + +#include "actAlgorithm.h" +#include "actBlob.h" +#include "actException.h" +#include "actIAlgorithm.h" +#include "actIKey.h" +#include "actIRNGAlg.h" +#include "actMode.h" +#include "actState.h" + +#include +#include + +#include +#include + +namespace act +{ + namespace detail + { + struct BnFree { void operator()(BIGNUM *p) const { BN_clear_free(p); } }; + struct BnCtxFree { void operator()(BN_CTX *p) const { BN_CTX_free(p); } }; + struct GroupFree { void operator()(EC_GROUP *p) const { EC_GROUP_free(p); } }; + struct PointFree { void operator()(EC_POINT *p) const { EC_POINT_clear_free(p); } }; + + typedef std::unique_ptr BnPtr; + typedef std::unique_ptr BnCtxPtr; + typedef std::unique_ptr GroupPtr; + typedef std::unique_ptr PointPtr; + + BnPtr NewBn(); + BnCtxPtr NewBnCtx(); + + // Parses "[-]0x" or "[-]"; whitespace is ignored. Returns null on error. + BnPtr ParseNumber(const char *text); + // Big-endian two's complement, minimal length (at least one byte). + Blob BnToTwosComplement(const BIGNUM *bn); + // Big-endian unsigned or two's complement with a leading zero byte. + BnPtr BlobToBn(const Blob &b); + Blob BnToPadded(const BIGNUM *bn, size_t len); + + void RandomBytes(byte *out, size_t n, IRNGAlg *prng); + + // Minimal DER helpers. + void DerAppend(Blob &out, byte tag, const Blob &content); + void DerAppend(Blob &out, byte tag, const byte *content, size_t len); + struct DerItem + { + byte tag; + const byte *data; + size_t len; + }; + // Reads one TLV at pos (advancing pos). Returns false on malformed input. + bool DerRead(const byte *buf, size_t size, size_t &pos, DerItem &item); + + Blob Digest(const char *name, const Blob &data); + Blob X963Kdf(const char *digest, const Blob &secret, const Blob &sharedInfo, size_t len); + Blob Hmac(const char *digest, const Blob &key, const Blob &data); + + // Base for algorithms whose output is collected in a buffer and drained by Read(). + class BufferedAlgorithm : public IAlgorithm + { + public: + BufferedAlgorithm() : mStatus(READY) {} + + size_t GetAvailableSize() const { return mOut.size(); } + size_t Read(Blob &output, size_t max); + size_t Read(byte *outbuffer, size_t buffersize); + status_t GetStatus() const { return mStatus; } + + protected: + Blob mOut; + status_t mStatus; + }; + + IKey *CreateIESKey(); + IKey *CreateBlockCipherKey(); + IKey *ImportECKeyBlob(const Blob &keyblob); + IAlgorithm *CreateHashAlgorithm(const char *name); + } // namespace detail +} // namespace act + +#endif // ACT_COMPAT_INTERNAL_H diff --git a/port/thirdparty/miracl/mirdef.h b/port/thirdparty/miracl/mirdef.h new file mode 100644 index 000000000..1ce8df95a --- /dev/null +++ b/port/thirdparty/miracl/mirdef.h @@ -0,0 +1,48 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * Portable C configuration for the CrypTool port (GCC/Clang, 32- and 64-bit). + * + * Same word size as the original Win32 build (32-bit mr_small, 64-bit + * double-length type), but without any inline assembly. + */ + +#ifndef CRYPTOOL_MIRDEF_H +#define CRYPTOOL_MIRDEF_H + +#define MIRACL 32 + +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MR_BIG_ENDIAN +#else +#define MR_LITTLE_ENDIAN +#endif + +#define mr_utype int +#define MR_IBITS 32 +#if defined(__LP64__) || defined(_LP64) +#define MR_LBITS 64 +#else +#define MR_LBITS 32 +#endif +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_NOASM +#define MR_FLASH 52 +#define MR_NO_STANDARD_IO + +/* glibc's (C23 / _GNU_SOURCE, always on in g++) declares fadd, fsub, fmul + and fdiv; rename MIRACL's flash functions after has been seen. */ +#ifdef __cplusplus +extern "C++" { +#include +} +#else +#include +#endif +#define fadd mr_fadd +#define fsub mr_fsub +#define fmul mr_fmul +#define fdiv mr_fdiv + +#endif diff --git a/port/thirdparty/ntl/MakeDesc.c b/port/thirdparty/ntl/MakeDesc.c new file mode 100644 index 000000000..fa3da2f9f --- /dev/null +++ b/port/thirdparty/ntl/MakeDesc.c @@ -0,0 +1,1105 @@ + + +#include +#include +#include +#include +#include + + +#include + + +#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || defined(__i586__))) + + +#define AutoFix (1) + +#else + +#define AutoFix (0) + +#endif + + +int val_int(int x); +unsigned int val_uint(unsigned int x); + +long val_long(long x); +unsigned long val_ulong(unsigned long x); + +size_t val_size_t(size_t x); + +double val_double(double x); + +void touch_int(int* x); +void touch_uint(unsigned int* x); + +void touch_long(long* x); +void touch_ulong(unsigned long* x); + +void touch_size_t(size_t* x); + +void touch_double(double* x); + + + + +double power2(long k) +{ + long i; + double res; + + res = 1; + + for (i = 1; i <= k; i++) + res = res * 2; + + return res; +} + + +long DoubleRounding(long dp) +{ + double a = power2(dp-1) + 1; + double b = (power2(dp)-1)/power2(dp+1); + register double x = a + b; + double y = x; + + touch_double(&y); + + if (y != power2(dp-1) + 1) + return 1; + else + return 0; +} + + + +long DoublePrecision(void) +{ + double eps, one, res; + long k; + + one = val_double(1.0); + eps = val_double(1.0); + + k = 0; + + do { + double tmp; + + k++; + eps *= 1.0/2.0; + tmp = 1.0 + eps; + touch_double(&tmp); + res = tmp - one; + } while (res == eps); + + return k; +} + +long DoublePrecision1(void) +{ + double eps, one, res; + long k; + + one = val_double(1.0); + eps = val_double(1.0); + + k = 0; + + do { + register double tmp; + + k++; + eps *= 1.0/2.0; + tmp = 1.0 + eps; + res = tmp - one; + } while (res == eps); + + return k; +} + + +union d_or_rep { + double d; + unsigned long rep[2]; +}; + +long RepTest(void) +{ + union d_or_rep v; + + if (sizeof(double) != 2*sizeof(long)) + return 0; + + v.rep[0] = v.rep[1] = 0; + + v.d = 565656565656.0; + + if (v.rep[0] == 0x42607678 && v.rep[1] == 0x46f30000) + return 1; + else if (v.rep[1] == 0x42607678 && v.rep[0] == 0x46f30000) + return -1; + else + return 0; +} + +void print2k(FILE *f, long k, long bpl) +{ + long m, l; + long first; + + if (k <= 0) { + fprintf(f, "((double) 1.0)"); + return; + } + + m = bpl - 2; + first = 1; + + fprintf(f, "("); + + while (k > 0) { + if (k > m) + l = m; + else + l = k; + + k = k - l; + + if (first) + first = 0; + else + fprintf(f, "*"); + + fprintf(f, "((double)(1L<<%ld))", l); + } + + fprintf(f, ")"); +} + + + + + + +void print_mul_body(FILE *f, long n1, long k, long fn, + long half_flag, long short_flag) +{ + + long n, i, chop, r; + unsigned long mask, mask2; + + if (half_flag) + n = n1/2; + else + n = n1; + + chop = n % k; /* first block */ + if (chop == 0) + chop = k; + r = n - k; + mask = (1UL << k) - 1UL; + + fprintf(f, "\n\n#define NTL_"); + if (half_flag) fprintf(f, "HALF_"); + if (short_flag) fprintf(f, "SHORT_"); + + fprintf(f, "BB_MUL_CODE%ld \\\n", fn); + + + if (fn > 0) /* Mul1/AddMul1 */ + { + fprintf(f, " long i;\\\n"); + fprintf(f, " _ntl_ulong carry = 0, b;\\\n"); + } + fprintf(f, " _ntl_ulong hi, lo, t;\\\n"); + fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); + fprintf(f, " A[0] = 0;\\\n"); + + fprintf(f, " A[1] = a;\\\n"); + + for (i = 2; i < (1L << k); i++) + { + if (i % 2 == 0) + fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); + else + fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); + } + + if (fn > 0) + { + fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); + fprintf(f, " b = bp[i];\\\n"); + fprintf(f, " "); + } + + fprintf(f, " lo = A[b & %lu]; ", mask); + fprintf(f, "t = A[(b >> %ld) & %lu]; ", k, mask); + fprintf(f, "hi = t >> %ld; lo ^= t << %ld;\\\n", n1-k, k); + + for (i = 2*k; i < n - chop; i += k) { + if (fn > 0) fprintf(f, " "); + fprintf(f, " t = A[(b >> %ld) & %lu]; ", i, mask); + fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); + } + + if (fn > 0) fprintf(f, " "); + fprintf(f, " t = A[b >> %ld]; ", n-chop); + fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); + + mask = 0; + for (i = 0; i < n; i += k) + mask |= 1UL << i; + mask = ~mask; + if (half_flag) mask &= (1UL << n) - 1UL; + mask2 = mask; + + if (!short_flag) { + for (i = 1; i < k; i++) + { + if (fn > 0) fprintf(f, " "); + + if (i == 1) + fprintf(f, " if (a >> %ld) ", n1-i); + else + fprintf(f, " if ((a >> %ld) & 1) ", n1-i); + + /* bit n1-i from a was not considered in blocks of + k bits from b for index j >= i */ + fprintf(f, "hi ^= ((b & 0x%lxUL) >> %ld);\\\n", mask2, i); + mask2 = (mask2 << 1) & mask; + } + } + + if (fn > 0) fprintf(f, " "); + + if (fn == 0) + { + fprintf(f, " c[0] = lo; "); + fprintf(f, " c[1] = hi;\\\n"); + } + else if (fn == 1 || fn == 3) + { + fprintf(f, " cp[i] = carry ^ lo; "); + fprintf(f, " carry = hi;\\\n"); + } + else if (fn == 2) + { + fprintf(f, " cp[i] ^= (carry ^ lo); "); + fprintf(f, " carry = hi;\\\n"); + } + if (fn > 0) + { + + fprintf(f, " }\\\n"); + + if (fn == 1 || fn == 3) + fprintf(f, " cp[sb] = carry;\\\n"); + else + fprintf(f, " cp[sb] ^= carry;\\\n"); + + } + fprintf(f, "\n\n\n"); + + +} + + + + + +/* + * This generates anternative code that runs significantly faster + * on some machines, like a PowerPC (and probably other RISC machines). + * It makes it easier for the compiler to schedule instrucyions better, + * and it avoids branches. It seems like this does not help + * on x86 machines (and can even make things worse). + */ + + +void print_alt_mul_body(FILE *f, long n1, long k, long fn, + long half_flag, long short_flag) +{ + + long n, i, chop, r; + unsigned long mask, mask2; + + if (half_flag) + n = n1/2; + else + n = n1; + + chop = n % k; /* first block */ + if (chop == 0) + chop = k; + r = n - k; + mask = (1UL << k) - 1UL; + + fprintf(f, "\n\n#define NTL_ALT_"); + if (half_flag) fprintf(f, "HALF_"); + if (short_flag) fprintf(f, "SHORT_"); + + fprintf(f, "BB_MUL_CODE%ld \\\n", fn); + + if (fn > 0) /* Mul1/AddMul1 */ + { + fprintf(f, " long i;\\\n"); + fprintf(f, " _ntl_ulong carry = 0;\\\n"); + } + fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); + fprintf(f, " A[0] = 0;\\\n"); + + fprintf(f, " A[1] = a;\\\n"); + + for (i = 2; i < (1L << k); i++) + { + if (i % 2 == 0) + fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); + else + fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); + } + + if (fn > 0) + { + fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); + fprintf(f, " const _ntl_ulong b = bp[i];\\\n"); + } + + for (i = k; i < n - chop; i += k) { + if (fn > 0) fprintf(f, " "); + fprintf(f, " const _ntl_ulong t%ld = A[(b >> %ld) & %lu]; \\\n", i, i, mask); + + } + if (fn > 0) fprintf(f, " "); + fprintf(f, " const _ntl_ulong t%ld = A[b >> %ld]; \\\n", n-chop, n-chop); + + if (fn > 0) fprintf(f, " "); + fprintf(f, " const _ntl_ulong lo = A[b & %lu] \\\n", mask); + + for (i = k; i < n; i += k) { + if (fn > 0) fprintf(f, " "); + fprintf(f, " ^ (t%ld << %ld)", i, i); + if (i == n - chop) + fprintf(f, ";\\\n"); + else + fprintf(f, "\\\n"); + } + + for (i = k; i < n; i += k) { + if (fn > 0) fprintf(f, " "); + if (i == k) + fprintf(f, " const _ntl_ulong hi = "); + else + fprintf(f, " ^ "); + fprintf(f, "(t%ld >> %ld)", i, n1-i); + if (i == n - chop && short_flag) + fprintf(f, ";\\\n"); + else + fprintf(f, "\\\n"); + + + } + + mask = 0; + for (i = 0; i < n; i += k) + mask |= 1UL << i; + mask = ~mask; + if (half_flag) mask &= (1UL << n) - 1UL; + mask2 = mask; + + if (!short_flag) { + for (i = 1; i < k; i++) + { + + /* bit n1-i from a was not considered in blocks of + k bits from b for index j >= i */ + + if (fn > 0) fprintf(f, " "); + + + if (i == 1) + fprintf(f, + " ^ (((b & 0x%lxUL) >> %ld) & (-(a >> %ld)))", + mask2, i, n1-1); + else { + fprintf(f, + " ^ (((b & 0x%lxUL) >> %ld) & (-((a >> %ld) & 1UL)))", + mask2, i, n1-i); + } + if (i == k-1) + fprintf(f, ";\\\n"); + else + fprintf(f, "\\\n"); + + + + mask2 = (mask2 << 1) & mask; + } + } + + if (fn > 0) fprintf(f, " "); + + if (fn == 0) + { + fprintf(f, " c[0] = lo; "); + fprintf(f, " c[1] = hi;\\\n"); + } + else if (fn == 1) + { + fprintf(f, " cp[i] = carry ^ lo; "); + fprintf(f, " carry = hi;\\\n"); + } + else if (fn == 2) + { + fprintf(f, " cp[i] ^= (carry ^ lo); "); + fprintf(f, " carry = hi;\\\n"); + } + if (fn > 0) + { + + fprintf(f, " }\\\n"); + + if (fn == 1 || fn == 3) + fprintf(f, " cp[sb] = carry;\\\n"); + else + fprintf(f, " cp[sb] ^= carry;\\\n"); + + } + fprintf(f, "\n\n\n"); + + +} + + + + +void print_alt1_mul_body(FILE *f, long n1, long k, long fn, + long half_flag, long short_flag) +{ + + long n, i, chop, r; + unsigned long mask, mask2; + + if (half_flag) + n = n1/2; + else + n = n1; + + chop = n % k; /* first block */ + if (chop == 0) + chop = k; + r = n - k; + mask = (1UL << k) - 1UL; + + fprintf(f, "\n\n#define NTL_ALT1_"); + if (half_flag) fprintf(f, "HALF_"); + if (short_flag) fprintf(f, "SHORT_"); + + fprintf(f, "BB_MUL_CODE%ld \\\n", fn); + + + if (fn > 0) /* Mul1/AddMul1 */ + { + fprintf(f, " long i;\\\n"); + fprintf(f, " _ntl_ulong carry = 0, b;\\\n"); + } + fprintf(f, " _ntl_ulong hi, lo, t;\\\n"); + fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); + fprintf(f, " A[0] = 0;\\\n"); + + fprintf(f, " A[1] = a;\\\n"); + + for (i = 2; i < (1L << k); i++) + { + if (i % 2 == 0) + fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); + else + fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); + } + + if (fn > 0) + { + fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); + fprintf(f, " b = bp[i];\\\n"); + fprintf(f, " "); + } + + fprintf(f, " lo = A[b & %lu]; ", mask); + fprintf(f, "t = A[(b >> %ld) & %lu]; ", k, mask); + fprintf(f, "hi = t >> %ld; lo ^= t << %ld;\\\n", n1-k, k); + + for (i = 2*k; i < n - chop; i += k) { + if (fn > 0) fprintf(f, " "); + fprintf(f, " t = A[(b >> %ld) & %lu]; ", i, mask); + fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); + } + + if (fn > 0) fprintf(f, " "); + fprintf(f, " t = A[b >> %ld]; ", n-chop); + fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); + + mask = 0; + for (i = 0; i < n; i += k) + mask |= 1UL << i; + mask = ~mask; + if (half_flag) mask &= (1UL << n) - 1UL; + mask2 = mask; + + + if (!short_flag) { + for (i = 1; i < k; i++) + { + + /* bit n1-i from a was not considered in blocks of + k bits from b for index j >= i */ + + if (fn > 0) fprintf(f, " "); + + + if (i == 1) + fprintf(f, + " hi ^= (((b & 0x%lxUL) >> %ld) & (-(a >> %ld)))", + mask2, i, n1-1); + else { + fprintf(f, + " ^ (((b & 0x%lxUL) >> %ld) & (-((a >> %ld) & 1UL)))", + mask2, i, n1-i); + } + if (i == k-1) + fprintf(f, ";\\\n"); + else + fprintf(f, "\\\n"); + + + + mask2 = (mask2 << 1) & mask; + } + } + + + + + if (fn > 0) fprintf(f, " "); + + if (fn == 0) + { + fprintf(f, " c[0] = lo; "); + fprintf(f, " c[1] = hi;\\\n"); + } + else if (fn == 1 || fn == 3) + { + fprintf(f, " cp[i] = carry ^ lo; "); + fprintf(f, " carry = hi;\\\n"); + } + else if (fn == 2) + { + fprintf(f, " cp[i] ^= (carry ^ lo); "); + fprintf(f, " carry = hi;\\\n"); + } + if (fn > 0) + { + + fprintf(f, " }\\\n"); + + if (fn == 1 || fn == 3) + fprintf(f, " cp[sb] = carry;\\\n"); + else + fprintf(f, " cp[sb] ^= carry;\\\n"); + + } + fprintf(f, "\n\n\n"); + + +} + + + + + + + +void print_BB_mul_code(FILE *f, long n) +{ + long k; + + if (n >= 64) + k = 4; + else + k = 3; + + + print_mul_body(f, n, k, 0, 0, 0); + print_mul_body(f, n, 4, 1, 0, 0); + print_mul_body(f, n, 4, 2, 0, 0); + print_mul_body(f, n, 4, 1, 0, 1); + print_mul_body(f, n, 2, 0, 1, 0); + + + + print_alt_mul_body(f, n, k, 0, 0, 0); + print_alt_mul_body(f, n, 4, 1, 0, 0); + print_alt_mul_body(f, n, 4, 2, 0, 0); + print_alt_mul_body(f, n, 4, 1, 0, 1); + print_alt_mul_body(f, n, 2, 0, 1, 0); + + + + print_alt1_mul_body(f, n, k, 0, 0, 0); + print_alt1_mul_body(f, n, 4, 1, 0, 0); + print_alt1_mul_body(f, n, 4, 2, 0, 0); + print_alt1_mul_body(f, n, 4, 1, 0, 1); + print_alt1_mul_body(f, n, 2, 0, 1, 0); + + fprintf(f, "#define NTL_BB_MUL1_BITS (4)\n\n"); +} + + + + + +void print_BB_sqr_code(FILE *f, long n) +{ + long i, pos; + + fprintf(f, "\n\n"); + fprintf(f, "#define NTL_BB_SQR_CODE \\\n"); + fprintf(f, "lo=sqrtab[a&255];\\\n"); + pos = 16; + + for (i = 8; i < n; i += 8) { + if (2*(i+8) <= n) { + fprintf(f, "lo=lo|(sqrtab[(a>>%ld)&255]<<%ld);\\\n", i, pos); + pos += 16; + } + else if (2*i == n) { + fprintf(f, "hi=sqrtab[(a>>%ld)&255];\\\n", i); + pos = 16; + } + else if (2*i > n) { + fprintf(f, "hi=hi|(sqrtab[(a>>%ld)&255]<<%ld);\\\n", i, pos); + pos += 16; + } + else { /* only applies if word size is not a multiple of 16 */ + fprintf(f, "_ntl_ulong t=sqrtab[(a>>%ld)&255];\\\n", i); + fprintf(f, "lo=lo|(t<<%ld);\\\n", pos); + fprintf(f, "hi=t>>%ld;\\\n", n-8); + pos = 8; + } + } + + fprintf(f, "\n\n"); +} + + +void print_BB_rev_code(FILE *f, long n) +{ + long i; + + fprintf(f, "\n\n"); + fprintf(f, "#define NTL_BB_REV_CODE "); + + for (i = 0; i < n; i += 8) { + if (i != 0) fprintf(f, "\\\n|"); + fprintf(f, "(revtab[(a>>%ld)&255]<<%ld)", i, n-8-i); + } + + fprintf(f, "\n\n"); +} + + + + +char *yn_vec[2] = { "no", "yes" }; + + + +int main() +{ + long bpl, bpi, bpt, rs_arith, nbits, single_mul_ok; + long dp, dp1, dr; + FILE *f; + long warnings = 0; + + unsigned long ulval; + unsigned int uival; + size_t tval; + long slval; + + fprintf(stderr, "This is NTL version %s\n\n", NTL_VERSION); + + + + + /* + * compute bpl = bits per long + */ + + ulval = val_ulong(1); + bpl = 0; + + while (ulval) { + ulval <<= 1; + touch_ulong(&ulval); + bpl++; + } + + + + + /* + * compute bpi = bits per int + */ + + uival = val_uint(1); + bpi = 0; + + while (uival) { + uival <<= 1; + touch_uint(&uival); + bpi++; + } + + + + /* + * compute bpt = bits per size_t + */ + + tval = val_size_t(1); + bpt = 0; + + while (tval) { + tval <<= 1; + touch_size_t(&tval); + bpt++; + } + + + /* + * check if bpl and bpi are not too small --- any standard conforming + * platform should pass this test. + */ + + if (bpi < 16) { + fprintf(stderr, "BAD NEWS: int type too short.\n"); + return 1; + } + + if (bpl < 32) { + fprintf(stderr, "BAD NEWS: long type too short.\n"); + return 1; + } + + /* + * check that ints are bigger than chars. + */ + + if (bpi <= CHAR_BIT) { + fprintf(stderr, "BAD NEWS: int type must be longer than char type.\n"); + return 1; + } + + + + /* + * check that bpl is a multiple of 8. + */ + + if (bpl % 8 != 0) { + fprintf(stderr, "BAD NEWS: word size must be multiple of 8 bits.\n"); + return 1; + } + + + + + /* + * check if width of signed versions of int and long agree with that of + * the unsigned versions, and that negative numbers are represented + * using 2's compliment. + * + * The C99 standard, at least, is very precise about the possible + * representations of unsigned and signed integer types, and so if + * the following tests pass, we can be sure that the desired + * properties hold. NTL relies implicitly and crucially on + * these properties. + * + * I know of no machines for which these properties do not hold. + */ + + if (((unsigned int) val_int(INT_MIN)) != val_uint(1U << (bpi-1))) { + fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); + return 1; + } + + if (((unsigned int) val_int(INT_MAX)) != val_uint((1U << (bpi-1)) - 1U)) { + fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); + return 1; + } + + if (((unsigned long) val_long(LONG_MIN)) != val_ulong(1UL << (bpl-1))) { + fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); + return 1; + } + + if (((unsigned long) val_long(LONG_MAX)) != val_ulong((1UL<<(bpl-1))-1UL)) { + fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); + return 1; + } + + + + /* + * check that floating point to integer conversions truncates toward zero + * --- any standard conforming platform should pass this test. + */ + + if (((long) val_double(1.75)) != 1L) { + fprintf(stderr, + "BAD NEWS: machine must truncate floating point toward zero.\n"); + return 1; + } + + if (((long) val_double(-1.75)) != -1L) { + fprintf(stderr, + "BAD NEWS: machine must truncate floating point toward zero.\n"); + return 1; + } + + + + /* + * Test if right shift is arithemtic or not. According to the + * standards, the result of right-shifting a negative number is + * "implementation defined", which almost surely means the right shift + * is *always* arithmetic or *always* logical. However, this cannot + * be guaranteed, and so this test is *not* 100% portable --- but I + * know of no machine for which this test does not correctly + * predict the general behavior. One should set the NTL_CLEAN_INT + * flag if one wants to avoid such machine dependencies. + */ + + slval = val_long(-1); + if ((slval >> 1) == slval) + rs_arith = 1; + else + rs_arith = 0; + + + + /* + * Next, we check some properties of floating point arithmetic. + * An implementation should conform to the IEEE floating + * point standard --- essentially all modern platforms do, + * except for a few very old Cray's. There is no easy way + * to check this, so we simply make a few simple sanity checks, + * calculate the precision, and if the platform performs + * double precision arithemtic in extended double precision registers. + * The last property is one that the IEE standard allows, and which + * some important platforms (like x86) have --- this is quite + * unfortunate, as it really makes many of the other properties + * of the IEEE standard unusable. + */ + + /* + * First, we simply check that we are using a machine with radix 2. + */ + + if (FLT_RADIX != 2) { + fprintf(stderr, "BAD NEWS: machine must use IEEE floating point.\n"); + return 1; + } + + /* + * Next, we calculate the precision of "in memory" doubles, + * and check that it is at least 53. + */ + + dp = DoublePrecision(); + + if (dp < 53) { + fprintf(stderr, "BAD NEWS: machine must use IEEE floating point (*).\n"); + return 1; + } + + /* + * Next, we check that the *range* of doubles is sufficiently large. + * Specifically, we require that DBL_MAX > 2^{7*max(bpl, dp)} + * and 1/DBL_MIN > 2^{7*max(bpl, dp)}. + * On IEEE floating point compliant machines, this + * will hold, and the following test will pass, if bpl is at most 128, which + * should be true for the foreseeable future. + */ + + if (log(DBL_MAX)/log(2.0) < 7.01*bpl || log(DBL_MAX)/log(2.0) < 7.01*dp || + -log(DBL_MIN)/log(2.0) < 7.01*bpl || -log(DBL_MIN)/log(2.0) < 7.01*dp) { + fprintf(stderr, "BAD NEWS: range of doubles too small.\n"); + return 1; + } + + + + /* + * Next, we check if the machine has wider "in-register" doubles or not. + * This test almost always yields the correct result --- if not, + * you will have to set the NTL_EXT_DOUBLE in "mach_desc.h" + * by hand. + * + * The test effectively proves that in-register doubles are wide + * if dp1 > dp || dr. + */ + + + dp1 = DoublePrecision1(); + dr = DoubleRounding(dp); + + + /* + * Set nbits --- the default radix size for NTL's "built in" + * long integer arithmetic. + * + * Given the minimum size of blp and dp, the smallest possible + * value of nbits is 30. + */ + + + if (bpl-2 < dp-3) + nbits = bpl-2; + else + nbits = dp-3; + + if (nbits % 2 != 0) nbits--; + + + /* + * We next test if the NTL_SINGLE_MUL option is valid. This test is + * inherently DIRTY (i.e., the behavior of the test itself is not well + * defined according to the standard), but in practice should not cause any + * bad behavior, especially if the NTL_SINGLE_MUL option is never used. + * This option is anyway considered fairly obsolete, and if desired, one may + * change the following "if 1" to "if 0" and avoid performing this test + * altogether. + */ + +#if 1 + single_mul_ok = RepTest(); +#else + single_mul_ok = 0; +#endif + + + /* + * That's it! All tests have passed. + */ + + fprintf(stderr, "GOOD NEWS: compatible machine.\n"); + fprintf(stderr, "summary of machine characteristics:\n"); + fprintf(stderr, "bits per long = %ld\n", bpl); + fprintf(stderr, "bits per int = %ld\n", bpi); + fprintf(stderr, "bits per size_t = %ld\n", bpt); + fprintf(stderr, "arith right shift = %s\n", yn_vec[rs_arith]); + fprintf(stderr, "double precision = %ld\n", dp); + fprintf(stderr, "NBITS (maximum) = %ld\n", nbits); + fprintf(stderr, "single mul ok = %s\n", yn_vec[single_mul_ok != 0]); + fprintf(stderr, "register double precision = %ld\n", dp1); + fprintf(stderr, "double rounding detected = %s\n", yn_vec[dr]); + + if (((dp1 > dp) || dr) && AutoFix) + fprintf(stderr, "-- auto x86 fix\n"); + + if (dp != 53) { + warnings = 1; + + fprintf(stderr, "\n\nWARNING:\n\n"); + fprintf(stderr, "Nonstandard floating point precision.\n"); + fprintf(stderr, "IEEE standard is 53 bits.\n"); + } + +#if (defined(__sparc__) && !defined(__sparc_v8__) && \ + !defined(__sparcv8) && !defined(__sparc_v9__) && !defined(__sparcv9)) + + warnings = 1; + + fprintf(stderr, "\n\nWARNING:\n\n"); + fprintf(stderr, "If this Sparc is a Sparc-10 or later (so it has\n"); + fprintf(stderr, "a hardware integer multiply instruction) you\n"); + fprintf(stderr, "should specify the -mv8 option in the makefile\n"); + fprintf(stderr, "to obtain more efficient code.\n"); + +#endif + + if (((dp1 > dp) || dr) && !AutoFix) { + warnings = 1; + fprintf(stderr, "\n\nWARNING:\n\n"); + fprintf(stderr, "This platform has extended double precision registers.\n"); + fprintf(stderr, "While that may sound like a good thing, it actually is not.\n"); + fprintf(stderr, "If this is a Pentium or other x86 and your compiler\n"); + fprintf(stderr, "is g++ or supports GNU 'asm' constructs, it is recommended\n"); + fprintf(stderr, "to compile NTL with the NTL_X86_FIX flag to get true IEEE floating point.\n"); + fprintf(stderr, "Set this flag by editing the file config.h.\n"); + fprintf(stderr, "The code should still work even if you don't set\n"); + fprintf(stderr, "this flag. See quad_float.txt for details.\n\n"); + } + + +#if 0 + + /* better not to be interactive */ + + if (warnings) { + int c; + + fprintf(stderr, "Do you want to continue anyway[y/n]? "); + c = getchar(); + if (c == 'n' || c == 'N') { + fprintf(stderr, "Make the necessary changes to the makefile and/or config.h,\n"); + fprintf(stderr, "then type 'make clobber' and then 'make'.\n\n\n"); + return 1; + } + } + +#endif + + f = fopen("mach_desc.h", "w"); + if (!f) { + fprintf(stderr, "can't open mach_desc.h for writing\n"); + return 1; + } + + fprintf(f, "#ifndef NTL_mach_desc__H\n"); + fprintf(f, "#define NTL_mach_desc__H\n\n\n"); + fprintf(f, "#define NTL_BITS_PER_LONG (%ld)\n", bpl); + fprintf(f, "#define NTL_MAX_LONG (%ldL)\n", ((long) ((1UL<<(bpl-1))-1UL))); + fprintf(f, "#define NTL_MAX_INT (%ld)\n", ((long) ((1UL<<(bpi-1))-1UL))); + fprintf(f, "#define NTL_BITS_PER_INT (%ld)\n", bpi); + fprintf(f, "#define NTL_BITS_PER_SIZE_T (%ld)\n", bpt); + fprintf(f, "#define NTL_ARITH_RIGHT_SHIFT (%ld)\n", rs_arith); + fprintf(f, "#define NTL_NBITS_MAX (%ld)\n", nbits); + fprintf(f, "#define NTL_DOUBLE_PRECISION (%ld)\n", dp); + fprintf(f, "#define NTL_FDOUBLE_PRECISION "); + print2k(f, dp-1, bpl); + fprintf(f, "\n"); + fprintf(f, "#define NTL_QUAD_FLOAT_SPLIT ("); + print2k(f, dp - (dp/2), bpl); + fprintf(f, "+1.0)\n"); + fprintf(f, "#define NTL_EXT_DOUBLE (%d)\n", ((dp1 > dp) || dr)); + fprintf(f, "#define NTL_SINGLE_MUL_OK (%d)\n", single_mul_ok != 0); + fprintf(f, "#define NTL_DOUBLES_LOW_HIGH (%d)\n\n\n", single_mul_ok < 0); + print_BB_mul_code(f, bpl); + print_BB_sqr_code(f, bpl); + print_BB_rev_code(f, bpl); + + fprintf(f, "#define NTL_MIN_LONG (-NTL_MAX_LONG - 1L)\n"); + fprintf(f, "#define NTL_MIN_INT (-NTL_MAX_INT - 1)\n"); + + fprintf(f, "#endif\n\n"); + + fclose(f); + + fprintf(stderr, "\n\n"); + + return 0; +} diff --git a/port/thirdparty/ntl/MakeDescAux.c b/port/thirdparty/ntl/MakeDescAux.c new file mode 100644 index 000000000..cad629e62 --- /dev/null +++ b/port/thirdparty/ntl/MakeDescAux.c @@ -0,0 +1,23 @@ + +#include + +int val_int(int x) { return x; } +unsigned int val_uint(unsigned int x) { return x; } + +long val_long(long x) { return x; } +unsigned long val_ulong(unsigned long x) { return x; } + +size_t val_size_t(size_t x) { return x; } + +double val_double(double x) { return x; } + +void touch_int(int* x) {} +void touch_uint(unsigned int* x) {} + +void touch_long(long* x) {} +void touch_ulong(unsigned long* x) {} + +void touch_size_t(size_t* x) {} + +void touch_double(double* x) {} + diff --git a/port/thirdparty/openssl_compat/include/OpenSSL/ct_ossl_base.h b/port/thirdparty/openssl_compat/include/OpenSSL/ct_ossl_base.h new file mode 100644 index 000000000..149918e57 --- /dev/null +++ b/port/thirdparty/openssl_compat/include/OpenSSL/ct_ossl_base.h @@ -0,0 +1,24 @@ +/* + * Shared helpers for the OpenSSL 1.0.1 compatibility headers used by CrypTool. + * Deliberately free of system #includes: CrypTool includes these headers inside + * C++ namespaces (namespace __SSL { ... }), where pulling in system headers + * would misplace their declarations. + */ +#ifndef CT_OSSL_BASE_H +#define CT_OSSL_BASE_H + +#if defined(__SIZE_TYPE__) +#define CT_OSSL_SIZE_T __SIZE_TYPE__ +#else +#define CT_OSSL_SIZE_T size_t +#endif + +#ifdef __cplusplus +#define CT_OSSL_BEGIN_C extern "C" { +#define CT_OSSL_END_C } +#else +#define CT_OSSL_BEGIN_C +#define CT_OSSL_END_C +#endif + +#endif diff --git a/port/thirdparty/openssl_compat/include/OpenSSL/md2.h b/port/thirdparty/openssl_compat/include/OpenSSL/md2.h new file mode 100644 index 000000000..f084d1f8e --- /dev/null +++ b/port/thirdparty/openssl_compat/include/OpenSSL/md2.h @@ -0,0 +1,40 @@ +/* + * OpenSSL 1.0.1 compatible MD2 API. OpenSSL 3 ships without MD2, so the + * functions are implemented by cryptool_openssl_compat (ct_MD2_*). + */ +#ifndef OPENSSL_MD2_H +#define OPENSSL_MD2_H +#ifndef HEADER_MD2_H +#define HEADER_MD2_H +#endif + +#include "ct_ossl_base.h" + +#define MD2_DIGEST_LENGTH 16 +#define MD2_BLOCK 16 +#ifndef MD2_INT +#define MD2_INT unsigned int +#endif + +CT_OSSL_BEGIN_C + +typedef struct MD2state_st { + unsigned int num; + unsigned char data[MD2_BLOCK]; + MD2_INT cksm[MD2_BLOCK]; + MD2_INT state[MD2_BLOCK]; +} MD2_CTX; + +#define MD2_options ct_MD2_options +#define MD2_Init ct_MD2_Init +#define MD2_Update ct_MD2_Update +#define MD2_Final ct_MD2_Final + +const char *MD2_options(void); +int MD2_Init(MD2_CTX *c); +int MD2_Update(MD2_CTX *c, const unsigned char *data, CT_OSSL_SIZE_T len); +int MD2_Final(unsigned char *md, MD2_CTX *c); + +CT_OSSL_END_C + +#endif diff --git a/port/thirdparty/openssl_compat/include/OpenSSL/md4.h b/port/thirdparty/openssl_compat/include/OpenSSL/md4.h new file mode 100644 index 000000000..4524e7d54 --- /dev/null +++ b/port/thirdparty/openssl_compat/include/OpenSSL/md4.h @@ -0,0 +1,35 @@ +/* + * OpenSSL 1.0.1/3.x compatible MD4 declarations (implemented by libcrypto). + * Same layout and guards as OpenSSL 3's . + */ +#ifndef OPENSSL_MD4_H +#define OPENSSL_MD4_H +#ifndef HEADER_MD4_H +#define HEADER_MD4_H +#endif + +#include "ct_ossl_base.h" + +#define MD4_DIGEST_LENGTH 16 +#define MD4_LONG unsigned int +#define MD4_CBLOCK 64 +#define MD4_LBLOCK (MD4_CBLOCK / 4) + +CT_OSSL_BEGIN_C + +typedef struct MD4state_st { + MD4_LONG A, B, C, D; + MD4_LONG Nl, Nh; + MD4_LONG data[MD4_LBLOCK]; + unsigned int num; +} MD4_CTX; + +int MD4_Init(MD4_CTX *c); +int MD4_Update(MD4_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int MD4_Final(unsigned char *md, MD4_CTX *c); +unsigned char *MD4(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); +void MD4_Transform(MD4_CTX *c, const unsigned char *b); + +CT_OSSL_END_C + +#endif diff --git a/port/thirdparty/openssl_compat/include/OpenSSL/md5.h b/port/thirdparty/openssl_compat/include/OpenSSL/md5.h new file mode 100644 index 000000000..b93214840 --- /dev/null +++ b/port/thirdparty/openssl_compat/include/OpenSSL/md5.h @@ -0,0 +1,35 @@ +/* + * OpenSSL 1.0.1/3.x compatible MD5 declarations (implemented by libcrypto). + * Same layout and guards as OpenSSL 3's . + */ +#ifndef OPENSSL_MD5_H +#define OPENSSL_MD5_H +#ifndef HEADER_MD5_H +#define HEADER_MD5_H +#endif + +#include "ct_ossl_base.h" + +#define MD5_DIGEST_LENGTH 16 +#define MD5_LONG unsigned int +#define MD5_CBLOCK 64 +#define MD5_LBLOCK (MD5_CBLOCK / 4) + +CT_OSSL_BEGIN_C + +typedef struct MD5state_st { + MD5_LONG A, B, C, D; + MD5_LONG Nl, Nh; + MD5_LONG data[MD5_LBLOCK]; + unsigned int num; +} MD5_CTX; + +int MD5_Init(MD5_CTX *c); +int MD5_Update(MD5_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); +void MD5_Transform(MD5_CTX *c, const unsigned char *b); + +CT_OSSL_END_C + +#endif diff --git a/port/thirdparty/openssl_compat/include/OpenSSL/ripemd.h b/port/thirdparty/openssl_compat/include/OpenSSL/ripemd.h new file mode 100644 index 000000000..231ac2bb3 --- /dev/null +++ b/port/thirdparty/openssl_compat/include/OpenSSL/ripemd.h @@ -0,0 +1,35 @@ +/* + * OpenSSL 1.0.1/3.x compatible RIPEMD-160 declarations (implemented by libcrypto). + * Same layout and guards as OpenSSL 3's . + */ +#ifndef OPENSSL_RIPEMD_H +#define OPENSSL_RIPEMD_H +#ifndef HEADER_RIPEMD_H +#define HEADER_RIPEMD_H +#endif + +#include "ct_ossl_base.h" + +#define RIPEMD160_DIGEST_LENGTH 20 +#define RIPEMD160_LONG unsigned int +#define RIPEMD160_CBLOCK 64 +#define RIPEMD160_LBLOCK (RIPEMD160_CBLOCK / 4) + +CT_OSSL_BEGIN_C + +typedef struct RIPEMD160state_st { + RIPEMD160_LONG A, B, C, D, E; + RIPEMD160_LONG Nl, Nh; + RIPEMD160_LONG data[RIPEMD160_LBLOCK]; + unsigned int num; +} RIPEMD160_CTX; + +int RIPEMD160_Init(RIPEMD160_CTX *c); +int RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c); +unsigned char *RIPEMD160(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); +void RIPEMD160_Transform(RIPEMD160_CTX *c, const unsigned char *b); + +CT_OSSL_END_C + +#endif diff --git a/port/thirdparty/openssl_compat/include/OpenSSL/sha.h b/port/thirdparty/openssl_compat/include/OpenSSL/sha.h new file mode 100644 index 000000000..8f571aa75 --- /dev/null +++ b/port/thirdparty/openssl_compat/include/OpenSSL/sha.h @@ -0,0 +1,100 @@ +/* + * OpenSSL 1.0.1/3.x compatible SHA declarations. SHA-1/224/256/384/512 are + * implemented by libcrypto (same layout and guards as OpenSSL 3's + * ); SHA-0 (SHA_Init/SHA_Update/SHA_Final), removed in + * OpenSSL 1.1.0, is implemented by cryptool_openssl_compat (ct_SHA0_*). + */ +#ifndef OPENSSL_SHA_H +#define OPENSSL_SHA_H +#ifndef HEADER_SHA_H +#define HEADER_SHA_H +#endif + +#include "ct_ossl_base.h" + +#define SHA_DIGEST_LENGTH 20 +#define SHA_LONG unsigned int +#define SHA_LBLOCK 16 +#define SHA_CBLOCK (SHA_LBLOCK * 4) +#define SHA_LAST_BLOCK (SHA_CBLOCK - 8) + +#define SHA256_CBLOCK (SHA_LBLOCK * 4) +#define SHA256_192_DIGEST_LENGTH 24 +#define SHA224_DIGEST_LENGTH 28 +#define SHA256_DIGEST_LENGTH 32 +#define SHA384_DIGEST_LENGTH 48 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_CBLOCK (SHA_LBLOCK * 8) +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +#define SHA_LONG64 unsigned __int64 +#elif defined(__arch64__) +#define SHA_LONG64 unsigned long +#else +#define SHA_LONG64 unsigned long long +#endif + +CT_OSSL_BEGIN_C + +typedef struct SHAstate_st { + SHA_LONG h0, h1, h2, h3, h4; + SHA_LONG Nl, Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num; +} SHA_CTX; + +typedef struct SHA256state_st { + SHA_LONG h[8]; + SHA_LONG Nl, Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num, md_len; +} SHA256_CTX; + +typedef struct SHA512state_st { + SHA_LONG64 h[8]; + SHA_LONG64 Nl, Nh; + union { + SHA_LONG64 d[SHA_LBLOCK]; + unsigned char p[SHA512_CBLOCK]; + } u; + unsigned int num, md_len; +} SHA512_CTX; + +#define SHA_Init ct_SHA0_Init +#define SHA_Update ct_SHA0_Update +#define SHA_Final ct_SHA0_Final +#define SHA_Transform ct_SHA0_Transform + +int SHA_Init(SHA_CTX *c); +int SHA_Update(SHA_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int SHA_Final(unsigned char *md, SHA_CTX *c); +void SHA_Transform(SHA_CTX *c, const unsigned char *data); + +int SHA1_Init(SHA_CTX *c); +int SHA1_Update(SHA_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int SHA1_Final(unsigned char *md, SHA_CTX *c); +void SHA1_Transform(SHA_CTX *c, const unsigned char *data); +unsigned char *SHA1(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); + +int SHA224_Init(SHA256_CTX *c); +int SHA224_Update(SHA256_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int SHA224_Final(unsigned char *md, SHA256_CTX *c); +int SHA256_Init(SHA256_CTX *c); +int SHA256_Update(SHA256_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int SHA256_Final(unsigned char *md, SHA256_CTX *c); +void SHA256_Transform(SHA256_CTX *c, const unsigned char *data); +unsigned char *SHA224(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); +unsigned char *SHA256(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); + +int SHA384_Init(SHA512_CTX *c); +int SHA384_Update(SHA512_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int SHA384_Final(unsigned char *md, SHA512_CTX *c); +int SHA512_Init(SHA512_CTX *c); +int SHA512_Update(SHA512_CTX *c, const void *data, CT_OSSL_SIZE_T len); +int SHA512_Final(unsigned char *md, SHA512_CTX *c); +void SHA512_Transform(SHA512_CTX *c, const unsigned char *data); +unsigned char *SHA384(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); +unsigned char *SHA512(const unsigned char *d, CT_OSSL_SIZE_T n, unsigned char *md); + +CT_OSSL_END_C + +#endif diff --git a/port/thirdparty/openssl_compat/include_bare/crypto.h b/port/thirdparty/openssl_compat/include_bare/crypto.h new file mode 100644 index 000000000..49ed76004 --- /dev/null +++ b/port/thirdparty/openssl_compat/include_bare/crypto.h @@ -0,0 +1,33 @@ +/* + * Minimal stand-in for OpenSSL 1.0.1's "crypto.h" as included bare by + * CrypTool/DlgAbout.cpp inside namespace OPENSSL { }: only the version query, + * forwarded to OpenSSL 3's OpenSSL_version(). No system #includes. + */ +#ifndef CT_OSSL_COMPAT_CRYPTO_H +#define CT_OSSL_COMPAT_CRYPTO_H + +#ifndef OPENSSL_VERSION +#define OPENSSL_VERSION 0 +#endif +#ifndef SSLEAY_VERSION +#define SSLEAY_VERSION OPENSSL_VERSION +#endif +#ifndef SSLeay_version +#define SSLeay_version OpenSSL_version +#endif +#ifndef SSLeay +#define SSLeay OpenSSL_version_num +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +const char *OpenSSL_version(int type); +unsigned long OpenSSL_version_num(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/thirdparty/openssl_compat/src/ct_md2.c b/port/thirdparty/openssl_compat/src/ct_md2.c new file mode 100644 index 000000000..d4ef0bea4 --- /dev/null +++ b/port/thirdparty/openssl_compat/src/ct_md2.c @@ -0,0 +1,108 @@ +/* MD2 message digest (RFC 1319) with the OpenSSL 1.0.1 MD2_* interface. */ +#include +#include + +#include "OpenSSL/md2.h" + +static const unsigned char PI_SUBST[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, + 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, + 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, + 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, + 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, + 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, + 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, + 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, + 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, + 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, + 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, + 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, + 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, + 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, + 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 +}; + +static void md2_block(MD2_CTX *c, const unsigned char *block) +{ + unsigned char x[48]; + unsigned int j, k, t; + unsigned int l; + + for (j = 0; j < 16; j++) { + x[j] = (unsigned char)c->state[j]; + x[16 + j] = block[j]; + x[32 + j] = (unsigned char)(c->state[j] ^ block[j]); + } + t = 0; + for (j = 0; j < 18; j++) { + for (k = 0; k < 48; k++) + t = x[k] ^= PI_SUBST[t]; + t = (t + j) & 0xff; + } + for (j = 0; j < 16; j++) + c->state[j] = x[j]; + + l = c->cksm[15]; + for (j = 0; j < 16; j++) { + c->cksm[j] ^= PI_SUBST[block[j] ^ l]; + c->cksm[j] &= 0xff; + l = c->cksm[j]; + } + memset(x, 0, sizeof(x)); +} + +const char *MD2_options(void) +{ + return "md2(int)"; +} + +int MD2_Init(MD2_CTX *c) +{ + memset(c, 0, sizeof(*c)); + return 1; +} + +int MD2_Update(MD2_CTX *c, const unsigned char *data, size_t len) +{ + if (len == 0) + return 1; + if (c->num != 0) { + size_t take = MD2_BLOCK - c->num; + if (len < take) { + memcpy(c->data + c->num, data, len); + c->num += (unsigned int)len; + return 1; + } + memcpy(c->data + c->num, data, take); + md2_block(c, c->data); + data += take; + len -= take; + c->num = 0; + } + while (len >= MD2_BLOCK) { + md2_block(c, data); + data += MD2_BLOCK; + len -= MD2_BLOCK; + } + memcpy(c->data, data, len); + c->num = (unsigned int)len; + return 1; +} + +int MD2_Final(unsigned char *md, MD2_CTX *c) +{ + unsigned char pad = (unsigned char)(MD2_BLOCK - c->num); + unsigned char cksm[MD2_BLOCK]; + unsigned int i; + + memset(c->data + c->num, pad, pad); + md2_block(c, c->data); + for (i = 0; i < MD2_BLOCK; i++) + cksm[i] = (unsigned char)c->cksm[i]; + md2_block(c, cksm); + for (i = 0; i < MD2_DIGEST_LENGTH; i++) + md[i] = (unsigned char)c->state[i]; + memset(c, 0, sizeof(*c)); + return 1; +} diff --git a/port/thirdparty/openssl_compat/src/ct_sha0.c b/port/thirdparty/openssl_compat/src/ct_sha0.c new file mode 100644 index 000000000..e2eea746c --- /dev/null +++ b/port/thirdparty/openssl_compat/src/ct_sha0.c @@ -0,0 +1,131 @@ +/* SHA-0 (FIPS 180, 1993) with the OpenSSL 1.0.1 SHA_* interface. */ +#include +#include + +#include "OpenSSL/sha.h" + +#define ROL32(x, n) ((((x) << (n)) | ((x) >> (32 - (n)))) & 0xffffffffU) + +void SHA_Transform(SHA_CTX *c, const unsigned char *p) +{ + SHA_LONG w[80]; + SHA_LONG a, b, d, e, f, k, t, cc; + int i; + + for (i = 0; i < 16; i++, p += 4) + w[i] = ((SHA_LONG)p[0] << 24) | ((SHA_LONG)p[1] << 16) | ((SHA_LONG)p[2] << 8) | (SHA_LONG)p[3]; + for (i = 16; i < 80; i++) + w[i] = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; + + a = c->h0; + b = c->h1; + cc = c->h2; + d = c->h3; + e = c->h4; + for (i = 0; i < 80; i++) { + if (i < 20) { + f = (b & cc) | (~b & d); + k = 0x5a827999U; + } else if (i < 40) { + f = b ^ cc ^ d; + k = 0x6ed9eba1U; + } else if (i < 60) { + f = (b & cc) | (b & d) | (cc & d); + k = 0x8f1bbcdcU; + } else { + f = b ^ cc ^ d; + k = 0xca62c1d6U; + } + t = (ROL32(a, 5) + f + e + k + w[i]) & 0xffffffffU; + e = d; + d = cc; + cc = ROL32(b, 30); + b = a; + a = t; + } + c->h0 = (c->h0 + a) & 0xffffffffU; + c->h1 = (c->h1 + b) & 0xffffffffU; + c->h2 = (c->h2 + cc) & 0xffffffffU; + c->h3 = (c->h3 + d) & 0xffffffffU; + c->h4 = (c->h4 + e) & 0xffffffffU; +} + +int SHA_Init(SHA_CTX *c) +{ + memset(c, 0, sizeof(*c)); + c->h0 = 0x67452301U; + c->h1 = 0xefcdab89U; + c->h2 = 0x98badcfeU; + c->h3 = 0x10325476U; + c->h4 = 0xc3d2e1f0U; + return 1; +} + +int SHA_Update(SHA_CTX *c, const void *data_, size_t len) +{ + const unsigned char *data = (const unsigned char *)data_; + unsigned char *buf = (unsigned char *)c->data; + SHA_LONG lo = (c->Nl + ((SHA_LONG)len << 3)) & 0xffffffffU; + + if (lo < c->Nl) + c->Nh++; + c->Nh += (SHA_LONG)((unsigned long long)len >> 29); + c->Nl = lo; + + if (c->num != 0) { + size_t take = SHA_CBLOCK - c->num; + if (len < take) { + memcpy(buf + c->num, data, len); + c->num += (unsigned int)len; + return 1; + } + memcpy(buf + c->num, data, take); + SHA_Transform(c, buf); + data += take; + len -= take; + c->num = 0; + } + while (len >= SHA_CBLOCK) { + SHA_Transform(c, data); + data += SHA_CBLOCK; + len -= SHA_CBLOCK; + } + memcpy(buf, data, len); + c->num = (unsigned int)len; + return 1; +} + +int SHA_Final(unsigned char *md, SHA_CTX *c) +{ + unsigned char *buf = (unsigned char *)c->data; + SHA_LONG h[5]; + unsigned int n = c->num; + int i; + + buf[n++] = 0x80; + if (n > SHA_LAST_BLOCK) { + memset(buf + n, 0, SHA_CBLOCK - n); + SHA_Transform(c, buf); + n = 0; + } + memset(buf + n, 0, SHA_LAST_BLOCK - n); + for (i = 0; i < 4; i++) { + buf[SHA_LAST_BLOCK + i] = (unsigned char)(c->Nh >> (24 - 8 * i)); + buf[SHA_LAST_BLOCK + 4 + i] = (unsigned char)(c->Nl >> (24 - 8 * i)); + } + SHA_Transform(c, buf); + + h[0] = c->h0; + h[1] = c->h1; + h[2] = c->h2; + h[3] = c->h3; + h[4] = c->h4; + for (i = 0; i < 5; i++) { + md[4 * i] = (unsigned char)(h[i] >> 24); + md[4 * i + 1] = (unsigned char)(h[i] >> 16); + md[4 * i + 2] = (unsigned char)(h[i] >> 8); + md[4 * i + 3] = (unsigned char)h[i]; + } + memset(c, 0, sizeof(*c)); + return 1; +} diff --git a/port/thirdparty/tests/test_aes_candidates.cpp b/port/thirdparty/tests/test_aes_candidates.cpp new file mode 100644 index 000000000..7f583d6fa --- /dev/null +++ b/port/thirdparty/tests/test_aes_candidates.cpp @@ -0,0 +1,242 @@ +// Known-answer tests for the AES candidate ciphers through the NIST API calls +// CrypTool's CoreCryptography.cpp makes. Build with CT_AES_ORACLE (and the +// original headers) to regenerate the reference table with --dump. +#include "mars.h" +#include "RC6.h" +#include "Rijndael-api-fst.h" +#include "Serpent.h" +#include "Twofish.h" + +#ifdef long +#error "the AES wrapper headers leaked their long narrowing" +#endif + +#include +#include +#include +#include +#include + +#ifndef CT_AES_ORACLE +extern "C" const size_t ct_aes_mars_sizes[2]; +extern "C" const size_t ct_aes_rc6_sizes[2]; +extern "C" const size_t ct_aes_rijndael_sizes[2]; +extern "C" const size_t ct_aes_serpent_sizes[2]; +extern "C" const size_t ct_aes_twofish_sizes[2]; +#endif + +static int failures = 0; + +static void fail(const std::string &what) { + std::fprintf(stderr, "FAIL: %s\n", what.c_str()); + ++failures; +} + +static std::string hex(const BYTE *p, int n) { + static const char digits[] = "0123456789abcdef"; + std::string s; + for (int i = 0; i < n; ++i) { + s += digits[p[i] >> 4]; + s += digits[p[i] & 15]; + } + return s; +} + +static std::vector unhex(const char *s) { + std::vector out; + for (; s[0] && s[1]; s += 2) { + unsigned v = 0; + std::sscanf(s, "%2x", &v); + out.push_back((BYTE)v); + } + return out; +} + +template +struct Api { + const char *name; + int (*makeKey)(K *, BYTE, int, char *); + int (*cipherInit)(C *, BYTE, char *); + int (*encrypt)(C *, K *, BYTE *, int, BYTE *); + int (*decrypt)(C *, K *, BYTE *, int, BYTE *); +}; + +template +static std::string run(const Api &api, int keyBits, const char *keyHex, BYTE mode, + const char *ivHex, const std::vector &pt) { + std::string label = std::string(api.name) + " key=" + keyHex + " mode=" + + std::to_string(mode) + " iv=" + (ivHex ? ivHex : "-"); + char keyBuf[80], ivBuf[40]; + std::snprintf(keyBuf, sizeof keyBuf, "%s", keyHex); + std::snprintf(ivBuf, sizeof ivBuf, "%s", ivHex ? ivHex : "00000000000000000000000000000000"); + std::vector in(pt), ct(pt.size() + 16), back(pt.size() + 16); + int bits = (int)pt.size() * 8; + + K key; + C cipher; + std::memset(&key, 0, sizeof key); + std::memset(&cipher, 0, sizeof cipher); + if (api.makeKey(&key, DIR_ENCRYPT, keyBits, keyBuf) != TRUE) + fail(label + ": makeKey(encrypt)"); + if (api.cipherInit(&cipher, mode, ivBuf) != TRUE) + fail(label + ": cipherInit(encrypt)"); + api.encrypt(&cipher, &key, in.data(), bits, ct.data()); + + std::snprintf(keyBuf, sizeof keyBuf, "%s", keyHex); + std::snprintf(ivBuf, sizeof ivBuf, "%s", ivHex ? ivHex : "00000000000000000000000000000000"); + std::memset(&key, 0, sizeof key); + std::memset(&cipher, 0, sizeof cipher); + if (api.makeKey(&key, DIR_DECRYPT, keyBits, keyBuf) != TRUE) + fail(label + ": makeKey(decrypt)"); + if (api.cipherInit(&cipher, mode, ivBuf) != TRUE) + fail(label + ": cipherInit(decrypt)"); + api.decrypt(&cipher, &key, ct.data(), bits, back.data()); + if (std::memcmp(back.data(), pt.data(), pt.size()) != 0) + fail(label + ": decrypt(encrypt(x)) != x"); + return hex(ct.data(), (int)pt.size()); +} + +static const Api kMars = { + "MARS", makeKeyMars, cipherInitMars, blockEncryptMars, blockDecryptMars}; +static const Api kRC6 = { + "RC6", makeKeyRC6, cipherInitRC6, blockEncryptRC6, blockDecryptRC6}; +static const Api kRijndael = { + "RIJNDAEL", makeKeyRijndael, cipherInitRijndael, blockEncryptRijndael, blockDecryptRijndael}; +static const Api kSerpent = { + "SERPENT", makeKeySerpent, cipherInitSerpent, blockEncryptSerpent, blockDecryptSerpent}; +static const Api kTwofish = { + "TWOFISH", makeKeyTwofish, cipherInitTwofish, blockEncryptTwofish, blockDecryptTwofish}; + +template +static std::string runAny(int which, const Api &api, int keyBits, const char *key, + BYTE mode, const char *iv, const std::vector &pt) { + (void)which; + return run(api, keyBits, key, mode, iv, pt); +} + +static std::string dispatch(int alg, int keyBits, const char *key, BYTE mode, const char *iv, + const std::vector &pt) { + switch (alg) { + case 0: return runAny(alg, kMars, keyBits, key, mode, iv, pt); + case 1: return runAny(alg, kRC6, keyBits, key, mode, iv, pt); + case 2: return runAny(alg, kRijndael, keyBits, key, mode, iv, pt); + case 3: return runAny(alg, kSerpent, keyBits, key, mode, iv, pt); + default: return runAny(alg, kTwofish, keyBits, key, mode, iv, pt); + } +} + +static const char *const kAlgNames[] = {"MARS", "RC6", "RIJNDAEL", "SERPENT", "TWOFISH"}; + +// Published vectors (independent of the reference implementations above). +struct Kat { + int alg, keyBits; + const char *key, *pt, *ct; +}; +static const Kat kPublished[] = { + // FIPS-197 appendix C + {2, 128, "000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a"}, + {2, 192, "000102030405060708090a0b0c0d0e0f1011121314151617", "00112233445566778899aabbccddeeff", "dda97ca4864cdfe06eaf70a0ec0d7191"}, + {2, 256, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", "8ea2b7ca516745bfeafc49904b496089"}, + // Twofish paper, all-zero key and plaintext + {4, 128, "00000000000000000000000000000000", "00000000000000000000000000000000", "9f589f5cf6122c32b6bfec2f2ae8c35a"}, + {4, 192, "000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "efa71f788965bd4453f860178fc19101"}, + {4, 256, "0000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "57ff739d4dc92c1bd7fc01700cc8216f"}, + // RC6 paper + {1, 128, "00000000000000000000000000000000", "00000000000000000000000000000000", "8fc3a53656b1f778c129df4e9848a41e"}, + {1, 128, "0123456789abcdef0112233445566778", "02132435465768798a9bacbdcedfe0f1", "524e192f4715c6231f51f6367ea43f18"}, + {1, 192, "000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "6cd61bcb190b30384e8a3f168690ae82"}, + {1, 256, "0123456789abcdef0112233445566778899aabbccddeeff01032547698badcfe", "02132435465768798a9bacbdcedfe0f1", "c8241816f0d7e48920ad16a1674e5d48"}, +}; + +// Generated with --dump from the unmodified sources built for i386 (32-bit +// long, i.e. the semantics of the original Win32 build). +struct Ref { + int alg, keyBits, keyIdx, mode, ivIdx; + const char *ct; +}; +static const Ref kReference[] = { +#include "test_aes_candidates_ref.inc" +}; + +static const char *keyFor(int idx, int bits, std::string &buf) { + static const char pattern[] = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + static const char other[] = "2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe"; + if (idx == 0) + buf.assign(bits / 4, '0'); + else + buf.assign(idx == 1 ? pattern : other, bits / 4); + return buf.c_str(); +} + +static const char *ivFor(int idx) { + switch (idx) { + case 0: return "00000000000000000000000000000000"; + default: return "0f0e0d0c0b0a09080706050403020100"; + } +} + +static std::vector plaintext() { + std::vector pt(48); + for (int i = 0; i < 48; ++i) + pt[i] = (BYTE)(((i % 16) * 0x11 + i / 16) & 0xff); + return pt; +} + +int main(int argc, char **argv) { + bool dump = argc > 1 && std::strcmp(argv[1], "--dump") == 0; + +#ifndef CT_AES_ORACLE + if (ct_aes_mars_sizes[0] != sizeof(keyInstanceMars) || ct_aes_mars_sizes[1] != sizeof(cipherInstanceMars)) + fail("MARS struct layout differs between library and public header"); + if (ct_aes_rc6_sizes[0] != sizeof(keyInstanceRC6) || ct_aes_rc6_sizes[1] != sizeof(cipherInstanceRC6)) + fail("RC6 struct layout differs between library and public header"); + if (ct_aes_rijndael_sizes[0] != sizeof(keyInstanceRijndael) || ct_aes_rijndael_sizes[1] != sizeof(cipherInstanceRijndael)) + fail("Rijndael struct layout differs between library and public header"); + if (ct_aes_serpent_sizes[0] != sizeof(keyInstanceSerpent) || ct_aes_serpent_sizes[1] != sizeof(cipherInstanceSerpent)) + fail("Serpent struct layout differs between library and public header"); + if (ct_aes_twofish_sizes[0] != sizeof(keyInstanceTwofish) || ct_aes_twofish_sizes[1] != sizeof(cipherInstanceTwofish)) + fail("Twofish struct layout differs between library and public header"); +#endif + + for (const Kat &k : kPublished) { + std::vector pt = unhex(k.pt); + std::string ct = dispatch(k.alg, k.keyBits, k.key, MODE_ECB, nullptr, pt); + if (ct != k.ct) + fail(std::string(kAlgNames[k.alg]) + " published KAT key=" + k.key + ": got " + ct + " want " + k.ct); + } + + const std::vector pt = plaintext(); + const int modes[] = {MODE_ECB, MODE_CBC}; + size_t checked = 0; + for (int alg = 0; alg < 5; ++alg) + for (int keyBits : {128, 192, 256}) + for (int keyIdx = 0; keyIdx < 3; ++keyIdx) + for (int mode : modes) + for (int ivIdx = 0; ivIdx < (mode == MODE_CBC ? 2 : 1); ++ivIdx) { + std::string keyBuf; + const char *key = keyFor(keyIdx, keyBits, keyBuf); + std::string ct = dispatch(alg, keyBits, key, (BYTE)mode, ivFor(ivIdx), pt); + if (dump) { + std::printf("{%d, %d, %d, %d, %d, \"%s\"},\n", alg, keyBits, keyIdx, mode, ivIdx, ct.c_str()); + continue; + } + bool found = false; + for (const Ref &r : kReference) + if (r.alg == alg && r.keyBits == keyBits && r.keyIdx == keyIdx && r.mode == mode && r.ivIdx == ivIdx) { + found = true; + ++checked; + if (ct != r.ct) + fail(std::string(kAlgNames[alg]) + " reference key=" + key + " mode=" + + std::to_string(mode) + " iv=" + std::to_string(ivIdx) + ": got " + ct + " want " + r.ct); + } + if (!found) + fail(std::string(kAlgNames[alg]) + ": no reference entry"); + } + + if (dump) + return failures == 0 ? 0 : 1; + if (failures == 0) + std::printf("aes candidates: %zu reference vectors and %zu published KATs passed\n", checked, + sizeof kPublished / sizeof kPublished[0]); + return failures == 0 ? 0 : 1; +} diff --git a/port/thirdparty/tests/test_aes_candidates_ref.inc b/port/thirdparty/tests/test_aes_candidates_ref.inc new file mode 100644 index 000000000..c6829f653 --- /dev/null +++ b/port/thirdparty/tests/test_aes_candidates_ref.inc @@ -0,0 +1,135 @@ +{0, 128, 0, 1, 0, "7199b218d7554c9d4323fae452debb7a4d866911094b1ebc874dbca1df361ab55841a56270990e5193e659407cb1905a"}, +{0, 128, 0, 2, 0, "7199b218d7554c9d4323fae452debb7a1083771f67871578925063e58c1b5eae82f722ca87d94a1253041c6a02aa7672"}, +{0, 128, 0, 2, 1, "99c73ac4135edf5b8ceb2adf2ab5a34942af8f6cd0cbbba189355b642d55df68dd0ae51647429ed6a63aac143b8f6e32"}, +{0, 128, 1, 1, 0, "93eded1c5d729f449eed0ec7766922d316e7e1c328abcfe08cc13a39eabb4cb9d05b412f5bdc46703e27e7adc82d3f9a"}, +{0, 128, 1, 2, 0, "93eded1c5d729f449eed0ec7766922d3ce622dc260ee21ee226bae6301fd913d1205b1425e4e0b34c2f38a9edfc0b0d1"}, +{0, 128, 1, 2, 1, "141c3b5fd5ea76bb6f795ce878bdef42f88c5039a296f0287151f3cf1901bfc4dc6a6bcb0e2a713fd9a61583fe2d4ca5"}, +{0, 128, 2, 1, 0, "be4f1331022ceafb6c11feee9bb2ece47dd22297c3337ddfd16a3a371673140817ccb4a4143b740244d74fb1a64a0301"}, +{0, 128, 2, 2, 0, "be4f1331022ceafb6c11feee9bb2ece42064f4f97955690f9584a146cc423fbb832bf735944b4fca5c4d91ca57d98c43"}, +{0, 128, 2, 2, 1, "23cecf5ed174dd90e03a3fcbcfc60d0a714605c5789cf7f01ee81ef0a6f2bc62b42e16059cee4d4b7f83c4c6acfc9c76"}, +{0, 192, 0, 1, 0, "c3e76c5c3212190ef65d119c2fb32a7ad882d132ae2a6fa46dad862e614c248b784d0ed55395156c2241f4f621138994"}, +{0, 192, 0, 2, 0, "c3e76c5c3212190ef65d119c2fb32a7afe40ed725adf4710b9a2ddaccf1b16afd2d059c32cb454c00123a9b866792ec3"}, +{0, 192, 0, 2, 1, "e1951c99732cbdf322d03b7646787c1fc362a3d454a671561e015ec5d9b5d44d06e8b2030f190deaf8209f8dcd16740c"}, +{0, 192, 1, 1, 0, "c382106e7ab3ef5080e478db5fe04612148f894034d30b45d3629c7e6419578ea4131f073e9329a4e59e8b7c02063bff"}, +{0, 192, 1, 2, 0, "c382106e7ab3ef5080e478db5fe04612a745edc19f74591b70336e1c579eeb659ab94bf0a2dd2881e97099cf9d28c7a1"}, +{0, 192, 1, 2, 1, "9b8330d29c585ffad7a4c126019252b53b76456d7f405ae5d61f74ef221def32dd11a4a9a28c86660a65c2f5c800b4b9"}, +{0, 192, 2, 1, 0, "1fe2b2b13ca6f7ef41f978cd2452bd7013671c0ccf6f0e2fa96ba4d9de8a1c0ce00f68560deca6293256bc2d650660e6"}, +{0, 192, 2, 2, 0, "1fe2b2b13ca6f7ef41f978cd2452bd70b161fe6f37cfa3c057ab1482572fa7698ea49f0ac29ae458e30ab41539922881"}, +{0, 192, 2, 2, 1, "80d797c4b2c8cf2b2f9b64a963c30727d58bfda5724f2918e00b44477ea5d1c4c71adeb953fd4be98ea68886400eb0b3"}, +{0, 256, 0, 1, 0, "5e6cb0355f8468e4766399778a89323c23f29cb19a6da8b95705f5926f47d4b98a646a2ae41ee5c20b813fb3d71607bb"}, +{0, 256, 0, 2, 0, "5e6cb0355f8468e4766399778a89323ced344ec091c0c22379a21229ea9d2a2108ee728d65225b6dda2eabf49d81b141"}, +{0, 256, 0, 2, 1, "d8dc83de1a1b059f00c35883a4c84673471607354800bffa3d50f55827f51adc1be5e6b267ceeccfa013b1d9291c06d4"}, +{0, 256, 1, 1, 0, "7606084702df4339bf475122cbf4b31c53fc67ee343fb7a9e5f73c24e219025363365234dfa80ec86f773ec7d8a20ffa"}, +{0, 256, 1, 2, 0, "7606084702df4339bf475122cbf4b31c34e93524f55ccb77b3502e0794fedb3889474f14bd95170f2f2d41414ce141e1"}, +{0, 256, 1, 2, 1, "ed890d2d5a92edc2de92fc961cafe11cc6e8f06f043b1d1b351f0029ac5bb79455fb144ae8b67e455b62fcf5e3f08646"}, +{0, 256, 2, 1, 0, "2f918eb6cb6ef5abaf9c4ec1a252d8bf5608b4acc312745aafec20ed35c3709658ea0e59f1829bc5ad40a7d02a9355ec"}, +{0, 256, 2, 2, 0, "2f918eb6cb6ef5abaf9c4ec1a252d8bfefa3fd26c8e7f1140e20741ad78d1213e66c8668fed56d476e68d70deb7475e3"}, +{0, 256, 2, 2, 1, "a33d1269f3258439c66699b56e74c70d0923b38681dafdb3e267f430c0b24e265f89f0eec6cd7daa741bcf84a8de2a1e"}, +{1, 128, 0, 1, 0, "a66cadd6ddc3124cc08b656adafb2ef28dcf41e04fb9f054704642d087730f95c9ccd9daf870b17781cc704b449f9c95"}, +{1, 128, 0, 2, 0, "a66cadd6ddc3124cc08b656adafb2ef292e91ce78c7b8855cd6a102363b7312f1a55fcd9ecf1ed0a27cf068053e2df37"}, +{1, 128, 0, 2, 1, "3ceb8db9364409ff45f3401886be3ca5d9c7cdcf5dcee365597ed8ba583519d1cf4e7e794ee6d4dc1e2acf63e6f59c57"}, +{1, 128, 1, 1, 0, "09c26143b47b1a22ec2d9cd8b8a4e57345bdf2fc71ac91de131a1637428bcb30b7efd846f1f41577be5b5f2b276d985d"}, +{1, 128, 1, 2, 0, "09c26143b47b1a22ec2d9cd8b8a4e573d8211cc753d44527b30e1b2883bf2054ba08ccb2f4f38282f34c51ba7469349a"}, +{1, 128, 1, 2, 1, "830c25c2eab508f0632c5c139d0e8ee5c1ff5bceb454e3327365daa1c4fa6fe94bb89592e3273a771f847c649869b5e1"}, +{1, 128, 2, 1, 0, "99b49d58a5658a2bc103a36a3c02844875d1b1e5b97b427cc2d9cd21674b0f28869d8ff8e665ab625cafdb924fbefaa9"}, +{1, 128, 2, 2, 0, "99b49d58a5658a2bc103a36a3c028448e731e811d640ee3fcc82ab633097b4bf0ae39d6dc1d34bc5ded9f4dc81dddf63"}, +{1, 128, 2, 2, 1, "f7abd936d1c00e06c306da6d1ff9b6b905aae66105eabc5536079d6e225165652408ff39c947467ea8782db882e67598"}, +{1, 192, 0, 1, 0, "774e13bfd3dfe7eee0ac91f19450f83ed32542e94ac79e4e4019be89bab72dda47877e1b483d659bb344c8c2c344d46b"}, +{1, 192, 0, 2, 0, "774e13bfd3dfe7eee0ac91f19450f83ece1953a4d0a3f5f8561a4800d5dbbda255b7d5e0eabe83e2b52ab0b39d7bb76b"}, +{1, 192, 0, 2, 1, "1a0b595c14ee7bb75ff84476f2f7c85cf9864ab4c8c80e77f4fe712ed49b63430856a1e6eebaab28fe9b8b42f3517f9e"}, +{1, 192, 1, 1, 0, "37e13fb5351bd78d3e7912fdc5f80fcd0b69e0e0979704190fd06cc5557d4eb077d8c4498c384c4b322484a3b76c8942"}, +{1, 192, 1, 2, 0, "37e13fb5351bd78d3e7912fdc5f80fcd3e983ea2b5a0b69c5fc05f146e9ffd9a767f46e31e101e84122219cb421d6770"}, +{1, 192, 1, 2, 1, "89be07425819562f6e88942b6d80537d2832cbbd428157a71ec4fc43ceda34b1fd86031175cb42ba4efa247948922bb7"}, +{1, 192, 2, 1, 0, "7dcb01a770302ce1d3510addad7680d5db7b6612d60a9fb2c7c009e6eacec311ca58446d0420a00b6aa6ab75af1117ae"}, +{1, 192, 2, 2, 0, "7dcb01a770302ce1d3510addad7680d55fab253e216a387eaeec750b88af2653c6dd0848060e33d0d6029fa5e74834ed"}, +{1, 192, 2, 2, 1, "881ce8b25f524279bd932ce87e40c32cfa0710cd6f53d48a7e80221a584033560562d16c1586d5b3c4a678fbdc9e6539"}, +{1, 256, 0, 1, 0, "d3cea9ac0401858b1bbb8a1bb5cc3e7a201123559289080ef304f30aeb28b2894f239f896916c4ac6cb2417784a8f1d5"}, +{1, 256, 0, 2, 0, "d3cea9ac0401858b1bbb8a1bb5cc3e7a1539e27f8b1e66efaaaf6e420d2c96d0aa402db41dfaa8bb3b8c2fc10002c6ce"}, +{1, 256, 0, 2, 1, "1c9691e7e4bb8bc00f1947c32fa939911c7ade800c3779c5d426d91e8c44267ab91a0ad9c3217d2ea6b11681ab7e7fb1"}, +{1, 256, 1, 1, 0, "e5c82d388ed59b96ee87e3f48a6e879ee95a6d7cc749a9fba4666a493bf09544bedec6fbb93a47131ef92bf640882863"}, +{1, 256, 1, 2, 0, "e5c82d388ed59b96ee87e3f48a6e879e9d6f6a65aa34cae089709040fa21fcec69cf41364866ac8c73bfa5375ef71d9a"}, +{1, 256, 1, 2, 1, "9341edc00a385760ceb305f3351b107e7dd5a52ce73ea5b84f44167dc5641a93629a9095d33090b2955b3d2cfc417a88"}, +{1, 256, 2, 1, 0, "94bbd7384cdca8a4b5d79c8f6c9d3bdc6d908192729c77414b7352bb1a316bf3c945cbe93575a5cc4a8097f447993ded"}, +{1, 256, 2, 2, 0, "94bbd7384cdca8a4b5d79c8f6c9d3bdc39f408fd644f865d5933afda2cc4742cae291e67ca96f106ce309d42941a36c4"}, +{1, 256, 2, 2, 1, "7f66c150f568fa5f2a1c00d03a63479f7f3fbb4af144227ef521b64f41a5c9cf6d9f21dade72e7e86ff2287926e60474"}, +{2, 128, 0, 1, 0, "c8a331ff8edd3db175e1545dbefb760bf5836e6f7f388e2ab41c8a6faed0f94c5fd79929d55d616998dee86026b4f802"}, +{2, 128, 0, 2, 0, "c8a331ff8edd3db175e1545dbefb760b45c2286b7ba92776bc1177203616314d06fa37c469aeab37ef943e78b59784e2"}, +{2, 128, 0, 2, 1, "e6d598af6b41465134d30303171d1780949c77942ff846279f87478249eca090336b181b89e983c3022fe075064439ad"}, +{2, 128, 1, 1, 0, "69c4e0d86a7b0430d8cdb78070b4c55a000648a951ca51d04fd755fe200e700f12c4f1789bf09ef5c791c5437f37f98b"}, +{2, 128, 1, 2, 0, "69c4e0d86a7b0430d8cdb78070b4c55af0fcd0fafc2c2b0e318b3ffcc2682d39607b35293a46d5b3eb4dc2ba58d98f07"}, +{2, 128, 1, 2, 1, "16628846f7334843bc7321cc79661680adec66f5855d645098db263f733bc28ae50995ab659f20a1917a09ba29f88270"}, +{2, 128, 2, 1, 0, "8df4e9aac5c7573a27d8d055d6e4d64b3f76cf6551e0b115858ab0170e2d3459e9ad6771522a6a391c6d5c5c95dc8bfc"}, +{2, 128, 2, 2, 0, "8df4e9aac5c7573a27d8d055d6e4d64b3fbbaea608a6c77265b33d3b7c954ceba016d976c65b9c32317f0f78fa3374d9"}, +{2, 128, 2, 2, 1, "15440d3c83995b30aa8340cb0d1433f1fdc484cf0c7a4d2115b4196977dd89b638071b7f26bd088d9ed2c2d2543b7c57"}, +{2, 192, 0, 1, 0, "4e95298c89bc57c77d2d39912f323996ead6ae5d7532d4ac32c3e7987308d3d37077ff0b72bb1689eafb176da8d96a93"}, +{2, 192, 0, 2, 0, "4e95298c89bc57c77d2d39912f3239964dd263baeac4cdede1b281c5c2c98b74c4166a512f339a9178316003046dca74"}, +{2, 192, 0, 2, 1, "ce772c17066f77c04c28fef40b4f84eb3195d0c10ea28941e9d7d444897bf089aea4d0c9de6c8f0b3fdb2514099a069e"}, +{2, 192, 1, 1, 0, "dda97ca4864cdfe06eaf70a0ec0d7191beb545f8c56b5576e377c9f3c2b8ed539219541e668bd56fe24a058800599b43"}, +{2, 192, 1, 2, 0, "dda97ca4864cdfe06eaf70a0ec0d719150de3e940180c3a5b430ae10ed2bb51c4815f551359b6d5e83c2c05e870c716d"}, +{2, 192, 1, 2, 1, "6bbbc6dfcca3de831587b4208f20da1c06829a0fdb08b5521c39e463f8aa5c05282a6f5f1635873e658a25a318d53d84"}, +{2, 192, 2, 1, 0, "bf8d8b2f6d7d82729bbeb8ad41f1de7667027354a95c11a48b9f8f9d5a2506df4ac231038529eb317c50d1a3415d35c5"}, +{2, 192, 2, 2, 0, "bf8d8b2f6d7d82729bbeb8ad41f1de76347dcb1df6fcd3bd65d6336dad65b9cda7ced9c0db901ddf7c1bacadb8f150f3"}, +{2, 192, 2, 2, 1, "6e3b72c607dc92803c781263a56a718e2142045d3e6a5c9b16ee31d3aa923651597a718e512c587b2a51a1720ef0e3f7"}, +{2, 256, 0, 1, 0, "1c060f4c9e7ea8d6ca961a2d64c05c18bb78b28d030105a7bcaca9772ee49b1a70f7af2b633fa2096493a02582fa1b77"}, +{2, 256, 0, 2, 0, "1c060f4c9e7ea8d6ca961a2d64c05c18bc6aca1b4526465e9479ca757ea5cf6e7d043349815bd9cbbbcd397325aaeb3b"}, +{2, 256, 0, 2, 1, "595c6d7b3042a47f04006fee4c8c9c8a37309dc59b431344e9f38831b0ba2614fe5e9648ea5c452bd841d7f4d7fb6054"}, +{2, 256, 1, 1, 0, "8ea2b7ca516745bfeafc49904b496089acac7b5f2614c2a0e6ea9d1339f4031cf48a8a6159e6b7b94cbac9176ecce557"}, +{2, 256, 1, 2, 0, "8ea2b7ca516745bfeafc49904b4960890e4795e4d482e8321ace5c9d027c2f878f43ac59c5c2f036a807e1a172b6590b"}, +{2, 256, 1, 2, 1, "5619ba42f9b3e67661562c2dd0a5eddcbc13c078a84e401d93f7bbd43392d24e096ed6b4dcf2582d10f66197524b2db1"}, +{2, 256, 2, 1, 0, "ba278e3ebc953c3d4f97fdcd888a4e3ad20aca8328c28141d7a6688d98c895c7ba3e7bad833c31d2c254d56addf5b381"}, +{2, 256, 2, 2, 0, "ba278e3ebc953c3d4f97fdcd888a4e3a5ece20406d09195d5c7d02033f5022adea90d333352f70b56aad801646f591bd"}, +{2, 256, 2, 2, 1, "b5f1c946bc883f840ce8f6981621ccda7f57f08b9d6654de68fe092d4ead8ae4e7f86b101e266a051c36d68ccea5fd66"}, +{3, 128, 0, 1, 0, "a0ebe0b0021003ba26f95f1affca8ecfa69c216e11f57d58644302c05ca00257fd6eba1591f1f67702ffeea8dfd4f33e"}, +{3, 128, 0, 2, 0, "a0ebe0b0021003ba26f95f1affca8ecfc2332262eb614d44dd70eef348126971cdbe7a689af34f57f1790dcaa2ea9dc2"}, +{3, 128, 0, 2, 1, "987ca7c669ab26b34dbb8cce21b5c55a3487db10370b37b69e2455f71a6ff4fdda4555ab8422d28326a6c2195a65ec42"}, +{3, 128, 1, 1, 0, "558ecdc6e695b513e8f9cecc19787a051cd52edfd7c8ecb1c50dc0a4275f8714b4dccfb4278ca3f36338c996bab3b0af"}, +{3, 128, 1, 2, 0, "558ecdc6e695b513e8f9cecc19787a05c26ae478275f1833440b500467c9158988f1c834dacbbc51c9d15518992758ac"}, +{3, 128, 1, 2, 1, "c587ed2e181495dbe3272452414d0ca5d1210a4560c5e5b1f3ba9e804ef66a39b4817f9abe862e6ebf38e7a443ab7c1e"}, +{3, 128, 2, 1, 0, "a4a58521df02ccb23e2cabc9d08c84f59905241b47bd0fda96536933beea9cd42dc8f75fef7fbed4ae4efd7775fa41ad"}, +{3, 128, 2, 2, 0, "a4a58521df02ccb23e2cabc9d08c84f58c8fa8e31ef6d126a05b2f098c81ec872c72a1e53154fdf47798c2c88d77fbf2"}, +{3, 128, 2, 2, 1, "c7ec637eec09d7ec95c26fa1afe571de6ef387ad4720017536556b787dabe7291541c0080b02d9e5d98388c8db699d22"}, +{3, 192, 0, 1, 0, "e532aebb2793497afc40efb832f4d14fd1437293478201f524a69021db27f493de43a77365b7f99e493005ea83f3f074"}, +{3, 192, 0, 2, 0, "e532aebb2793497afc40efb832f4d14f6b9c66c74e59e8720c108f4c08c13eb9a8ff5ade351d74d171a7d4b4080d739d"}, +{3, 192, 0, 2, 1, "889bb1ed62eb07780c53cd01034f957ac4644135bcafd6708349477eaa93d2541384ab80c1b077b04554f33423c9e496"}, +{3, 192, 1, 1, 0, "ce30c25d8a92c0f26700938e79f50061962facf5367b20637fb0b82184556a92163980b724b087092ebeaea8cad45105"}, +{3, 192, 1, 2, 0, "ce30c25d8a92c0f26700938e79f50061c29253fd5bf0821c732d405e8cec29574c9d29682e1dd7d3cecdb339018c7bd8"}, +{3, 192, 1, 2, 1, "4bce85d457dec628a3462d19335fc55ae9ec5c89a34a0b9b8553ebf48ae223cd62a3cb149b76a26eee56293f57037d25"}, +{3, 192, 2, 1, 0, "9ad0a6190e3594a0309a77b586d88260bdff8a31db11f9b6d737709932e62fd83695c0b659701f2d807876915e268b2b"}, +{3, 192, 2, 2, 0, "9ad0a6190e3594a0309a77b586d8826044c4b9f399881bd854c794e95e1703d4c1ad150f99b1e35e6b8f7d2e765ee51a"}, +{3, 192, 2, 2, 1, "7a73983ce00f9e27c8aea0d29466b72b6e830ab4423999f0b060d75d7f419a6be63a8a0629adbae64abb22350c2700a9"}, +{3, 256, 0, 1, 0, "885113854d880f7f63c55203be74ab111e8d2333916b23f78e90f2f1d9ddaafd8d81cf8af04ff6235b406b6e16fd5a84"}, +{3, 256, 0, 2, 0, "885113854d880f7f63c55203be74ab1141f651283666b742c6a927014fa463a1377baf9c1bd37698550aa60e5ff4785c"}, +{3, 256, 0, 2, 1, "e7d1a3fcc9e092d62e32251bb873ac0ab6139091584c043d79830cd23a9342b84365755b3b23d3d5aeca7834541d3c84"}, +{3, 256, 1, 1, 0, "9234ed5ee16f79702bcda836ccee6467581e8d1bcce3562a821143efe568c5562cde3d2ff2ae31c4b364af2956e3c297"}, +{3, 256, 1, 2, 0, "9234ed5ee16f79702bcda836ccee646722d9953597a850d7d29274419e34fed8094080c0017b581dee4367a53ee12f30"}, +{3, 256, 1, 2, 1, "c1cc23e1c3c932b284c2b5178649084a54b798307582b71f9c75e78745833fef15d2d5c24a758b94c228d3d893d1c1e7"}, +{3, 256, 2, 1, 0, "0d5eb3ced45e39e4a8513b807ece5e46d313a366b4cedda126bc609c9a80b076b52a859dbd39435a58819680fe5806f8"}, +{3, 256, 2, 2, 0, "0d5eb3ced45e39e4a8513b807ece5e46547543b057111485f1f4370b3d4068dd7223a9ca6473e2fbedb838818e80ba8d"}, +{3, 256, 2, 2, 1, "f66b7dfb4ca74e74ea504e3d8c48b745cac32103e2dd56161f5d1c903d15082627794e335f2fbb8c889691e5fbd7afcc"}, +{4, 128, 0, 1, 0, "1242fae0702a08d0903708274a6831d738e595ce6f8384e0fd1eb8d1ad9e0f871b01f4c6d7377ef927cec0cb4b35d05b"}, +{4, 128, 0, 2, 0, "1242fae0702a08d0903708274a6831d76e2e8e7110c307ef274d18d00d166c5e3bdaa5bc2fc872d620fa0213794d9888"}, +{4, 128, 0, 2, 1, "85d9bba9db455f8b595fde9cea1da516481b9c2fca05763a9bdc33e4dde6e403673ff5645a08d7538785742eb3d50f62"}, +{4, 128, 1, 1, 0, "df8451d26e0504bc19b0a93b049e32037859fdb49198a016ee32a36e42439ff5cd9099f11757929bd54c2680637e49fa"}, +{4, 128, 1, 2, 0, "df8451d26e0504bc19b0a93b049e3203448156171e31596fc814c715b087271351e95d20a9988fe87b48440af32dcb55"}, +{4, 128, 1, 2, 1, "712fa33a40d43cc016f42fd72beb5ea9fc34c10a66b9bc8e85c57a5b87da30f625e661e660a98fc7ce705d9f06a3595e"}, +{4, 128, 2, 1, 0, "90f649d14f6f06c9d9160741813102b0bb181dd35c2ebd765124a39fd05a5f70a4a06e4f5d93bc82d712dafab8d6ea80"}, +{4, 128, 2, 2, 0, "90f649d14f6f06c9d9160741813102b04ad3d9a42a0fa1b4cb0f1150446eab87cef255fd21df6fe05e5ae55559f13d34"}, +{4, 128, 2, 2, 1, "07140dac1c3f5e7ea4cb95c35f2f1b565860d144a796f1b0d21f69126d507e357ad901011dd8b2c8c90578298eb7014d"}, +{4, 192, 0, 1, 0, "c8ca75770da7d806a22cffdb42cf8c74e5db5a633d54556827d111c39913aba33a05a625713e354e5bc0ffc1a77e6dc0"}, +{4, 192, 0, 2, 0, "c8ca75770da7d806a22cffdb42cf8c742bd883094858799022d405e8a4a261d804649fbef61d9cf6aad78b7c2d23a988"}, +{4, 192, 0, 2, 1, "1355610c89436c92f8e3e7080233856cf8044c6f5f755971b65b45fced0ff6dc51600af79397061054458677b47e6d12"}, +{4, 192, 1, 1, 0, "4afc654ce45e2e65d6716b8c6057c4f273113158a54d9cd6906f4a7c3a73c345e963e0b6e0dbd75c0abbd692ebbb655a"}, +{4, 192, 1, 2, 0, "4afc654ce45e2e65d6716b8c6057c4f2145db0606241f9a200997cce93839b2a5503269f20d0c584cc8475455e12787b"}, +{4, 192, 1, 2, 1, "e6307152f4e819360b4ebb0846f7bc2c3990356331a1119442c43323ef5c069596cb90356fc51fb24f92c935a980df31"}, +{4, 192, 2, 1, 0, "9e6f8b421425c38e33b20f6577539f842226d901626ace3ea1e63b7e19ffff66a1413b1c186f41c87df300255beb719c"}, +{4, 192, 2, 2, 0, "9e6f8b421425c38e33b20f6577539f84717aeddad8471de0043bd421619a8efea22508cf6a24b92376bf3618d4ff6148"}, +{4, 192, 2, 2, 1, "137e0d63a8626bd3c3eae9a58776e2ce3432b160b0f4e5cf53a94dc279f8f0a258878ed06332622f279a39b63e7ee38a"}, +{4, 256, 0, 1, 0, "368299949395960232ddf30029ef81b782977794ca94e480b3ddfa353aed6d134c5cd5e39752b4aadc6134709f09b13c"}, +{4, 256, 0, 2, 0, "368299949395960232ddf30029ef81b7887f757785c9f93796d66e45e52e3fa66021f3aec038ba9a14d03c04797f3db2"}, +{4, 256, 0, 2, 1, "419e4caf5764148b0d20c08da31b794953c4de670c4173a08b4ad45f799f07ecc9bd557e393807d1a7aade0ba76f1198"}, +{4, 256, 1, 1, 0, "b7b5fb57ec446a11cbb7e6292342537bfe179d2ce1129b30f50bf3252768b320f3696fc71a974fc784e54dcd804d4f1e"}, +{4, 256, 1, 2, 0, "b7b5fb57ec446a11cbb7e6292342537b6394fcf46308a311d5b15c3d5ae4ece8d1cb4daa2ed3b9c648bb2b81b1485f97"}, +{4, 256, 1, 2, 1, "8081a241a136739c003a34cd89e6d691923fbb551167755ad09a9f91e69a7d71028aea5c1458184bf299a6edada818e4"}, +{4, 256, 2, 1, 0, "3d14842ba23845ffb3dd2e8b275ea4335d4466f7344a810cd43acb85703da70d4b10749a61de31167269e78b51522e26"}, +{4, 256, 2, 2, 0, "3d14842ba23845ffb3dd2e8b275ea4338060c0f22958e3eed0d636649ae33207b05fb492bcda258e5a1152faa7c31e28"}, +{4, 256, 2, 2, 1, "9e88e57cda70899d4d922d49f0452d12f89e39bda9c4cb9fd8c8c8aaa18abd4d1b383a16b14736d728d5168d0924cd60"}, diff --git a/port/thirdparty/tests/test_analyse.cpp b/port/thirdparty/tests/test_analyse.cpp new file mode 100644 index 000000000..3a98d506f --- /dev/null +++ b/port/thirdparty/tests/test_analyse.cpp @@ -0,0 +1,88 @@ +#include "libanalyse/la_string.h" +#include "libanalyse/analyse.h" +#include "libanalyse/Des.h" + +#include +#include +#include +#include +#include + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +static std::string written(const SymbolArray &a) { + std::ostringstream os; + a.Write(os); + return os.str(); +} + +int main() { + String s("Krypto"); + s += "Tool"; + CHECK(s.length() == 10); + CHECK(std::strcmp(upcase(s).chars(), "KRYPTOTOOL") == 0); + CHECK(s.index("Tool") == 6); + CHECK(std::strcmp(common_prefix(s, String("Kryptologie")).chars(), "Krypto") == 0); + + AppConverter conv; + char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + conv.SetAlphabet(alphabet, 1); + CHECK(conv.IsInAlphabet('a') && conv.IsInAlphabet('Z') && !conv.IsInAlphabet('1')); + + SymbolArray text(conv); + text.ReadString("Hello, World!"); + CHECK(text.GetSize() == 10); + CHECK(written(text) == "HELLOWORLD"); + + SymbolArray key(conv); + key.ReadString("D"); + text += key; + CHECK(written(text) == "KHOORZRUOG"); + text -= key; + CHECK(written(text) == "HELLOWORLD"); + + SymbolArray vkey(conv); + vkey.ReadString("KEY"); + text += vkey; + CHECK(written(text) == "RIJVSUYVJN"); + text -= vkey; + CHECK(written(text) == "HELLOWORLD"); + + SymbolArray every2 = text.Extract(0, 2); + CHECK(written(every2) == "HLOOL"); + + SymbolArray sample(conv); + sample.ReadString("ABABABABABABABABABAB"); + NGram ng(sample); + CHECK(std::fabs(ng.Entropie() - 1.0) < 1e-9); + CHECK(std::fabs(ng.Koinzidenz() - 0.5) < 0.05); + + std::ostringstream shown; + { + OStream out(shown); + ng.Show(out << OStream::Title(0) << OStream::Description(0) << OStream::Summary(0)); + } + CHECK(!shown.str().empty()); + + DES des(0x13345779UL, 0x9BBCDFF1UL); + SimpleArray block; + block[0] = 0x01234567UL; + block[1] = 0x89ABCDEFUL; + des(block, Cipher::Encrypt); + CHECK(block[0] == 0x85E81354UL && block[1] == 0x0F0AB405UL); + des(block, Cipher::Decrypt); + CHECK(block[0] == 0x01234567UL && block[1] == 0x89ABCDEFUL); + + if (failures == 0) + std::printf("libanalyse: all checks passed\n"); + return failures == 0 ? 0 : 1; +} diff --git a/port/thirdparty/tests/test_apfloat.cpp b/port/thirdparty/tests/test_apfloat.cpp new file mode 100644 index 000000000..3f1867a73 --- /dev/null +++ b/port/thirdparty/tests/test_apfloat.cpp @@ -0,0 +1,129 @@ +// Smoke test for apfloat_compat, following CrypTool's DlgComputeMersenneNumbers usage. +#include "ap.h" +#include "apint.h" + +#include +#include +#include +#include +#include + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +struct MersenneNumberComputationParameters { + apint base; + unsigned long exponent; + std::string result; +} params; + +static unsigned computeMersenneNumber(void *_parameters) { + MersenneNumberComputationParameters *parameters = (MersenneNumberComputationParameters *)(_parameters); + apbase(10); + apint base = parameters->base; + unsigned long exp = parameters->exponent; + apint r = base; + int b2pow = 0; + if (!exp) return 1; + while (!(exp & 1)) { + b2pow++; + exp >>= 1; + } + while (exp >>= 1) { + base *= base; + if (exp & 1) r *= base; + } + while (b2pow--) { + r *= r; + } + apint result = r - 1; + std::ostringstream buffer; + buffer << result; + parameters->result = buffer.str(); + return 0; +} + +static std::string mersenne(const char *base, unsigned long exponent) { + params.base = (char *)base; + params.exponent = strtoul(std::to_string(exponent).c_str(), NULL, 10); + params.result = ""; + std::thread worker(computeMersenneNumber, (void *)¶ms); + worker.join(); + return params.result; +} + +static std::string str(const apint &x) { + std::ostringstream os; + os << x; + return os.str(); +} + +int main() { + CHECK(apinit()); + + CHECK(mersenne("2", 127) == "170141183460469231731687303715884105727"); + CHECK(mersenne("2", 10) == "1023"); + CHECK(mersenne("3", 4) == "80"); + CHECK(mersenne("10", 1) == "9"); + std::string m521 = mersenne("2", 521); + CHECK(m521.size() == 157); + CHECK(m521.substr(0, 10) == "6864797660" && m521.substr(147) == "1115057151"); + std::string m44497 = mersenne("2", 44497); + CHECK(m44497.size() == 13395); + CHECK(m44497.substr(0, 12) == "854509824303" && m44497.substr(13395 - 12) == "961011228671"); + + apint a = 1; + a <<= 127; + a -= 1; + apbase(16); + CHECK(str(a) == "7fffffffffffffffffffffffffffffff"); + apint h = (char *)"ff"; + CHECK(h == 255); + apbase(2); + CHECK(str(apint(10)) == "1010"); + apbase(10); + + CHECK(str(apint()) == "0"); + CHECK(str(-apint(42)) == "-42"); + CHECK(str(apint("1.5e3")) == "1500"); + CHECK(str(apint("-1.5")) == "-2"); + CHECK(str(apint(-2.5)) == "-3"); + CHECK(str(apint(" +123456789012345678901234567890")) == "123456789012345678901234567890"); + CHECK(str(apint(-7) / 2) == "-3"); + CHECK(str(apint(-7) % 2) == "-1"); + CHECK(str(100 - apint(1)) == "99"); + CHECK(str(apint(1LL << 40) * 3u) == "3298534883328"); + CHECK(str(apint(-(1LL << 62))) == "-4611686018427387904"); + CHECK(str(apint(~0ULL)) == "18446744073709551615"); + CHECK(apint(5) > 4 && 4 < apint(5) && apint(5) >= 5.0 && apint(5) != 4.5); + CHECK(pow(apint(3), 5) == 243); + CHECK(powmod(apint(3), apint(200), apint(1000)) == 1); + CHECK(gcd(apint(84), apint(36)) == 12 && lcm(apint(4), apint(6)) == 12); + apdiv_t qr = div(apint(17), apint(5)); + CHECK(qr.quot == 3 && qr.rem == 2); + CHECK(abs(apint(-9)) == 9); + apint i = 5; + CHECK((i++) == 5 && i == 6 && (--i) == 5); + + std::istringstream in("31415926535897932384626"); + apint parsed; + in >> parsed; + CHECK(str(parsed) == "31415926535897932384626"); + + apdeinit(); + + if (failures) { + std::fprintf(stderr, "%d check(s) failed\n", failures); + return 1; + } + std::printf("test_apfloat: OK (2^127-1 = %s)\n", mersenne("2", 127).c_str()); + return 0; +} diff --git a/port/thirdparty/tests/test_cracklib.cpp b/port/thirdparty/tests/test_cracklib.cpp new file mode 100644 index 000000000..bc4445d81 --- /dev/null +++ b/port/thirdparty/tests/test_cracklib.cpp @@ -0,0 +1,115 @@ +// Smoke test for cryptool_cracklib using CrypTool's own declarations (passwordchecker.h). +#include +#include +#include +#include + +#define STRINGSIZE 1024 +#define NUMWORDS 16 +#define MAXWORDLEN 32 + +struct pi_header { + unsigned long int pih_magic; + unsigned long int pih_numwords; + unsigned short int pih_blocklen; + unsigned short int pih_pad; +}; + +struct PWDICT { + FILE *ifp; + FILE *dfp; + FILE *wfp; + unsigned long int flags; + unsigned long int hwms[256]; + struct pi_header header; + int count; + char data[NUMWORDS][MAXWORDLEN]; +}; + +#define PW_WORDS(x) ((x)->header.pih_numwords) + +extern "C" { + unsigned long int FindPW(PWDICT *pwp, char *password); + int PMatch(char *pattern, char *password); + char *Trim(char *password); + int PWClose(PWDICT *pwp); + PWDICT *PWOpen(char *prefix, char *mode); + + void ct_cracklib_layout(size_t *size, size_t *numwords_offset, size_t *count_offset); + char *ct_cracklib_getpw(PWDICT *pwp, unsigned long number); + char *ct_cracklib_fascistcheck(char *password, char *path); +} + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +static bool inDictionary(PWDICT *pwp, const char *word) { + char buf[STRINGSIZE]; + std::snprintf(buf, sizeof buf, "%s", word); + return FindPW(pwp, buf) != PW_WORDS(pwp); +} + +int main() { + size_t libSize = 0, libNumwordsOffset = 0, libCountOffset = 0; + ct_cracklib_layout(&libSize, &libNumwordsOffset, &libCountOffset); + CHECK(libSize == sizeof(PWDICT)); + CHECK(libNumwordsOffset == offsetof(PWDICT, header.pih_numwords)); + CHECK(libCountOffset == offsetof(PWDICT, count)); + + char path[STRINGSIZE]; + std::snprintf(path, sizeof path, "%s", CT_CRACKLIB_DICT); + char mode[] = "r"; + PWDICT *pwp = PWOpen(path, mode); + CHECK(pwp != nullptr); + if (!pwp) return 1; + + CHECK(pwp->header.pih_magic == 0x70775631UL); + CHECK(PW_WORDS(pwp) == 1648594UL); + CHECK(pwp->header.pih_blocklen == NUMWORDS); + CHECK(pwp->flags & 0x0004); + + CHECK(inDictionary(pwp, "password")); + CHECK(inDictionary(pwp, "dragon")); + CHECK(inDictionary(pwp, "letmein")); + CHECK(!inDictionary(pwp, "xq7#Zr!pW2vK")); + + char word[] = "dragon"; + unsigned long idx = FindPW(pwp, word); + CHECK(idx < PW_WORDS(pwp)); + const char *back = ct_cracklib_getpw(pwp, idx); + CHECK(back != nullptr && std::strcmp(back, "dragon") == 0); + const char *last = ct_cracklib_getpw(pwp, PW_WORDS(pwp) - 1); + CHECK(last != nullptr && last[0] != '\0'); + + char pattern[] = "aadddddda"; + char ni[] = "ab123456c"; + CHECK(PMatch(pattern, ni) == 1); + char padded[] = " word "; + Trim(padded); + CHECK(std::strcmp(padded, " word") == 0); + + CHECK(PWClose(pwp) == 0); + + char weak[] = "password"; + char strong[] = "xq7#Zr!pW2vK"; + const char *weakReason = ct_cracklib_fascistcheck(weak, path); + const char *strongReason = ct_cracklib_fascistcheck(strong, path); + CHECK(weakReason != nullptr); + CHECK(strongReason == nullptr); + + if (failures) { + std::fprintf(stderr, "%d check(s) failed\n", failures); + return 1; + } + std::printf("test_cracklib: OK (%lu words, \"password\" -> %s)\n", 1648594UL, + weakReason ? weakReason : "(null)"); + return 0; +} diff --git a/port/thirdparty/tests/test_cracklib_layout.c b/port/thirdparty/tests/test_cracklib_layout.c new file mode 100644 index 000000000..9bda37dc2 --- /dev/null +++ b/port/thirdparty/tests/test_cracklib_layout.c @@ -0,0 +1,20 @@ +/* Reports the PWDICT layout as seen by the cracklib sources. */ +#include +#include CT_CRACKLIB_PACKER_H + +void ct_cracklib_layout(size_t *size, size_t *numwords_offset, size_t *count_offset) +{ + *size = sizeof(PWDICT); + *numwords_offset = offsetof(PWDICT, header.pih_numwords); + *count_offset = offsetof(PWDICT, count); +} + +char *ct_cracklib_getpw(PWDICT *pwp, unsigned long number) +{ + return GetPW(pwp, (int32) number); +} + +char *ct_cracklib_fascistcheck(char *password, char *path) +{ + return FascistCheck(password, path); +} diff --git a/port/thirdparty/tests/test_cvact.cpp b/port/thirdparty/tests/test_cvact.cpp new file mode 100644 index 000000000..8098eb46e --- /dev/null +++ b/port/thirdparty/tests/test_cvact.cpp @@ -0,0 +1,435 @@ +// Smoke test for cvact_compat: mirrors the call sequence of CrypTool/ECIESMain.cpp. +#include "actInit.h" +#include "actAlgorithm.h" +#include "actTools.h" +#include "actDate.h" +#include "actIRNGAlg.h" +#include "actException.h" +#include "actKey.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace act +{ + namespace detail + { + Blob X963Kdf(const char *digest, const Blob &secret, const Blob &sharedInfo, size_t len); + bool CurveFallbackMatches(int id); + } +} + +static int g_failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, #cond); \ + ++g_failures; \ + } \ + } while (0) + +static std::string Hex(const act::Blob &b) +{ + std::string s(b.size() * 2 + 1, '\0'); + act::blob2hex(b, &s[0]); + s.resize(b.size() * 2); + return s; +} + +// Mimics the strings CrypTool obtains from libec: "0X" with the X lowered to x. +static std::string CrypToolNumber(const act::Blob &twosComplement) +{ + std::string h = Hex(twosComplement); + size_t nz = h.find_first_not_of('0'); + h = nz == std::string::npos ? "0" : h.substr(nz); + for (size_t i = 0; i < h.size(); ++i) + h[i] = static_cast(std::toupper(static_cast(h[i]))); + return "0x" + h; +} + +static int importKey(act::Key &key, int curve, const char *x, const char *y, const char *s) +{ + try + { + key.SetParam(act::CURVE, curve); + if (std::string(s) != "") + key.SetParam(act::PRIVATEKEY, s); + else + { + key.SetParam(act::PUBLIC_X, x); + key.SetParam(act::PUBLIC_Y, y); + } + return 0; + } + catch (act::InvalidKeyException &) + { + return 2; + } + catch (act::Exception &) + { + return 2; + } +} + +static bool encryptSessionKey(const act::Key &pubRecECIES, const act::Key &privSendECIES, + const act::Blob &sessionKey, act::Blob &encryptedSessionKey) +{ + try + { + act::Blob publicBlob; + pubRecECIES.Export(publicBlob, act::PUBLIC); + act::Algorithm Encrypt(privSendECIES, act::ENCRYPT, publicBlob); + Encrypt.Write(sessionKey); + Encrypt.Finalize(); + Encrypt.Read(encryptedSessionKey); + return true; + } + catch (act::Exception &e) + { + std::cerr << "Exception: " << typeid(e).name() << " what: " << e.what() << " where: " << e.where() << "\n"; + return false; + } +} + +static int decryptSessionKey(const act::Key &privRecECIES, const act::Blob &encryptedSessionKey, act::Blob &sessionKey) +{ + try + { + act::Algorithm Decrypt(privRecECIES, act::DECRYPT); + Decrypt.Write(encryptedSessionKey); + Decrypt.Finalize(); + Decrypt.Read(sessionKey); + return 0; + } + catch (act::Exception &) + { + return 42; + } +} + +static bool encryptData(const act::Blob &plaintext, act::Blob &sessionKey, act::Blob &ciphertext) +{ + try + { + act::Key blockCipher("BlockCipher"); + blockCipher.SetParam(act::CIPHER, "AES"); + blockCipher.SetParam(act::BCMODE, "CBC"); + blockCipher.SetParam(act::KEYSIZE, 32); + act::Blob salt; + act::Algorithm saltGen(act::CreateBBS()); + saltGen.Write(act::Date()); + saltGen.Read(salt, 256); + + blockCipher.Derive(plaintext, salt); + salt.clear(); + blockCipher.GetParam(act::RAWKEY, sessionKey); + + act::Algorithm encrypt(blockCipher, act::ENCRYPT); + encrypt.Write(plaintext); + encrypt.Finalize(); + encrypt.Read(ciphertext); + return true; + } + catch (act::Exception &e) + { + std::cerr << "Exception: " << typeid(e).name() << " what: " << e.what() << " where: " << e.where() << "\n"; + return false; + } +} + +static int decryptData(const act::Blob &ciphertext, const act::Blob &sessionKey, act::Blob &plaintext) +{ + try + { + act::Key blockCipher("BlockCipher"); + blockCipher.SetParam(act::CIPHER, "AES"); + blockCipher.SetParam(act::BCMODE, "CBC"); + blockCipher.SetParam(act::RAWKEY, sessionKey); + + act::Algorithm decrypt(blockCipher, act::DECRYPT); + decrypt.Write(ciphertext); + decrypt.Finalize(); + decrypt.Read(plaintext); + return 0; + } + catch (act::Exception &) + { + return 5; + } +} + +// Same Blob manipulations as writeEncFile()/readEncFile() in ECIESMain.cpp. +static act::Blob writeEncFile(const act::Blob &encryptedSessionKey, const act::Blob &ciphertext, size_t &keyStart) +{ + std::ostringstream header; + header << "Receiver:Bob, Test|Curve ID:EC-prime256v1|Length of the ECIES encrypted AES session key:" + << encryptedSessionKey.size() << "Byte|Ciphertext length:" << ciphertext.size() + << "Byte|ECIES encrypted AES session key:"; + std::string message = header.str(); + act::Blob output(message.c_str()); + keyStart = output.size(); + output.insert(output.end(), encryptedSessionKey.begin(), encryptedSessionKey.end()); + act::Blob header07("|AES ciphertext:"); + output.insert(output.end(), header07.begin(), header07.end()); + header07.clear(); + output.insert(output.end(), ciphertext.begin(), ciphertext.end()); + return output; +} + +static bool readEncFile(const act::Blob &input, size_t keyStart, size_t keyLength, size_t ctStart, + act::Blob &encryptedSessionKey, act::Blob &ciphertext) +{ + act::Blob in(input); + std::string message = reinterpret_cast(&in[0]); + act::Blob key; + act::Blob ctext; + key.insert(key.begin(), &in[keyStart], &in[keyStart + keyLength]); + ctext.insert(ctext.begin(), &in[ctStart], &in[in.size()]); + encryptedSessionKey = key; + ciphertext = ctext; + return !message.empty(); +} + +static void TestBlobAndTools() +{ + act::Blob a("hello"); + CHECK(a.size() == 5); + CHECK(a[a.size()] == 0); + CHECK(std::strcmp(reinterpret_cast(&a[0]), "hello") == 0); + act::Blob empty; + CHECK(empty.empty() && reinterpret_cast(&empty[0])[0] == '\0'); + std::string s("world"); + act::Blob w(s); + a.insert(a.end(), w.begin(), w.end()); + CHECK(a == act::Blob("helloworld")); + a.insert(a.begin() + 5, a.begin(), a.begin() + 5); + CHECK(a == act::Blob("hellohelloworld")); + a.erase(a.begin(), a.begin() + 5); + CHECK(a == act::Blob("helloworld")); + a.resize(3); + CHECK(a == act::Blob("hel") && a[3] == 0); + CHECK(act::Blob("abc") < act::Blob("abd") && act::Blob("ab") < act::Blob("abc")); + act::Blob filled(4, 0xab); + CHECK(filled.size() == 4 && filled[3] == 0xab); + bool threw = false; + try { filled.at(4); } catch (act::OutOfRangeException &) { threw = true; } + CHECK(threw); + std::ostringstream os; + os << act::hex2blob("0x00ff10"); + CHECK(os.str() == "00ff10"); + + act::Blob h = act::hex2blob("0xDEADbeef01"); + CHECK(h.size() == 5 && h[0] == 0xde && h[4] == 0x01); + CHECK(Hex(h) == "deadbeef01"); + CHECK(Hex(act::hex2blob("abc")) == "0abc"); + + CHECK(Hex(act::EncodeNumber("128")) == "0080"); + CHECK(Hex(act::EncodeNumber("-128")) == "80"); + CHECK(Hex(act::EncodeNumber("-129")) == "ff7f"); + CHECK(Hex(act::EncodeNumber("0x7f")) == "7f"); + CHECK(Hex(act::EncodeNumber(0)) == "00"); + CHECK(Hex(act::EncodeOID("0.2.262.1.10.1.3.8")) == "028206010a010308"); + CHECK(Hex(act::EncodeOID("1.2.840.10045.2.1")) == "2a8648ce3d0201"); + + act::Blob check("123456789"); + CHECK(act::CalculateCRC32(check) == 0xCBF43926UL); + CHECK(act::CalculateCRC16(check) == 0xBB3DUL); + CHECK(act::CalculateCRC16CCITT(check) == 0x29B1UL); + + act::Date d(31, 1, 2024, 23, 59, 30); + CHECK(Hex(d.Encode()) == Hex(act::Blob("\x17\x0d" "240131235930Z"))); + act::Date d2(d.Encode()); + CHECK(d2 == d); + d2.AddMonths(1); + CHECK(d2.GetMonth() == 2 && d2.GetDay() == 29); + d2.AddSecond(31); + CHECK(d2.GetDay() == 1 && d2.GetMonth() == 3 && d2.GetHour() == 0 && d2.GetMinute() == 0 && d2.GetSecond() == 1); + CHECK(act::Date(1, 1, 2000).DayOfWeek() == 6); + act::Blob now = act::Date(); + CHECK(now.size() == 15 && now[0] == 0x17); +} + +static void TestKdfVectors() +{ + // NIST CAVP SP 800-135 ANSI X9.63 KDF vectors. + CHECK(Hex(act::detail::X963Kdf("SHA1", act::hex2blob("1c7d7b5f0597b03d06a018466ed1a93e30ed4b04dc64ccdd"), + act::Blob(), 16)) == "bf71dffd8f4d99223936beb46fee8ccc"); + CHECK(Hex(act::detail::X963Kdf("SHA256", act::hex2blob("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08"), + act::Blob(), 16)) == "443024c3dae66b95e6f5670601558f71"); +} + +static void TestKnownAnswer() +{ + // NIST CAVP ECC CDH P-256 vector #0 used as sender (ephemeral) key and recipient key; + // the expected ciphertext was computed independently (SHA-1 X9.63 KDF over R || Z, HMAC-SHA1). + act::Key sender("IES"); + CHECK(importKey(sender, act::ANSIp256r1, "", "", "0x7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534") == 0); + act::Blob x, y; + sender.GetParam(act::PUBLIC_X, x); + sender.GetParam(act::PUBLIC_Y, y); + CHECK(Hex(x) == "00ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230"); + CHECK(Hex(y) == "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141"); + + act::Key recipient("IES"); + CHECK(importKey(recipient, act::ANSIp256r1, + "0x700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287", + "0xdb71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", "") == 0); + + act::Blob message; + for (int i = 0; i < 32; ++i) + message.push_back(static_cast(i)); + act::Blob encrypted; + CHECK(encryptSessionKey(recipient, sender, message, encrypted)); + CHECK(Hex(encrypted) == + "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230" + "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141" + "29603457fcb66a714e976d89526304033bf6cb06d4641f63244b7d3a122ae698" + "59bc42f5ec7d495c7047f63bb3df2de71bf77d07"); +} + +struct CurveCase +{ + int id; + const char *name; + size_t fieldLen; +}; + +static void TestCurve(const CurveCase &c) +{ + CHECK(act::detail::CurveFallbackMatches(c.id)); + + // Receiver key pair, as created with CrypTool's key generation and read back from the PSE. + act::Key receiver("IES"); + receiver.SetParam(act::CURVE, c.id); + receiver.Generate(); + act::Blob rx, ry, rs; + receiver.GetParam(act::PUBLIC_X, rx); + receiver.GetParam(act::PUBLIC_Y, ry); + receiver.GetParam(act::PRIVATEKEY, rs); + std::string xR = CrypToolNumber(rx), yR = CrypToolNumber(ry), sR = CrypToolNumber(rs); + + // encrypt() + act::Key privSendECIES("IES"); + privSendECIES.SetParam(act::CURVE, c.id); + privSendECIES.Generate(); + act::Key pubRecECIES("IES"); + CHECK(importKey(pubRecECIES, c.id, xR.c_str(), yR.c_str(), "") == 0); + + act::Blob plaintext("The quick brown fox jumps over the lazy dog. ECIES/AES hybrid test for "); + plaintext.append(act::Blob(c.name)); + act::Blob sessionKey, ciphertext, encryptedSessionKey; + CHECK(encryptData(plaintext, sessionKey, ciphertext)); + CHECK(sessionKey.size() == 32); + CHECK(ciphertext.size() == 16 + (plaintext.size() / 16 + 1) * 16); + CHECK(encryptSessionKey(pubRecECIES, privSendECIES, sessionKey, encryptedSessionKey)); + CHECK(encryptedSessionKey.size() == 1 + 2 * c.fieldLen + sessionKey.size() + 20); + + size_t keyStart = 0; + act::Blob file = writeEncFile(encryptedSessionKey, ciphertext, keyStart); + size_t ctStart = keyStart + encryptedSessionKey.size() + std::strlen("|AES ciphertext:"); + + // decrypt() + act::Key privRecECIES("IES"); + CHECK(importKey(privRecECIES, c.id, "", "", sR.c_str()) == 0); + act::Blob readKey, readCipher, decryptedSessionKey, decrypted; + CHECK(readEncFile(file, keyStart, encryptedSessionKey.size(), ctStart, readKey, readCipher)); + CHECK(readKey == encryptedSessionKey && readCipher == ciphertext); + CHECK(decryptSessionKey(privRecECIES, readKey, decryptedSessionKey) == 0); + CHECK(decryptedSessionKey == sessionKey); + CHECK(decryptData(readCipher, decryptedSessionKey, decrypted) == 0); + CHECK(decrypted == plaintext); + + // Tampering and wrong keys are reported as in ECIESMain.cpp. + for (size_t pos : {size_t(1 + 2 * c.fieldLen), encryptedSessionKey.size() - 1}) + { + act::Blob tampered(encryptedSessionKey); + tampered[pos] ^= 0x01; + act::Blob out; + CHECK(decryptSessionKey(privRecECIES, tampered, out) == 42); + } + act::Blob badPoint(encryptedSessionKey); + badPoint[2] ^= 0x01; + act::Blob out; + CHECK(decryptSessionKey(privRecECIES, badPoint, out) == 42); + CHECK(decryptSessionKey(privSendECIES, encryptedSessionKey, out) == 42); + CHECK(decryptSessionKey(privRecECIES, act::Blob(5, 4), out) == 42); + act::Blob truncated(readCipher.begin(), readCipher.end() - 1); + CHECK(decryptData(truncated, decryptedSessionKey, out) == 5); + + act::Key invalid("IES"); + CHECK(importKey(invalid, c.id, xR.c_str(), "0x1234", "") == 2); + act::Key infinity("IES"); + CHECK(importKey(infinity, c.id, "inf", "inf", "") == 2); + + // Key blob export/import round trip. + act::Blob pub, priv; + receiver.Export(pub, act::PUBLIC); + receiver.Export(priv, act::PRIVATE); + act::Key fromPub(pub), fromPriv(priv); + CHECK(fromPub.GetParam(act::CURVE) == c.id && fromPriv.GetParam(act::CURVE) == c.id); + act::Blob px; + fromPub.GetParam(act::PUBLIC_X, px); + CHECK(px == rx); + act::Blob roundtrip; + { + act::Algorithm enc(fromPub, act::ENCRYPT); + enc << plaintext << act::final; + act::Blob ct; + enc >> ct; + act::Algorithm dec(fromPriv, act::DECRYPT); + dec << ct << act::final; + dec >> roundtrip; + } + CHECK(roundtrip == plaintext); +} + +int main() +{ + act::Init(); + act::Init(); + + try + { + TestBlobAndTools(); + TestKdfVectors(); + TestKnownAnswer(); + + const CurveCase curves[] = { + {act::ANSIp192r1, "EC-prime192v1", 24}, {act::ANSIp192r2, "EC-prime192v2", 24}, + {act::ANSIp192r3, "EC-prime192v3", 24}, {act::ANSIp239r1, "EC-prime239v1", 30}, + {act::ANSIp239r2, "EC-prime239v2", 30}, {act::ANSIp239r3, "EC-prime239v3", 30}, + {act::ANSIp256r1, "EC-prime256v1", 32}, {act::SECGp160r1, "secp160r1", 20}, + }; + for (const CurveCase &c : curves) + TestCurve(c); + + act::Algorithm sha1("SHA1"); + sha1 << act::Blob("abc") << act::final; + act::Blob md; + sha1 >> md; + CHECK(Hex(md) == "a9993e364706816aba3e25717850c26c9cd0d89d"); + + bool threw = false; + try { act::Key unknown("RSA"); } catch (act::NoSuchAlgorithmException &) { threw = true; } + CHECK(threw); + } + catch (act::Exception &e) + { + std::fprintf(stderr, "unexpected act::Exception %s: %s (%s)\n", typeid(e).name(), e.what(), e.where()); + return 1; + } + + if (g_failures != 0) + { + std::fprintf(stderr, "%d check(s) failed\n", g_failures); + return 1; + } + std::printf("cvact_compat: all checks passed\n"); + return 0; +} diff --git a/port/thirdparty/tests/test_ec.cpp b/port/thirdparty/tests/test_ec.cpp new file mode 100644 index 000000000..038337c54 --- /dev/null +++ b/port/thirdparty/tests/test_ec.cpp @@ -0,0 +1,90 @@ +#include "ECsecude.h" +#include "s_ecFp.h" +#include "s_ecconv.h" +#include "ecssa.h" + +#include +#include +#include +#include +#include + +#ifndef CT_HAVE_SECUDE_COMPAT +#define CT_HAVE_SECUDE_COMPAT 0 +#endif + +#if CT_HAVE_SECUDE_COMPAT + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +static std::string hex_of(char *s) { + std::string out; + if (!s) + return ""; + const char *p = s; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + p += 2; + for (; *p; ++p) + if (std::isxdigit((unsigned char)*p)) + out += (char)std::toupper((unsigned char)*p); + std::size_t nz = out.find_first_not_of('0'); + out = nz == std::string::npos ? "0" : out.substr(nz); + std::free(s); + return out; +} + +int main() { + // Same wiring CrypToolApp::InitInstance performs for libec. +#define DoOneFn(a, b, c, d) ECSecudeLib.c = c; +#define DoOneData(a, b) ECSecudeLib.b = &b; + DoECAll +#undef DoOneFn +#undef DoOneData + + __CurveFp_struct curve; + __PointAc_struct G, R, S, T; + L_NUMBER cofactor[MAXLGTH], order[MAXLGTH]; + // prime192v1..v3 cannot be used: their literals in s_ecpcur.c contain TABs, + // which libec's string_to_ln() rejects (dead code for CrypTool, also on Windows); + // string_to_ln() also only accepts upper-case hex digits. + char id[] = "prime256v1"; + CHECK(X9_62_init_curve_Fp(&curve, &G, cofactor, order, id) == 0); + CHECK(hex_of(ecFp_point_getstr_xcoord_ac(&G, 16)) == "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"); + CHECK(hex_of(ecFp_point_getstr_ycoord_ac(&G, 16)) == "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"); + + CHECK(ecFp_mult_ac_str(&R, &curve, "2", &G) == 0); + CHECK(hex_of(ecFp_point_getstr_xcoord_ac(&R, 16)) == "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978"); + CHECK(hex_of(ecFp_point_getstr_ycoord_ac(&R, 16)) == "7775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1"); + + CHECK(ecFp_mult_ac_str(&S, &curve, "0X1234567890ABCDEF1234567890ABCDEF", &G) == 0); + CHECK(hex_of(ecFp_point_getstr_xcoord_ac(&S, 16)) == "F9EBE464147CC102D92324D099D927C1A50E42D57A08A116FFEC0A29819D8C65"); + CHECK(hex_of(ecFp_point_getstr_ycoord_ac(&S, 16)) == "70BAF7D12888902A6A0C1D67ADD103123C859AB69BF8E9431C9384930D4B7EEE"); + + CHECK(ecFp_add_ac(&T, &curve, &G, &G) == 0); + CHECK(hex_of(ecFp_point_getstr_xcoord_ac(&T, 16)) == "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978"); + + CHECK(ecFp_mult_ac(&T, &curve, order, &G) == 0); + CHECK(ecFp_point_check_infinity_ac(&T)); + + if (failures == 0) + std::printf("libec: all checks passed\n"); + return failures == 0 ? 0 : 1; +} + +#else + +int main() { + std::printf("libec: secude_compat target not available, headers compiled only\n"); + return 77; +} + +#endif diff --git a/port/thirdparty/tests/test_gmp.cpp b/port/thirdparty/tests/test_gmp.cpp new file mode 100644 index 000000000..069c82b07 --- /dev/null +++ b/port/thirdparty/tests/test_gmp.cpp @@ -0,0 +1,102 @@ +// Exercises the GMP/gmpxx API subset used by CrypTool (PrimeTest*, PrimePolynom, DlgAbout). +#include +#include + +#include +#include +#include +#include +#include +#include + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +static mpz_class square_multiply(const mpz_class &a, const mpz_class &b, const mpz_class &n) { + mpz_class x = 1, y = a, s = b; + while (s > 0) { + mpz_class s2 = s % 2; + long odd = mpz_get_si(s2.get_mpz_t()); + if (odd == 1) { + x = x * y; + x = x % n; + } + s >>= 1; + y = y * y; + y = y % n; + } + return x; +} + +int main() { + mpz_class n("170141183460469231731687303715884105727"); + CHECK(mpz_probab_prime_p(n.get_mpz_t(), 10) > 0); + CHECK(mpz_sizeinbase(n.get_mpz_t(), 2) == 127); + + mpz_class m = 561; + CHECK(mpz_probab_prime_p(m.get_mpz_t(), 10) == 0); + + mpz_class pot_b = 1; + pot_b = pot_b << 64; + mpz_class u = pot_b * 12345 + 678; + mpz_class coef = u % pot_b; + CHECK(coef == 678); + u = u >> 64; + CHECK(mpz_get_ui(u.get_mpz_t()) == 12345UL); + mpz_class c = 7; + c <<= 1; + CHECK(c == 14); + + CHECK(square_multiply(2, 10, 1000) == 24); + CHECK(square_multiply(3, n - 1, n) == 1); + + mpz_class small = -42; + CHECK(small.fits_sint_p()); + CHECK(small.get_si() == -42); + CHECK(mpz_get_si(small.get_mpz_t()) == -42); + + std::string per_s = "99.9"; + int size = (int)std::ceil(3.321 * per_s.length()); + mpf_class per(per_s, size); + mpf_class val(50.0, size + 1); + mpf_class res(50.0, size + 1); + int rounds = 1; + while (per > res && rounds < 100) { + val = val / 2; + res = res + val; + ++rounds; + } + CHECK(per >= 0 && per < 100); + CHECK(rounds == 10); + + gmp_randclass rand(gmp_randinit_default); + rand.seed(12345UL); + mpz_class r = rand.get_z_range(n); + CHECK(r >= 0 && r < n); + + char buf[64]; + gmp_snprintf(buf, sizeof buf, "%Zd", u.get_mpz_t()); + CHECK(std::strcmp(buf, "12345") == 0); + std::vector vec{1, 2, 3}; + for (auto it = vec.begin(); it != vec.end(); ++it) + gmp_printf(" %Zd", (*it).mpz_class::get_mpz_t()); + std::printf("\n"); + + CHECK(gmp_version != nullptr && gmp_version[0] >= '6'); + std::cout << "GMP " << gmp_version << ", 2^127-1 = " << n << std::endl; + + if (failures) { + std::fprintf(stderr, "%d check(s) failed\n", failures); + return 1; + } + std::printf("test_gmp: OK\n"); + return 0; +} diff --git a/port/thirdparty/tests/test_miracl.cpp b/port/thirdparty/tests/test_miracl.cpp new file mode 100644 index 000000000..408b62b92 --- /dev/null +++ b/port/thirdparty/tests/test_miracl.cpp @@ -0,0 +1,123 @@ +#include +#include + +#include +#include +#include +#include + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +static std::string to_dec(const Big &b) { + std::ostringstream os; + os << b; + return os.str(); +} + +static Big from_dec(const char *s) { + char buf[512]; + std::strncpy(buf, s, sizeof buf - 1); + buf[sizeof buf - 1] = 0; + return Big(buf); +} + +static Big pollard_rho(const Big &n) { + Big x = 2, y = 2, d = 1; + int c = 1; + while (d == 1) { + x = (x * x + c) % n; + y = (y * y + c) % n; + y = (y * y + c) % n; + d = gcd(x > y ? x - y : y - x, n); + } + return d; +} + +static void run(miracl *mip) { + + Big m127 = pow(Big(2), 127) - 1; + CHECK(to_dec(m127) == "170141183460469231731687303715884105727"); + CHECK(prime(m127)); + CHECK(!prime(pow(Big(2), 128) + 1)); + CHECK(bits(m127) == 127); + + Big a = from_dec("123456789012345678901234567890"); + CHECK(pow(a, m127 - 1, m127) == 1); + + Big p = from_dec("1000000007"); + Big e = from_dec("65537"); + CHECK(to_dec(pow(Big(3), e, p)) == "754428556"); + Big inv = inverse(Big(65537), p); + CHECK((inv * 65537) % p == 1); + + Big q1 = from_dec("1000003"), q2 = from_dec("998244353"); + Big n = q1 * q2; + Big f = pollard_rho(n); + CHECK(f == q1 || f == q2); + CHECK(f * (n / f) == n); + + CHECK(to_dec(Big((long)-42)) == "-42"); + if (sizeof(long) == 8) + CHECK(to_dec(Big((long)0x123456789ABL)) == "1250999896491"); + + mip->IOBASE = 16; + CHECK(to_dec(m127) == "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + mip->IOBASE = 10; + + big raw = mirvar(0); + char in[] = "987654321987654321987654321"; + cinstr(raw, in); + char out[128]; + cotstr(raw, out); + CHECK(std::strcmp(out, in) == 0); + mirkill(raw); + + mr_utype moduli[3] = {3, 5, 7}; + mr_utype residues[3] = {2, 3, 2}; + Crt chinese(3, moduli); + CHECK(chinese.eval(residues) == 23); + + Big bm[2] = {from_dec("1000000007"), from_dec("998244353")}; + Big br[2] = {Big(5), Big(7)}; + Crt bigchinese(2, bm); + Big x = bigchinese.eval(br); + CHECK(x % bm[0] == 5 && x % bm[1] == 7); + + flash fx = mirvar(0), fy = mirvar(0), fz = mirvar(0); + fconv(1, 4, fx); + fadd(fx, fx, fy); + fmul(fy, fy, fz); + fconv(1, 4, fx); + CHECK(fcomp(fz, fx) == 0); + fdiv(fz, fy, fx); + fsub(fy, fx, fz); + CHECK(size(fz) == 0); + mirkill(fz); + mirkill(fy); + mirkill(fx); +} + +int main() { + static_assert(sizeof(mr_small) == 4, "CrypTool expects 32-bit MIRACL digits"); + static_assert(sizeof(mr_large) == 8, "double-length type must be 64-bit"); + + miracl *mip = mirsys(4096 / 32 + 128, 0); + CHECK(mip != NULL); + CHECK(mip == get_mip()); + mip->IOBASE = 10; + run(mip); + mirexit(); + + if (failures == 0) + std::printf("miracl: all checks passed\n"); + return failures == 0 ? 0 : 1; +} diff --git a/port/thirdparty/tests/test_ntl.cpp b/port/thirdparty/tests/test_ntl.cpp new file mode 100644 index 000000000..4a3acacbb --- /dev/null +++ b/port/thirdparty/tests/test_ntl.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// Same pattern as CrypTool/ZZXY.h and ZZXY.cpp. +using namespace NTL; + +NTL_vector_decl(vec_ZZX, vec_vec_ZZX) + +NTL_matrix_decl(ZZX, vec_ZZX, vec_vec_ZZX, mat_ZZX) + +NTL_vector_decl(vec_ZZ_pX, vec_vec_ZZ_pX) + +NTL_matrix_decl(ZZ_pX, vec_ZZ_pX, vec_vec_ZZ_pX, mat_ZZ_pX) + +NTL_vector_impl(vec_ZZX, vec_vec_ZZX) + +NTL_matrix_impl(ZZX, vec_ZZX, vec_vec_ZZX, mat_ZZX) + +NTL_vector_impl(vec_ZZ_pX, vec_vec_ZZ_pX) + +NTL_matrix_impl(ZZ_pX, vec_ZZ_pX, vec_vec_ZZ_pX, mat_ZZ_pX) + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, \ + #cond); \ + ++failures; \ + } \ + } while (0) + +static std::string str(const ZZ& a) { + std::ostringstream os; + os << a; + return os.str(); +} + +static ZZ zz(const char* s) { + ZZ r; + std::istringstream is(s); + is >> r; + return r; +} + +int main() { + CHECK(std::string(NTL_VERSION) == "5.5.2"); + CHECK(NTL_BITS_PER_LONG == (int)(sizeof(long) * CHAR_BIT)); + CHECK(NTL_MAX_LONG == LONG_MAX); + + ZZ m127 = power(to_ZZ(2), 127) - 1; + CHECK(str(m127) == "170141183460469231731687303715884105727"); + CHECK(ProbPrime(m127)); + CHECK(!ProbPrime(power(to_ZZ(2), 128) - 1)); + CHECK(zz("170141183460469231731687303715884105727") == m127); + CHECK(NumBits(m127) == 127); + + // Fermat: 3^(p-1) = 1 mod p. + CHECK(IsOne(PowerMod(to_ZZ(3), m127 - 1, m127))); + CHECK(PowerMod(to_ZZ(4), to_ZZ(13), to_ZZ(497)) == 445); + + ZZ a = zz("123456789012345678901234567890"); + ZZ b = zz("987654321098765432109876543210"); + CHECK(str(GCD(a, b)) == "9000000000900000000090"); + CHECK(str(a * b) == "121932631137021795226185032733622923332237463801111263526900"); + ZZ q, r; + DivRem(q, r, b, a); + CHECK(q == 8 && str(r) == "9000000000900000000090"); + + ZZ inv = InvMod(to_ZZ(17), to_ZZ(3120)); + CHECK(inv == 2753); + + // RSA-like round trip. + ZZ p = zz("61"), qq = zz("53"), n = p * qq; + ZZ c = PowerMod(to_ZZ(65), to_ZZ(17), n); + CHECK(c == 2790); + CHECK(PowerMod(c, inv, n) == 65); + + ZZ sq = SqrRoot(m127 * m127); + CHECK(sq == m127); + + // RR + RR::SetPrecision(200); + RR x = to_RR(2); + RR s = sqrt(x); + CHECK(abs(s * s - x) < to_RR(1e-50)); + + // ZZX factorization: (x - 1)(x + 2)(x^2 + 1) = x^4 + x^3 - x^2 + x - 2 + ZZX f; + SetCoeff(f, 4, 1); + SetCoeff(f, 3, 1); + SetCoeff(f, 2, -1); + SetCoeff(f, 1, 1); + SetCoeff(f, 0, -2); + ZZ content; + vec_pair_ZZX_long factors; + factor(content, factors, f); + CHECK(content == 1); + CHECK(factors.length() == 3); + ZZX prod; + set(prod); + for (long i = 0; i < factors.length(); i++) + for (long e = 0; e < factors[i].b; e++) prod *= factors[i].a; + CHECK(prod == f); + + // LLL on a small lattice. + mat_ZZ B; + B.SetDims(3, 3); + B[0][0] = 1; B[0][1] = 1; B[0][2] = 1; + B[1][0] = -1; B[1][1] = 0; B[1][2] = 2; + B[2][0] = 3; B[2][1] = 5; B[2][2] = 6; + ZZ det2; + long rank = LLL(det2, B); + CHECK(rank == 3); + CHECK(det2 == 9); + ZZ n0 = B[0][0] * B[0][0] + B[0][1] * B[0][1] + B[0][2] * B[0][2]; + CHECK(n0 <= 2); + + mat_ZZ B2; + B2.SetDims(2, 2); + B2[0][0] = 201; B2[0][1] = 37; + B2[1][0] = 1648; B2[1][1] = 297; + LLL_FP(B2); + ZZ d = abs(B2[0][0] * B2[1][1] - B2[0][1] * B2[1][0]); + CHECK(d == 1279); + mat_ZZ B3; + B3.SetDims(2, 2); + B3[0][0] = 201; B3[0][1] = 37; + B3[1][0] = 1648; B3[1][1] = 297; + LLL_QP(B3); + CHECK(B3 == B2); + + // CrypTool-style mat_ZZX / vec_vec_ZZ_pX usage. + mat_ZZX MX; + MX.SetDims(2, 2); + SetCoeff(MX[0][0], 1, 3); + MX[1][1] = f; + CHECK(deg(MX[1][1]) == 4 && coeff(MX[0][0], 1) == 3); + vec_ZZX row = MX[1]; + CHECK(row.length() == 2); + + ZZ_p::init(to_ZZ(101)); + mat_ZZ_pX MP; + MP.SetDims(1, 1); + SetCoeff(MP[0][0], 2, 5); + ZZ_pX g = MP[0][0] * MP[0][0]; + CHECK(deg(g) == 4 && rep(coeff(g, 4)) == 25); + + if (failures) { + std::fprintf(stderr, "%d check(s) failed\n", failures); + return EXIT_FAILURE; + } + std::printf("NTL %s smoke test passed (NTL_BITS_PER_LONG=%d)\n", NTL_VERSION, NTL_BITS_PER_LONG); + return EXIT_SUCCESS; +} diff --git a/port/thirdparty/tests/test_openssl_compat.cpp b/port/thirdparty/tests/test_openssl_compat.cpp new file mode 100644 index 000000000..bed934b35 --- /dev/null +++ b/port/thirdparty/tests/test_openssl_compat.cpp @@ -0,0 +1,178 @@ +#include +#include +#include + +#include +#include + +// Exactly how CrypTool/HashingOperations.cpp and DlgAbout.cpp include them. +namespace __SSL +{ +#include "OpenSSL//md2.h" +#include "OpenSSL//md4.h" +#include "OpenSSL//md5.h" +#include "OpenSSL//ripemd.h" +#include "OpenSSL//sha.h" +} + +namespace OPENSSL { +#include "crypto.h" +} + +typedef void (*fp_Init_t)(void *context); +typedef void (*fp_Update_t)(void *context, void *data, unsigned long len); +typedef void (*fp_Final_t)(void *hash, void *context); + +struct HashAlgorithmsFP { + fp_Init_t fp_Init; + fp_Update_t fp_Update; + fp_Final_t fp_Final; + void *Context; + int ContextSize; + int BitLength; + const char *Name; +}; + +static HashAlgorithmsFP HAFP[] = { + {(fp_Init_t)__SSL::MD2_Init, (fp_Update_t)__SSL::MD2_Update, (fp_Final_t)__SSL::MD2_Final, NULL, sizeof(__SSL::MD2_CTX), 128, "MD2"}, + {(fp_Init_t)__SSL::MD4_Init, (fp_Update_t)__SSL::MD4_Update, (fp_Final_t)__SSL::MD4_Final, NULL, sizeof(__SSL::MD4_CTX), 128, "MD4"}, + {(fp_Init_t)__SSL::MD5_Init, (fp_Update_t)__SSL::MD5_Update, (fp_Final_t)__SSL::MD5_Final, NULL, sizeof(__SSL::MD5_CTX), 128, "MD5"}, + {(fp_Init_t)__SSL::SHA_Init, (fp_Update_t)__SSL::SHA_Update, (fp_Final_t)__SSL::SHA_Final, NULL, sizeof(__SSL::SHA_CTX), 160, "SHA"}, + {(fp_Init_t)__SSL::SHA1_Init, (fp_Update_t)__SSL::SHA1_Update, (fp_Final_t)__SSL::SHA1_Final, NULL, sizeof(__SSL::SHA_CTX), 160, "SHA-1"}, + {(fp_Init_t)__SSL::RIPEMD160_Init, (fp_Update_t)__SSL::RIPEMD160_Update, (fp_Final_t)__SSL::RIPEMD160_Final, NULL, sizeof(__SSL::RIPEMD160_CTX), 160, "RIPEMD-160"}, + {(fp_Init_t)__SSL::SHA256_Init, (fp_Update_t)__SSL::SHA256_Update, (fp_Final_t)__SSL::SHA256_Final, NULL, sizeof(__SSL::SHA256_CTX), 256, "SHA-256"}, + {(fp_Init_t)__SSL::SHA512_Init, (fp_Update_t)__SSL::SHA512_Update, (fp_Final_t)__SSL::SHA512_Final, NULL, sizeof(__SSL::SHA512_CTX), 512, "SHA-512"}, +}; + +extern "C" { +#define CT_LAYOUT_DECL(T) extern const size_t ct_real_sizeof_##T; extern const size_t ct_real_offsetof_##T; +CT_LAYOUT_DECL(MD4_CTX) +CT_LAYOUT_DECL(MD5_CTX) +CT_LAYOUT_DECL(RIPEMD160_CTX) +CT_LAYOUT_DECL(SHA_CTX) +CT_LAYOUT_DECL(SHA256_CTX) +CT_LAYOUT_DECL(SHA512_CTX) +const char *ct_real_openssl_version(void); +} + +static int failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, #cond); \ + ++failures; \ + } \ + } while (0) + +static std::string hex(const unsigned char *p, size_t n) { + static const char digits[] = "0123456789abcdef"; + std::string s; + for (size_t i = 0; i < n; ++i) { + s += digits[p[i] >> 4]; + s += digits[p[i] & 15]; + } + return s; +} + +// HashingOperations::DoHash: fp_Init, one fp_Update, fp_Final into a malloc'ed context. +static std::string do_hash(int id, const std::string &msg) { + HashAlgorithmsFP *h = &HAFP[id]; + h->Context = malloc(h->ContextSize); + unsigned char out[64]; + h->fp_Init(h->Context); + h->fp_Update(h->Context, (void *)msg.data(), (unsigned long)msg.size()); + h->fp_Final(out, h->Context); + free(h->Context); + h->Context = NULL; + return hex(out, h->BitLength / 8); +} + +// chunkHashInit/Update/Final with irregular chunk sizes. +static std::string chunk_hash(int id, const std::string &msg) { + HashAlgorithmsFP *h = &HAFP[id]; + h->Context = malloc(h->ContextSize); + unsigned char out[64]; + h->fp_Init(h->Context); + size_t pos = 0, step = 1; + while (pos < msg.size()) { + size_t n = step < msg.size() - pos ? step : msg.size() - pos; + h->fp_Update(h->Context, (void *)(msg.data() + pos), (unsigned long)n); + pos += n; + step = step * 3 % 97 + 1; + } + h->fp_Final(out, h->Context); + free(h->Context); + h->Context = NULL; + return hex(out, h->BitLength / 8); +} + +struct Kat { + int id; + const char *msg; + const char *digest; +}; + +int main() { + CHECK(sizeof(__SSL::MD4_CTX) == ct_real_sizeof_MD4_CTX && offsetof(__SSL::MD4_CTX, num) == ct_real_offsetof_MD4_CTX); + CHECK(sizeof(__SSL::MD5_CTX) == ct_real_sizeof_MD5_CTX && offsetof(__SSL::MD5_CTX, num) == ct_real_offsetof_MD5_CTX); + CHECK(sizeof(__SSL::RIPEMD160_CTX) == ct_real_sizeof_RIPEMD160_CTX && offsetof(__SSL::RIPEMD160_CTX, num) == ct_real_offsetof_RIPEMD160_CTX); + CHECK(sizeof(__SSL::SHA_CTX) == ct_real_sizeof_SHA_CTX && offsetof(__SSL::SHA_CTX, num) == ct_real_offsetof_SHA_CTX); + CHECK(sizeof(__SSL::SHA256_CTX) == ct_real_sizeof_SHA256_CTX && offsetof(__SSL::SHA256_CTX, md_len) == ct_real_offsetof_SHA256_CTX); + CHECK(sizeof(__SSL::SHA512_CTX) == ct_real_sizeof_SHA512_CTX && offsetof(__SSL::SHA512_CTX, md_len) == ct_real_offsetof_SHA512_CTX); + + static const char digits80[] = + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"; + static const char abc448[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + static const Kat kats[] = { + {0, "", "8350e5a3e24c153df2275c9f80692773"}, + {0, "a", "32ec01ec4a6dac72c0ab96fb34c0b5d1"}, + {0, "abc", "da853b0d3f88d99b30283a69e6ded6bb"}, + {0, "message digest", "ab4f496bfb2a530b219ff33031fe06b0"}, + {0, "abcdefghijklmnopqrstuvwxyz", "4e8ddff3650292ab5a4108c3aa47940b"}, + {0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "da33def2a42df13975352846c30338cd"}, + {0, digits80, "d5976f79d83d3a0dc9806c3c66f3efd8"}, + {1, "", "31d6cfe0d16ae931b73c59d7e0c089c0"}, + {1, "abc", "a448017aaf21d8525fc10ae87aa6729d"}, + {1, digits80, "e33b4ddc9c38f2199c3e7b164fcc0536"}, + {2, "", "d41d8cd98f00b204e9800998ecf8427e"}, + {2, "abc", "900150983cd24fb0d6963f7d28e17f72"}, + {2, digits80, "57edf4a22be3c955ac49da2e2107b67a"}, + {3, "abc", "0164b8a914cd2a5e74c4f7ff082c4d97f1edf880"}, + {3, abc448, "d2516ee1acfa5baf33dfc1c471e438449ef134c8"}, + {4, "abc", "a9993e364706816aba3e25717850c26c9cd0d89d"}, + {4, abc448, "84983e441c3bd26ebaae4aa1f95129e5e54670f1"}, + {5, "", "9c1185a5c5e9fc54612808977ee8f548b2258d31"}, + {5, "abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"}, + {6, "abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"}, + {6, abc448, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"}, + {7, "abc", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"}, + }; + + for (const Kat &k : kats) { + std::string got = do_hash(k.id, k.msg); + if (got != k.digest) { + fprintf(stderr, "%s(\"%.20s\") = %s, expected %s\n", HAFP[k.id].Name, k.msg, got.c_str(), k.digest); + ++failures; + } + } + + std::string million(1000000, 'a'); + CHECK(do_hash(3, million) == "3232affa48628a26653b5aaa44541fd90d690603"); + CHECK(do_hash(4, million) == "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + + std::string sample; + for (int i = 0; i < 5000; ++i) + sample += (char)(i * 131 + (i >> 3)); + for (int id = 0; id < 8; ++id) + CHECK(do_hash(id, sample) == chunk_hash(id, sample)); + + const char *version = OPENSSL::SSLeay_version(SSLEAY_VERSION); + CHECK(version != NULL && strncmp(version, "OpenSSL 3", 9) == 0); + CHECK(strcmp(version, ct_real_openssl_version()) == 0); + CHECK(strcmp(__SSL::MD2_options(), "md2(int)") == 0); + + if (failures == 0) + printf("openssl_compat: all checks passed (%s)\n", version); + return failures == 0 ? 0 : 1; +} diff --git a/port/thirdparty/tests/test_openssl_compat_layout.c b/port/thirdparty/tests/test_openssl_compat_layout.c new file mode 100644 index 000000000..5c8378af6 --- /dev/null +++ b/port/thirdparty/tests/test_openssl_compat_layout.c @@ -0,0 +1,24 @@ +/* Compiled against the real OpenSSL 3 headers only (no compat include dir). */ +#include + +#include +#include +#include +#include +#include + +#define CT_LAYOUT(T, last) \ + const size_t ct_real_sizeof_##T = sizeof(T); \ + const size_t ct_real_offsetof_##T = offsetof(T, last); + +CT_LAYOUT(MD4_CTX, num) +CT_LAYOUT(MD5_CTX, num) +CT_LAYOUT(RIPEMD160_CTX, num) +CT_LAYOUT(SHA_CTX, num) +CT_LAYOUT(SHA256_CTX, md_len) +CT_LAYOUT(SHA512_CTX, md_len) + +const char *ct_real_openssl_version(void) +{ + return OpenSSL_version(OPENSSL_VERSION); +} diff --git a/port/tools/build_help_index.py b/port/tools/build_help_index.py new file mode 100644 index 000000000..f42869850 --- /dev/null +++ b/port/tools/build_help_index.py @@ -0,0 +1,341 @@ +#!/usr/bin/env python3 +"""Builds the help index used by the mfcwx HTML Help replacement from an HTML Help Workshop project. + +The index maps HH_HELP_CONTEXT ids to topic files (the .hhp [MAP]/[ALIAS] sections, with +CrypTool_helpIDs.h recreated from resource.h like makehm + hh_generator.pl do), ALink and keyword +names to the pages declaring them, and records the default topic, contents and index files. +It also creates hid_load_readme.html from the readme text (like readme.pl). + + build_help_index.py --help-dir CrypTool/hlp_en --resource-header CrypTool/resource.h + --readme setup/template-en/ReadMe-en.txt --out-dir build/data/hlp_en [--mirror] + +--mirror turns the output directory into a copy of the help directory made of symbolic links +(development data directory); otherwise only the generated files are written. +""" +import argparse +import html +import os +import re +import shutil +import sys + +INDEX_NAME = 'CrypTool.helpindex' +README_NAME = 'hid_load_readme.html' +README_TEMPLATE = README_NAME + '.in' +MIRROR_EXCLUDE = re.compile(r'\.(vcproj|vcxproj.*|mak|dsp)$', re.I) + +# The makehm calls of CrypTool/MakeHtmlHelp.bat. +MAKEHM_RULES = [('ID_', 'HID_', 0x10000), ('IDM_', 'HIDM_', 0x10000), ('IDP_', 'HIDP_', 0x30000), + ('IDR_', 'HIDR_', 0x20000), ('IDD_', 'HIDD_', 0x20000), ('IDW_', 'HIDW_', 0x50000)] + +DEFINE_RE = re.compile(r'^\s*#\s*define\s+(\w+)\s+(0[xX][0-9a-fA-F]+|\d+)[uUlL]*\s*(?:$|//|/\*)') +MAP_LINE_RE = re.compile(r'^\s*(\w+)\s+(0[xX][0-9a-fA-F]+|\d+)\s*$') +INCLUDE_RE = re.compile(r'^\s*#\s*include\s+[<"]?([^>"\s]+)[>"]?\s*$', re.I) +ALIAS_RE = re.compile(r'^\s*(\w+)\s*=\s*(\S+)\s*$') +CHARSET_RE = re.compile(rb']+charset\s*=\s*["\']?([\w-]+)', re.I) +TITLE_RE = re.compile(r']*>(.*?)', re.I | re.S) +PARAM_RE = re.compile(r']*)>', re.I) +ATTR_RE = re.compile(r'(\w+)\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([^\s>]+))') + + +def read_text(path): + with open(path, 'rb') as f: + return f.read().decode('latin-1') + + +class Listing: + """Case-insensitive view of a directory: topic names in the project are not reliably cased.""" + + def __init__(self, directory, extra=()): + self.directory = directory + self.names = {} + for name in sorted(os.listdir(directory)): + self.names.setdefault(name.lower(), name) + for name in extra: + self.names.setdefault(name.lower(), name) + + def find(self, name): + return self.names.get(name.replace('\\', '/').lower()) + + def path(self, name): + real = self.find(name) + return os.path.join(self.directory, real) if real else None + + +def parse_hhp(path): + sections = {} + current = None + for line in read_text(path).splitlines(): + stripped = line.strip() + if stripped.startswith('[') and stripped.endswith(']'): + current = stripped[1:-1].upper() + sections.setdefault(current, []) + elif current is not None and stripped: + sections[current].append(stripped) + options = {} + for line in sections.get('OPTIONS', []): + key, sep, value = line.partition('=') + if sep: + options[key.strip().lower()] = value.strip() + return sections, options + + +def window_caption(sections, name): + for line in sections.get('WINDOWS', []): + key, sep, value = line.partition('=') + if sep and key.strip().lower() == name.lower(): + m = re.match(r'\s*"([^"]*)"', value) + if m: + return m.group(1) + return '' + + +def parse_defines(text): + for line in text.splitlines(): + m = DEFINE_RE.match(line) + if m: + yield m.group(1), int(m.group(2), 0) + + +def makehm(resource_header): + """CrypTool_helpIDs.h as produced by makehm + hh_generator.pl from resource.h.""" + out = [] + for name, value in parse_defines(read_text(resource_header)): + for prefix, hprefix, offset in MAKEHM_RULES: + if name.startswith(prefix): + out.append((hprefix + name[len(prefix):], value + offset)) + break + return out + + +def collect_map(sections, listing, resource_header, problems): + defines = [] + for line in sections.get('MAP', []): + m = INCLUDE_RE.match(line) + if m: + path = listing.path(m.group(1)) + if path: + defines += list(parse_defines(read_text(path))) + elif m.group(1).lower() == 'cryptool_helpids.h' and resource_header: + defines += makehm(resource_header) + else: + problems.append('[MAP] include not found: %s' % m.group(1)) + continue + m = DEFINE_RE.match(line) or MAP_LINE_RE.match(line) + if m: + defines.append((m.group(1), int(m.group(2), 0))) + return defines + + +def collect_aliases(sections, listing, problems): + aliases = {} + + def add_lines(lines): + for line in lines: + if line.startswith(';') or line.startswith('//'): + continue + m = ALIAS_RE.match(line) + if m: + aliases.setdefault(m.group(1).upper(), m.group(2)) + + for line in sections.get('ALIAS', []): + m = INCLUDE_RE.match(line) + if m: + path = listing.path(m.group(1)) + if path: + add_lines(read_text(path).splitlines()) + else: + problems.append('[ALIAS] include not found: %s' % m.group(1)) + else: + add_lines([line]) + return aliases + + +def resolve_topic(listing, target): + target = target.replace('\\', '/') + page, sep, anchor = target.partition('#') + real = listing.find(page) + if not real: + base, ext = os.path.splitext(page) + alternative = {'.htm': '.html', '.html': '.htm'}.get(ext.lower()) + real = listing.find(base + alternative) if alternative else None + return real + sep + anchor if real else None + + +def decode_page(data): + m = CHARSET_RE.search(data) + encoding = m.group(1).decode('ascii').lower() if m else 'cp1252' + try: + return data.decode(encoding) + except (LookupError, UnicodeDecodeError): + return data.decode('cp1252', errors='replace') + + +def clean(value): + return ' '.join(html.unescape(value).split()) + + +def scan_pages(listing, generated): + titles, alinks, keywords = {}, [], [] + for real in sorted(set(listing.names.values())): + if not re.search(r'\.html?$', real, re.I): + continue + source = generated.get(real) or os.path.join(listing.directory, real) + with open(source, 'rb') as f: + text = decode_page(f.read()) + m = TITLE_RE.search(text) + titles[real] = clean(re.sub(r'<[^>]*>', '', m.group(1))) if m else '' + for pm in PARAM_RE.finditer(text): + attrs = {a.group(1).lower(): next(v for v in a.groups()[1:] if v is not None) + for a in ATTR_RE.finditer(pm.group(1))} + name = attrs.get('name', '').strip().lower() + value = clean(attrs.get('value', '')) + if not value: + continue + if name == 'alink name': + alinks.append((value, real)) + elif name == 'keyword': + keywords.append((value, real)) + return titles, alinks, keywords + + +def make_readme(template_path, readme_path): + if not os.path.exists(readme_path): + readme_path = re.sub(r'-..([./\\])', r'-en\1', readme_path) + text = read_text(readme_path).replace('\r\n', '\n').replace('\r', '\n') + text = text.replace('&', '&').replace('<', '<').replace('>', '>') + text = re.sub(r'^( *)([.A-Z0-9]+)( +\.\.\.\.? +)(.*)$', r'\1\2\3\4', text, flags=re.M) + text = re.sub(r'^([.A-Z0-9]+\.) ([^.].*)', r'

\1 \2

', text, flags=re.M) + text = re.sub(r'----*', '', text) + return read_text(template_path).replace('__BODY__', text, 1).encode('latin-1') + + +def tsv(*fields): + return '\t'.join(f.replace('\t', ' ').replace('\n', ' ') for f in fields) + '\n' + + +def build(args): + help_dir = os.path.abspath(args.help_dir) + problems = [] + generated = {} + template = os.path.join(help_dir, README_TEMPLATE) + if args.readme and os.path.exists(template): + generated[README_NAME] = make_readme(template, args.readme) + + listing = Listing(help_dir, extra=generated) + hhp_name = args.project or next((n for n in listing.names.values() if n.lower().endswith('.hhp')), None) + if not hhp_name: + sys.exit('build_help_index: no .hhp project in %s' % help_dir) + sections, options = parse_hhp(os.path.join(help_dir, hhp_name)) + + defines = collect_map(sections, listing, args.resource_header, problems) + aliases = collect_aliases(sections, listing, problems) + + candidates = {} + unresolved = [] + for name, value in defines: + target = aliases.get(name.upper()) + topic = resolve_topic(listing, target if target else name.lower() + '.htm') + if topic: + entries = candidates.setdefault(value, []) + if (name, topic) not in entries: + entries.append((name, topic)) + else: + unresolved.append((name, value, target)) + + contexts = {} + collisions = [] + for value, entries in candidates.items(): + if len({t for _, t in entries}) > 1: + collisions.append((value, entries)) + # AFX_HIDD_* and HIDR_* ids can collide with CrypTool's dialogs and commands, which F1 asks for + best = sorted(entries, key=lambda e: 0 if e[0].startswith(('HIDD_', 'HID_')) else 1)[0] + contexts[value] = best[1] + + out_dir = os.path.abspath(args.out_dir) + prepare_out_dir(out_dir, help_dir, args.mirror, generated) + generated_paths = {} + for name, data in generated.items(): + generated_paths[name] = os.path.join(out_dir, name) + write(generated_paths[name], data) + + titles, alinks, keywords = scan_pages(listing, generated_paths) + + default_topic = resolve_topic(listing, options.get('default topic', '')) or '' + caption = window_caption(sections, options.get('default window', '')) or options.get('title', '') + lines = [tsv('CrypToolHelpIndex', '1'), + tsv('title', caption), + tsv('default', default_topic)] + for key, kind in (('contents file', 'contents'), ('index file', 'index')): + real = listing.find(options.get(key, '')) + if real: + lines.append(tsv(kind, real)) + for value in sorted(contexts): + lines.append(tsv('context', str(value), contexts[value])) + for keyword, page in sorted(set(alinks), key=lambda e: (e[0].lower(), e[1])): + lines.append(tsv('alink', keyword, page)) + for keyword, page in sorted(set(keywords), key=lambda e: (e[0].lower(), e[1])): + lines.append(tsv('keyword', keyword, page)) + for page in sorted(titles): + lines.append(tsv('topic', page, titles[page])) + write(os.path.join(out_dir, INDEX_NAME), ''.join(lines).encode('utf-8')) + + if args.stats or args.verbose: + print('%s: %d context ids mapped (%d MAP symbols, %d unresolved, %d ids with conflicting topics), ' + '%d ALinks (%d names), %d keywords, %d pages, default topic %s' % ( + os.path.basename(help_dir), len(contexts), len(defines), len(unresolved), len(collisions), + len(set(alinks)), len({a.lower() for a, _ in alinks}), len(set(keywords)), len(titles), + default_topic or '-')) + if args.verbose: + for name, value, target in unresolved: + print(' unresolved: %s (0x%X)%s' % (name, value, ' -> ' + target if target else '')) + for value, entries in collisions: + print(' conflict 0x%X: %s' % (value, ', '.join('%s=%s' % e for e in entries))) + for p in problems: + print(' ' + p) + + +def write(path, data): + with open(path, 'wb') as f: + f.write(data) + + +def prepare_out_dir(out_dir, help_dir, mirror, generated): + if mirror and os.path.islink(out_dir): + os.unlink(out_dir) + os.makedirs(out_dir, exist_ok=True) + if os.path.realpath(out_dir) == os.path.realpath(help_dir): + sys.exit('build_help_index: refusing to write into the help sources (%s)' % help_dir) + if not mirror: + return + wanted = {n for n in os.listdir(help_dir) if not MIRROR_EXCLUDE.search(n) and n not in generated} + for name in os.listdir(out_dir): + path = os.path.join(out_dir, name) + if os.path.islink(path) and (name not in wanted or not os.path.exists(path)): + os.unlink(path) + for name in sorted(wanted): + link = os.path.join(out_dir, name) + if os.path.lexists(link): + continue + src = os.path.join(help_dir, name) + try: + os.symlink(src, link) + except OSError: + (shutil.copytree if os.path.isdir(src) else shutil.copy2)(src, link) + + +def main(): + p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument('--help-dir', required=True, help='HTML Help Workshop project directory (hlp_en, ...)') + p.add_argument('--project', help='.hhp file name (default: the only .hhp in --help-dir)') + p.add_argument('--resource-header', help='resource.h to recreate CrypTool_helpIDs.h from') + p.add_argument('--readme', help='readme text for hid_load_readme.html') + p.add_argument('--out-dir', required=True) + p.add_argument('--mirror', action='store_true', help='link the help files into --out-dir') + p.add_argument('--stats', action='store_true', help='print a summary') + p.add_argument('--verbose', action='store_true', help='print the summary and every problem') + build(p.parse_args()) + + +if __name__ == '__main__': + main() diff --git a/port/tools/ccheck.py b/port/tools/ccheck.py new file mode 100644 index 000000000..3be92380c --- /dev/null +++ b/port/tools/ccheck.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +"""Runs the compile command of one source file from build/compile_commands.json with -fsyntax-only.""" +import json +import shlex +import subprocess +import sys + +build = sys.argv[1] +target = sys.argv[2] +extra = sys.argv[3:] +cc = json.load(open(build + '/compile_commands.json')) +entry = [x for x in cc if x['file'].endswith(target)][0] +args = shlex.split(entry['command']) +out = [] +skip = False +for a in args: + if skip: + skip = False + continue + if a in ('-o', '-MF', '-MT'): + skip = True + continue + if a in ('-MD', '-c'): + continue + out.append(a) +out += ['-fsyntax-only'] + extra +r = subprocess.run(out, cwd=entry['directory'], capture_output=True, text=True) +sys.stdout.write(r.stderr) +sys.exit(r.returncode) diff --git a/port/tools/fix_includes.py b/port/tools/fix_includes.py new file mode 100644 index 000000000..353b69791 --- /dev/null +++ b/port/tools/fix_includes.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""Rewrites #include directives in the CrypTool sources to portable spellings. + +Backslashes become slashes, './' prefixes are dropped and quoted includes are matched +case-insensitively against the files on disk so they also resolve on case-sensitive file systems. +""" +import os +import re +import sys + +REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) +DIRS = ['CrypTool', 'CrypTool/zip', 'ChallengeResponse', 'libVolRen'] +SPECIAL = { + '../aes/mars/mars.h': '"mars.h"', + '../aes/twofish/twofish.h': '"Twofish.h"', + '../aes/serpent/serpent.h': '"Serpent.h"', + '../aes/rijndael/rijndael-api-fst.h': '"Rijndael-api-fst.h"', + '../aes/rc6/rc6.h': '"RC6.h"', + '../libntl/include/ntl/version.h': '', + '../libmiracl/include/big.h': '"big.h"', + 'libanalyse/la_string.h': '"libanalyse/la_string.h"', + 'libanalyse/analyse.h': '"libanalyse/analyse.h"', + 'libanalyse/ngram.h': '"libanalyse/NGram.h"', + 'sys/timeb.h': '', +} +INCLUDE_RE = re.compile(rb'^(\s*#\s*include\s*)"([^"]+)"', re.M) + + +def listing(directory, cache={}): + if directory not in cache: + try: + cache[directory] = {name.lower(): name for name in os.listdir(directory)} + except OSError: + cache[directory] = {} + return cache[directory] + + +def resolve(base, rel): + parts = [p for p in rel.split('/') if p not in ('', '.')] + current = base + out = [] + for part in parts: + if part == '..': + current = os.path.dirname(current) + out.append('..') + continue + actual = listing(current).get(part.lower()) + if actual is None: + return None + current = os.path.join(current, actual) + out.append(actual) + return '/'.join(out) + + +def fix_file(path, search_dirs): + data = open(path, 'rb').read() + + def repl(match): + prefix, target = match.group(1), match.group(2).decode('latin-1') + norm = target.replace('\\', '/') + while norm.startswith('./'): + norm = norm[2:] + special = SPECIAL.get(norm.lower()) + if special: + return prefix + special.encode() + for base in [os.path.dirname(path)] + search_dirs: + resolved = resolve(base, norm) + if resolved: + return prefix + ('"%s"' % resolved).encode('latin-1') + if norm != target: + return prefix + ('"%s"' % norm).encode('latin-1') + return match.group(0) + + new = INCLUDE_RE.sub(repl, data) + if new != data: + open(path, 'wb').write(new) + return True + return False + + +def main(): + search = [os.path.join(REPO, 'CrypTool')] + changed = 0 + for d in DIRS: + full = os.path.join(REPO, d) + for name in sorted(os.listdir(full)): + if name.lower().endswith(('.cpp', '.c', '.h', '.hpp', '.cc', '.inl')): + if fix_file(os.path.join(full, name), search): + changed += 1 + print('changed', changed, 'files', file=sys.stderr) + + +if __name__ == '__main__': + main() diff --git a/port/tools/fix_msgmaps.py b/port/tools/fix_msgmaps.py new file mode 100644 index 000000000..1a3394367 --- /dev/null +++ b/port/tools/fix_msgmaps.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Qualifies message map handlers (ON_xxx(..., OnFoo) -> ON_xxx(..., &CClass::OnFoo)). + +MSVC accepts bare member names in message map macros; standard C++ needs &Class::member. +""" +import os +import re +import sys + +REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) +DIRS = ['CrypTool', 'ChallengeResponse', 'libVolRen', 'aestool', 'NumberShark'] +BEGIN_RE = re.compile(rb'BEGIN_MESSAGE_MAP\s*\(\s*(\w+)\s*,') +END_RE = re.compile(rb'END_MESSAGE_MAP\s*\(\s*\)') +ENTRY_RE = re.compile(rb'^(\s*ON_(?!EVENT\b)\w+\s*\(.*,\s*)([A-Za-z_]\w*)(\s*\)[^\n]*)$', re.M) + + +def fix(data): + out = [] + pos = 0 + changed = False + while True: + m = BEGIN_RE.search(data, pos) + if not m: + out.append(data[pos:]) + break + end = END_RE.search(data, m.end()) + if not end: + out.append(data[pos:]) + break + cls = m.group(1) + body = data[m.end():end.start()] + new_body = ENTRY_RE.sub(lambda e: e.group(1) + b'&' + cls + b'::' + e.group(2) + e.group(3), body) + changed |= new_body != body + out.append(data[pos:m.end()]) + out.append(new_body) + pos = end.start() + return b''.join(out), changed + + +def main(): + count = 0 + for d in DIRS: + full = os.path.join(REPO, d) + for name in sorted(os.listdir(full)): + if name.lower().endswith(('.cpp', '.h')): + path = os.path.join(full, name) + data = open(path, 'rb').read() + new, changed = fix(data) + if changed: + open(path, 'wb').write(new) + count += 1 + print('qualified handlers in', count, 'files', file=sys.stderr) + + +if __name__ == '__main__': + main() diff --git a/port/tools/gallery/CMakeLists.txt b/port/tools/gallery/CMakeLists.txt new file mode 100644 index 000000000..5e41782d6 --- /dev/null +++ b/port/tools/gallery/CMakeLists.txt @@ -0,0 +1,8 @@ +include(${REPO_ROOT}/port/rc/rc2cpp.cmake) + +add_executable(dialog_gallery gallery.cpp) +mfcwx_add_rc(dialog_gallery RC ${REPO_ROOT}/CrypTool/CrypTool.rc MODULE CrypTool HEADERS ${REPO_ROOT}/CrypTool/resource.h + REPLACE "[CRYPTOOL_VERSION_FULL]=CrypTool ${PROJECT_VERSION}" "[CRYPTOOL_VERSION]=${PROJECT_VERSION}" + OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/rc) +target_link_libraries(dialog_gallery PRIVATE mfcwx) +target_compile_definitions(dialog_gallery PRIVATE CRYPTOOL_DEV_DATA_DIR="${CMAKE_BINARY_DIR}/data") diff --git a/port/tools/gallery/gallery.cpp b/port/tools/gallery/gallery.cpp new file mode 100644 index 000000000..e6dac9c2f --- /dev/null +++ b/port/tools/gallery/gallery.cpp @@ -0,0 +1,91 @@ +// Opens every dialog template of CrypTool.rc in a language and saves a PNG snapshot of each. +// dialog_gallery [--lang de] [--out dir] [--only 101,102] + +#include "stdafx_gallery.h" + +#include "mfcwx/app.h" +#include "mfcwx/rcdata.h" + +#include +#include + +extern const mfcwx::rc::Module g_rcModule_CrypTool; +class wxWindow; +namespace mfcwx { +bool SnapshotWxWindow(wxWindow* w, const std::string& pngPath); +} + +namespace { + +struct RegisterModule { + RegisterModule() { + mfcwx::RegisterResourceModule(&g_rcModule_CrypTool); + mfcwx::SetDefaultDataDirectory(CRYPTOOL_DEV_DATA_DIR); + } +} registerModule; + +class GalleryDialog : public CDialog { +public: + explicit GalleryDialog(UINT id) : CDialog(id) {} + BOOL OnInitDialog() override { return TRUE; } +}; + +class GalleryApp : public CWinApp { +public: + BOOL InitInstance() override; +}; + +GalleryApp theApp; + +BOOL GalleryApp::InitInstance() { + std::string lang = "en"; + std::string out = "gallery"; + std::set only; + for (int i = 1; i + 1 < __argc; ++i) { + std::string a = __argv[i]; + if (a == "--lang") + lang = __argv[++i]; + else if (a == "--out") + out = __argv[++i]; + else if (a == "--only") { + std::string list = __argv[++i]; + size_t pos = 0; + while (pos < list.size()) { + size_t comma = list.find(',', pos); + only.insert(atoi(list.substr(pos, comma - pos).c_str())); + pos = comma == std::string::npos ? list.size() : comma + 1; + } + } + } + mfcwx::SetResourceLanguage(lang.c_str()); + _mkdir(out.c_str()); + const mfcwx::rc::Language* language = nullptr; + for (int i = 0; i < g_rcModule_CrypTool.languageCount; ++i) + if (lang == g_rcModule_CrypTool.languages[i]->code) + language = g_rcModule_CrypTool.languages[i]; + if (!language) + return FALSE; + int saved = 0; + for (int i = 0; i < language->dialogCount; ++i) { + const mfcwx::rc::Dialog& d = language->dialogs[i]; + if (!d.id || (!only.empty() && !only.count(d.id))) + continue; + GalleryDialog dlg(static_cast(d.id)); + if (!dlg.Create(static_cast(d.id), nullptr)) + continue; + dlg.ShowWindow(SW_SHOW); + dlg.UpdateWindow(); + MSG msg; + for (int k = 0; k < 5; ++k) + PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE); + char path[1024]; + snprintf(path, sizeof path, "%s/%s_%05d_%s.png", out.c_str(), lang.c_str(), d.id, d.name ? d.name : ""); + if (mfcwx::SnapshotWxWindow(dlg.GetWx(), path)) + ++saved; + dlg.DestroyWindow(); + } + printf("saved %d dialog snapshots to %s\n", saved, out.c_str()); + return FALSE; +} + +} // namespace diff --git a/port/tools/gallery/stdafx_gallery.h b/port/tools/gallery/stdafx_gallery.h new file mode 100644 index 000000000..3cc65b958 --- /dev/null +++ b/port/tools/gallery/stdafx_gallery.h @@ -0,0 +1,4 @@ +#pragma once +#include "afxwin.h" +#include "afxext.h" +#include "afxcmn.h" diff --git a/port/tools/port_status.py b/port/tools/port_status.py new file mode 100644 index 000000000..7fe19d8f5 --- /dev/null +++ b/port/tools/port_status.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +"""Measures how far the macOS/Linux port is and writes port/status/{status.json,badge.json,STATUS.md}. + +Progress = 50% x share of CrypTool sources that compile + 20% if CrypTool links + + 30% x share of passing tests (tests that do not build count as failed). +""" +import datetime +import json +import os +import re +import shlex +import subprocess +import sys +from concurrent.futures import ThreadPoolExecutor + +REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) +BUILD = os.environ.get('PORT_STATUS_BUILD', os.path.join(REPO, 'build-status')) +OUT = os.path.join(REPO, 'port', 'status') + + +def run(cmd, **kw): + print('+', ' '.join(cmd), flush=True) + return subprocess.run(cmd, cwd=REPO, capture_output=True, text=True, errors='replace', **kw) + + +def syntax_check(entry): + args = shlex.split(entry['command']) + out, skip = [], False + for a in args: + if skip: + skip = False + continue + if a in ('-o', '-MF', '-MT'): + skip = True + continue + if a in ('-MD', '-c'): + continue + out.append(a) + r = subprocess.run(out + ['-fsyntax-only', '-ferror-limit=0'], cwd=entry['directory'], capture_output=True, + text=True, errors='replace') + return r.returncode == 0, len(re.findall(r'\berror:', r.stderr)) + + +def main(): + configure = run(['cmake', '-S', REPO, '-B', BUILD, '-G', 'Ninja', '-DCRYPTOOL_THIRDPARTY_TESTS=ON', + '-DMFCWX_TESTS=ON'] + sys.argv[1:]) + if configure.returncode != 0: + sys.stderr.write(configure.stdout[-4000:] + configure.stderr[-4000:]) + sys.exit('configure failed') + + build = run(['ninja', '-C', BUILD, '-k', '0']) + app_dirs = ('/CrypTool/', '/ChallengeResponse/', '/libVolRen/') + library_errors = sum(1 for line in (build.stdout + build.stderr).splitlines() + if 'error:' in line and not any(d in line for d in app_dirs)) + + # Application sources are syntax-checked on their own so that a broken support library + # does not hide their state. + commands = json.load(open(os.path.join(BUILD, 'compile_commands.json'))) + units = [c for c in commands if '/CrypTool.dir/' in c.get('output', c['command'])] + with ThreadPoolExecutor(max_workers=os.cpu_count() or 4) as pool: + results = list(pool.map(syntax_check, units)) + compiled = sum(1 for ok, _ in results if ok) + errors = library_errors + sum(n for _, n in results) + linked = any(os.path.exists(os.path.join(BUILD, 'port', 'app', p)) + for p in ('CrypTool', 'CrypTool.app/Contents/MacOS/CrypTool')) + + tests = run(['ctest', '--test-dir', BUILD, '--timeout', '300']) + m = re.search(r'(\d+)% tests passed(?:, (\d+) tests? failed)? out of (\d+)', tests.stdout) + total = int(m.group(3)) if m else 0 + failed = int(m.group(2) or 0) if m else 0 + passed = total - failed + + compile_share = compiled / len(units) if units else 0.0 + test_share = passed / total if total else 0.0 + progress = round(50 * compile_share + 20 * (1 if linked else 0) + 30 * test_share) + + status = { + 'progress': progress, + 'compileErrors': errors, + 'sourcesCompiled': compiled, + 'sourcesTotal': len(units), + 'linked': linked, + 'testsPassed': passed, + 'testsTotal': total, + 'updated': datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M UTC'), + } + colour = 'red' if progress < 34 else 'orange' if progress < 67 else 'yellow' if progress < 100 else 'brightgreen' + os.makedirs(OUT, exist_ok=True) + json.dump(status, open(os.path.join(OUT, 'status.json'), 'w'), indent=2) + json.dump({'schemaVersion': 1, 'label': 'macOS/Linux port', 'message': f'{progress}%', 'color': colour}, + open(os.path.join(OUT, 'badge.json'), 'w')) + with open(os.path.join(OUT, 'STATUS.md'), 'w') as f: + f.write(f"""# Port status (generated by port/tools/port_status.py) + +| Metric | Value | +|---|---| +| Progress | **{progress}%** | +| Compile errors | {errors} | +| CrypTool sources compiling | {compiled} / {len(units)} | +| CrypTool links | {'yes' if linked else 'no'} | +| Tests passing | {passed} / {total} | +| Updated | {status['updated']} | + +Progress = 50% x sources compiling + 20% if the app links + 30% x tests passing. +""") + print(json.dumps(status, indent=2)) + + +if __name__ == '__main__': + main() diff --git a/secude/secude/af.h b/secude/secude/af.h index 007b00726..bb7d528ff 100644 --- a/secude/secude/af.h +++ b/secude/secude/af.h @@ -22,6 +22,11 @@ #include +#if !defined(HAS_EXT) +/* an older secure.h (CrypTool/secure.h) was included first and lacks this type */ +typedef SEQUENCE_OF(ObjId) SEQUENCE_OF_ObjId; +#endif + /* * secure.h defines: * diff --git a/secude/secude/af_p.h b/secude/secude/af_p.h index 46fb3543d..6e6af9eda 100644 --- a/secude/secude/af_p.h +++ b/secude/secude/af_p.h @@ -5527,11 +5527,13 @@ char SEC_GLOBAL_FUNC_PREFIX * SEC_API_CALLING_CONV str_up SEC_PROTOTYPE_1( ); +#ifdef _WIN32 /* elsewhere the name belongs to cracklib's char *Trim(char *) */ int SEC_GLOBAL_FUNC_PREFIX SEC_API_CALLING_CONV Trim SEC_PROTOTYPE_1( char * , str ); +#endif int SEC_GLOBAL_FUNC_PREFIX SEC_API_CALLING_CONV Skip_blanks SEC_PROTOTYPE_2( diff --git a/secude/secude/platform/platlinu.h b/secude/secude/platform/platlinu.h index 38c653bf7..f52ec56cf 100644 --- a/secude/secude/platform/platlinu.h +++ b/secude/secude/platform/platlinu.h @@ -33,6 +33,8 @@ # define SEC_TARGET_CPU_IA64 1 #elif defined(__x86_64__) # define SEC_TARGET_CPU_AMD64 1 +#elif defined(__aarch64__) +# define SEC_TARGET_CPU_ARM64 1 #else # error "architecture not supported" #endif @@ -43,6 +45,9 @@ #if __GNUC__ >= 3 || __GNUC_MINOR__ > 8 /* This is stupid: egcs is libc6, else libc5. Find a better way! */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#endif #define _BSD_SOURCE 1 #include diff --git a/secude/secude/platform/platmosx.h b/secude/secude/platform/platmosx.h index ce6a2044d..683b08ac1 100644 --- a/secude/secude/platform/platmosx.h +++ b/secude/secude/platform/platmosx.h @@ -9,7 +9,13 @@ #define SEC_TARGET_RT_MAC_MACHO 1 #define SEC_TARGET_API_MAC_CARBON 1 #define SEC_TARGET_API_UNIX 1 +#if defined(__arm64__) || defined(__aarch64__) +#define SEC_TARGET_CPU_ARM64 1 +#elif defined(__x86_64__) +#define SEC_TARGET_CPU_AMD64 1 +#else #define SEC_TARGET_CPU_PPC 1 +#endif /* #define _BSD_SOURCE 1 diff --git a/secude/secude/sec_conf.h b/secude/secude/sec_conf.h index a81ce782d..12a245ea1 100644 --- a/secude/secude/sec_conf.h +++ b/secude/secude/sec_conf.h @@ -93,6 +93,10 @@ || defined(SEC_TARGET_CPU_PPC) && SEC_TARGET_CPU_PPC \ || defined(SEC_TARGET_CPU_HPPA) && SEC_TARGET_CPU_HPPA # define SEC_BYTE_ORDER SEC_BIG_ENDIAN +# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define SEC_BYTE_ORDER SEC_LITTLE_ENDIAN +# elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SEC_BYTE_ORDER SEC_BIG_ENDIAN # endif # endif #endif diff --git a/secude/secude/sec_glob.h b/secude/secude/sec_glob.h index 0c7a4c7d2..276cb80e9 100644 --- a/secude/secude/sec_glob.h +++ b/secude/secude/sec_glob.h @@ -20,7 +20,10 @@ #include -#if !defined(TARGET_OS_MAC) || !TARGET_OS_MAC +#if defined(__APPLE__) && defined(__MACH__) +/* identical to the MacTypes.h typedef, so both headers can be combined */ +typedef unsigned char Boolean; +#elif !defined(TARGET_OS_MAC) || !TARGET_OS_MAC /* MPW-C defines 'Boolean', too */ #if (defined(applec)||defined(_MAC)) #include