[ZIPFLDR][BOOTDATA] Support UTF-8 Zip packing (#5450)

New ReactOS can zip/unzip files and folders in UTF-8 filenames.
You can also choose the codepage of filenames to zip/unzip via
the ZipCodePage / UnZipCodePage registry values on the registry
key HKEY_CURRENT_USER\Software\ReactOS.

Windows 8 or later also support UTF-8 zipped folders.
You can also use 3rd party software to zip/unzip in older Windows.

- Use <atlconv.h> for string conversion.
- Use zipOpenNewFileInZip4_64 instead of zipOpenNewFileInZip3_64,
  and then add MINIZIP_UTF8_FLAG flag.
- Set the filenames in UTF-8 by using CP_UTF8 codepage.
- Codepage is user selectable via registry settings.

CORE-16668
This commit is contained in:
Katayama Hirofumi MZ 2023-07-22 12:57:32 +09:00 committed by GitHub
parent 059427e31d
commit 104ef25fcc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 26 deletions

View file

@ -1978,6 +1978,10 @@ HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\WINXP",
HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\WINXP","SPMajorVersion",0x00010001,0x00000001
HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\WINXP","SPMinorVersion",0x00010001,0x00000000
; Zip/UnZip codepages
HKCU,"SOFTWARE\ReactOS","ZipCodePage",0x00000000,"65001" ; CP_UTF8
HKCU,"SOFTWARE\ReactOS","UnZipCodePage",0x00000000,"0" ; CP_ACP
; DEBUG: Windows Messages SPY configuration
HKCU,"SOFTWARE\ReactOS\Debug","SpyInclude",0x00020000,"INCLUDEALL"
;HKCU,"SOFTWARE\ReactOS\Debug","SpyExclude",0x00020000,""

View file

@ -3,7 +3,7 @@
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Create a zip file
* COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
* Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
* Copyright 2019-2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "precomp.h"
@ -34,13 +34,6 @@ static CStringW DoGetZipName(PCWSTR filename)
return ret;
}
static CStringA DoGetAnsiName(PCWSTR filename)
{
CHAR buf[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, filename, -1, buf, _countof(buf), NULL, NULL);
return buf;
}
static CStringW DoGetBaseName(PCWSTR filename)
{
WCHAR szBaseName[MAX_PATH];
@ -51,7 +44,7 @@ static CStringW DoGetBaseName(PCWSTR filename)
}
static CStringA
DoGetNameInZip(const CStringW& basename, const CStringW& filename)
DoGetNameInZip(const CStringW& basename, const CStringW& filename, UINT nCodePage)
{
CStringW basenameI = basename, filenameI = filename;
basenameI.MakeUpper();
@ -65,7 +58,7 @@ DoGetNameInZip(const CStringW& basename, const CStringW& filename)
ret.Replace(L'\\', L'/');
return DoGetAnsiName(ret);
return CStringA(CW2AEX<MAX_PATH>(ret, nCodePage));
}
static BOOL
@ -279,6 +272,7 @@ unsigned CZipCreatorImpl::JustDoIt()
int err = 0;
CStringW strTarget, strBaseName = DoGetBaseName(m_items[0]);
UINT nCodePage = GetZipCodePage(FALSE);
for (INT iFile = 0; iFile < files.GetSize(); ++iFile)
{
const CStringW& strFile = files[iFile];
@ -298,8 +292,8 @@ unsigned CZipCreatorImpl::JustDoIt()
// TODO: crc = ...;
}
CStringA strNameInZip = DoGetNameInZip(strBaseName, strFile);
err = zipOpenNewFileInZip3_64(zf,
CStringA strNameInZip = DoGetNameInZip(strBaseName, strFile, nCodePage);
err = zipOpenNewFileInZip4_64(zf,
strNameInZip,
&zi,
NULL,
@ -315,6 +309,8 @@ unsigned CZipCreatorImpl::JustDoIt()
Z_DEFAULT_STRATEGY,
password,
crc,
MINIZIP_COMPATIBLE_VERSION,
(nCodePage == CP_UTF8 ? MINIZIP_UTF8_FLAG : 0),
zip64);
if (err)
{

View file

@ -12,9 +12,11 @@ private:
CComPtr<IZip> m_Zip;
bool m_First;
CAtlList<CStringW> m_Returned;
UINT m_nCodePage;
public:
CZipEnumerator()
:m_First(true)
: m_First(true)
, m_nCodePage(GetZipCodePage(TRUE))
{
}
@ -92,9 +94,9 @@ public:
nameA.Replace('\\', '/');
if (info.flag & MINIZIP_UTF8_FLAG)
Utf8ToWide(nameA, name);
name = CA2WEX<MAX_PATH>(nameA, CP_UTF8);
else
name = CStringW(nameA);
name = CA2WEX<MAX_PATH>(nameA, m_nCodePage);
}
return err == UNZ_OK;
}

View file

@ -11,6 +11,7 @@
#include <atlbase.h>
#include <atlcom.h>
#include <atlcoll.h>
#include <atlconv.h>
#include <atlstr.h>
#include <ui/rosdlgs.h>
#include <shlwapi.h>
@ -21,8 +22,6 @@
#include <reactos/debug.h>
#include <shellutils.h>
void Utf8ToWide(const CStringA& strUtf8, CStringW& strWide);
#define EXTRACT_VERBA "extract"
#define EXTRACT_VERBW L"extract"
@ -36,10 +35,10 @@ EXTERN_C const GUID CLSID_ZipFolderExtractAllCommand;
extern LONG g_ModuleRefCnt;
UINT GetZipCodePage(BOOL bUnZip);
WCHAR* guid2string(REFCLSID iid);
#define MINIZIP_COMPATIBLE_VERSION 36
#define MINIZIP_PASSWORD_FLAG 1
#define MINIZIP_UTF8_FLAG (1 << 11)

View file

@ -48,13 +48,6 @@ static void init_zlib()
fill_win32_filefunc64W(&g_FFunc);
}
void Utf8ToWide(const CStringA& strUtf8, CStringW& strWide)
{
INT cchWide = MultiByteToWideChar(CP_UTF8, 0, strUtf8, -1, NULL, 0);
MultiByteToWideChar(CP_UTF8, 0, strUtf8, -1, strWide.GetBuffer(cchWide), cchWide);
strWide.ReleaseBuffer();
}
static BOOL
CreateEmptyFile(PCWSTR pszFile)
{
@ -94,6 +87,28 @@ GetDefaultUserSendTo(PWSTR pszPath)
SHGFP_TYPE_DEFAULT, pszPath);
}
UINT GetZipCodePage(BOOL bUnZip)
{
WCHAR szValue[16];
DWORD dwType, cbValue = sizeof(szValue);
UINT nDefaultCodePage = (bUnZip ? CP_ACP : CP_UTF8);
LONG error = SHGetValueW(HKEY_CURRENT_USER, L"Software\\ReactOS",
(bUnZip ? L"UnZipCodePage" : L"ZipCodePage"),
&dwType, szValue, &cbValue);
if (error != ERROR_SUCCESS)
return nDefaultCodePage;
if (cbValue == sizeof(DWORD) && (dwType == REG_DWORD || dwType == REG_BINARY))
return *(DWORD*)szValue;
if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
return nDefaultCodePage;
szValue[_countof(szValue) - 1] = UNICODE_NULL;
return (UINT)wcstol(szValue, NULL, 0);
}
EXTERN_C
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{