diff --git a/.github/workflows/build-package.yml b/.github/workflows/build-package.yml new file mode 100644 index 0000000..b5af4f3 --- /dev/null +++ b/.github/workflows/build-package.yml @@ -0,0 +1,48 @@ +name: Build Reader package + +on: + push: + branches: + - codex/fix-security-and-stability + workflow_dispatch: + +jobs: + build-x64: + runs-on: windows-2022 + + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Set up MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Build x64 Release + shell: pwsh + run: >- + msbuild Reader.sln /m /t:Rebuild + /p:Configuration=Release + /p:Platform=x64 + /p:PlatformToolset=v143 + /p:WindowsTargetPlatformVersion=10.0 + + - name: Package Reader + id: package + shell: pwsh + run: | + $shortSha = '${{ github.sha }}'.Substring(0, 7) + $packageName = "Reader_custom_x64_$shortSha" + $packageDir = Join-Path $env:RUNNER_TEMP $packageName + New-Item -ItemType Directory -Force $packageDir | Out-Null + Copy-Item -LiteralPath 'x64\Release\Reader.exe' -Destination $packageDir + Copy-Item -LiteralPath 'readme.txt' -Destination $packageDir + New-Item -ItemType Directory -Force 'dist' | Out-Null + & '.\tool\7z.exe' a "dist\$packageName.7z" "$packageDir\Reader.exe" "$packageDir\readme.txt" + "name=$packageName" >> $env:GITHUB_OUTPUT + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.package.outputs.name }} + path: dist/*.7z + if-no-files-found: error diff --git a/README.md b/README.md index fc441e7..8f8e433 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ Reader 是我个人开发的一款绿色、开源、免费的阅读器软件, 4. 增加隐藏任务栏图标功能(此功能暂不支持windows xp及以下系统) 4.1 默认不开启此功能 4.2 开启方式:菜单栏 > setting > config > 窗口设置 > 勾选“隐藏任务栏图标” - 4.3 勾选此功能,会强制勾选“最小化托盘”,方便用户点击打开窗口 + 4.3 此功能可与“最小化托盘”独立设置;若同时关闭托盘,请使用热键显示窗口 5. 支持窗口背景全透明,而字体不透明功能。 5.1 注意:此功能暂时只能在“隐藏边框 或者 全屏模式”下支持 5.2 新增 Ctrl + Shift + 鼠标滚动:直接设置最高/最低透明度。方便快速背景全透明 diff --git a/Reader/DisplaySet.cpp b/Reader/DisplaySet.cpp index ccef339..166d3a8 100644 --- a/Reader/DisplaySet.cpp +++ b/Reader/DisplaySet.cpp @@ -211,12 +211,15 @@ static INT_PTR CALLBACK DisplaySetDlgProc(HWND hDlg, UINT message, WPARAM wParam case IDC_CHECK_MENU_FONT: res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_MENU_FONT), BM_GETCHECK, 0, NULL); _display.meun_font_follow = BST_CHECKED == res ? 1 : 0; + break; case IDC_CHECK_WORD_WRAP: res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_WORD_WRAP), BM_GETCHECK, 0, NULL); _display.word_wrap = BST_CHECKED == res ? 1 : 0; + break; case IDC_CHECK_INDENT: res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_INDENT), BM_GETCHECK, 0, NULL); _display.line_indent = BST_CHECKED == res ? 1 : 0; + break; case IDC_CHECK_BLANKLINES: res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_BLANKLINES), BM_GETCHECK, 0, NULL); _display.blank_lines = BST_CHECKED == res ? 1 : 0; @@ -224,6 +227,7 @@ static INT_PTR CALLBACK DisplaySetDlgProc(HWND hDlg, UINT message, WPARAM wParam case IDC_CHECK_CHAPTER_PAGE: res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_CHAPTER_PAGE), BM_GETCHECK, 0, NULL); _display.chapter_page = BST_CHECKED == res ? 1 : 0; + break; default: break; } diff --git a/Reader/EpubBook.cpp b/Reader/EpubBook.cpp index 45d1e1c..47dfbb0 100644 --- a/Reader/EpubBook.cpp +++ b/Reader/EpubBook.cpp @@ -705,7 +705,10 @@ BOOL EpubBook::ParserOps(file_data_t *fdata, wchar_t **text, int *len, wchar_t * } xmlKeepBlanksDefault(1); - doc = xmlReadMemory((const char *)format_str, size, NULL, NULL, XML_PARSE_RECOVER/* | XML_PARSE_NOBLANKS*/); + // htmlDocDumpMemoryFormat may serialize characters such as curly quotes as + // HTML named entities. Reparse the formatted document as HTML so those + // entities survive instead of being discarded by the XML parser. + doc = htmlReadMemory((const char *)format_str, size, NULL, NULL, HTML_PARSE_RECOVER); xmlFree(format_str); if (!doc) goto end; @@ -1048,4 +1051,4 @@ BOOL EpubBook::ParserCover(epub_t &epub) } return m_Cover != NULL; -} \ No newline at end of file +} diff --git a/Reader/MobiBook.cpp b/Reader/MobiBook.cpp index 6d54bb1..53b489e 100644 --- a/Reader/MobiBook.cpp +++ b/Reader/MobiBook.cpp @@ -637,11 +637,12 @@ BOOL MobiBook::ParserOps(file_data_t *fdata, wchar_t **text, int *len, wchar_t * } xmlKeepBlanksDefault(1); - doc = xmlReadMemory((const char *)format_str, size, NULL, NULL, XML_PARSE_RECOVER | XML_PARSE_HUGE /*| XML_PARSE_NOBLANKS */ ); //XML_PARSE_HUGE 大文件支持 + // htmlDocDumpMemoryFormat can emit HTML named entities. The XML parser only + // understands XML's predefined entities and would silently lose others. + doc = htmlReadMemory((const char *)format_str, size, NULL, NULL, HTML_PARSE_RECOVER); xmlFree(format_str); if (!doc) goto end; - xmlDocDumpFormatMemory(doc, &format_str, &size, 1); #endif xpathctx = xmlXPathNewContext(doc); diff --git a/Reader/OnlineBook.cpp b/Reader/OnlineBook.cpp index 460e801..6cc8e6b 100644 --- a/Reader/OnlineBook.cpp +++ b/Reader/OnlineBook.cpp @@ -1397,7 +1397,7 @@ BOOL OnlineBook::ParseOlHeader(ol_header_t* header) item.size = cinfo->size; item.title = (TCHAR*)(buf + cinfo->title_offset); item.url = buf + cinfo->url_offset; - item.title_len = cinfo->title_offset/2; + item.title_len = (int)item.title.size(); m_Chapters.push_back(item); } diff --git a/Reader/Page.cpp b/Reader/Page.cpp index bfc9290..0155a5e 100644 --- a/Reader/Page.cpp +++ b/Reader/Page.cpp @@ -860,8 +860,11 @@ int Page::ParagraphToLines(HDC hdc, int start, int length, int width, int height _continue: if (is_blank(m_Text[i])) { - // for indent, ignore the blank chars which at the beginning of a paragraph. - if (LINE_INDENT && char_start == i && !is_title && is_new_paragraph && line_start == start) + // Normalize the leading whitespace of a paragraph. LINE_INDENT + // controls the layout offset instead of preserving whitespace from + // the source text, so disabling it produces a genuinely flush-left + // paragraph. + if (char_start == i && !is_title && is_new_paragraph && line_start == start) { char_start = i + 1; word_start = i + 1; diff --git a/Reader/Reader.cpp b/Reader/Reader.cpp index 2145ff6..e2b3532 100644 --- a/Reader/Reader.cpp +++ b/Reader/Reader.cpp @@ -329,9 +329,17 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) OnFindText(hWnd, message, wParam, lParam); return 0; } - if (WM_TASKBAR_CREATED == message) - { - ShowSysTray(hWnd, TRUE); + if (WM_TASKBAR_CREATED == message) + { + // Explorer may recreate taskbar buttons for visible top-level windows. + // Reapply the user's taskbar preference before restoring any tray icon. + ShowInTaskbar(hWnd, !_header->hide_taskbar); + if (_header->show_systray) + { + // Explorer discarded the old icon, so force it to be added again. + _nid.uFlags = 0; + ShowSysTray(hWnd, TRUE); + } } switch (message) { @@ -1478,17 +1486,10 @@ INT_PTR CALLBACK Setting(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) else cid = IDC_RADIO_MODE3; SendMessage(GetDlgItem(hDlg, cid), BM_SETCHECK, BST_CHECKED, NULL); - WheelSpeedInit(hDlg); - // init window style - SendMessage(GetDlgItem(hDlg, IDC_CHECK_TRAY), BM_SETCHECK, _header->show_systray ? BST_CHECKED : BST_UNCHECKED, NULL); - if (_header->hide_taskbar) - { - SendMessage(GetDlgItem(hDlg, IDC_CHECK_TASKBAR), BM_SETCHECK, BST_CHECKED, NULL); - SendMessage(GetDlgItem(hDlg, IDC_CHECK_TRAY), BM_SETCHECK, BST_CHECKED, NULL); - EnableWindow(GetDlgItem(hDlg, IDC_CHECK_TRAY), FALSE); - } - else - SendMessage(GetDlgItem(hDlg, IDC_CHECK_TASKBAR), BM_SETCHECK, BST_UNCHECKED, NULL); + WheelSpeedInit(hDlg); + // init window style + SendMessage(GetDlgItem(hDlg, IDC_CHECK_TRAY), BM_SETCHECK, _header->show_systray ? BST_CHECKED : BST_UNCHECKED, NULL); + SendMessage(GetDlgItem(hDlg, IDC_CHECK_TASKBAR), BM_SETCHECK, _header->hide_taskbar ? BST_CHECKED : BST_UNCHECKED, NULL); SendMessage(GetDlgItem(hDlg, IDC_CHECK_LRHIDE), BM_SETCHECK, _header->disable_lrhide ? BST_UNCHECKED : BST_CHECKED, NULL); SendMessage(GetDlgItem(hDlg, IDC_CHECK_ESCHIDE), BM_SETCHECK, _header->disable_eschide ? BST_UNCHECKED : BST_CHECKED, NULL); if ((_header->autopage_mode & 0x0f) == apm_page) @@ -1575,20 +1576,9 @@ INT_PTR CALLBACK Setting(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; break; - case IDC_CHECK_TASKBAR: - res = SendMessage(GetDlgItem(hDlg, IDC_CHECK_TASKBAR), BM_GETCHECK, 0, NULL); - if (res == BST_CHECKED) - { - SendMessage(GetDlgItem(hDlg, IDC_CHECK_TRAY), BM_SETCHECK, BST_CHECKED, NULL); - EnableWindow(GetDlgItem(hDlg, IDC_CHECK_TRAY), FALSE); - } - else - { - EnableWindow(GetDlgItem(hDlg, IDC_CHECK_TRAY), TRUE); - } - break; - case IDC_CHECK_TRAY: - break; + case IDC_CHECK_TASKBAR: + case IDC_CHECK_TRAY: + break; default: break; }