SkinInstaller/SkinPackager: Fix Unicode filename handling

Existing .rmskin files need to be repackaged for proper Unicode filename support.

Non-ASCII filenames can be used only if 'Minimum Rainmeter' is set to at least '3.0.1'. An error will be displayed otherwise.
This commit is contained in:
Birunthan Mohanathas 2013-10-16 17:21:07 +03:00
parent d6e26401ca
commit d087a7db42
5 changed files with 46 additions and 13 deletions

View File

@ -405,11 +405,14 @@ bool DialogInstall::ReadPackage()
// Helper to sets buffer with current file name // Helper to sets buffer with current file name
auto getFileInfo = [&]()->bool auto getFileInfo = [&]()->bool
{ {
char cBuffer[MAX_PATH]; char cBuffer[MAX_PATH * 3];
unz_file_info ufi; unz_file_info ufi;
if (unzGetCurrentFileInfo(m_PackageUnzFile, &ufi, cBuffer, MAX_PATH, nullptr, 0, nullptr, 0) == UNZ_OK) if (unzGetCurrentFileInfo(
m_PackageUnzFile, &ufi, cBuffer, _countof(cBuffer), nullptr, 0, nullptr, 0) == UNZ_OK)
{ {
MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); const uLong ZIP_UTF8_FLAG = 1 << 11;
const DWORD codePage = (ufi.flag & ZIP_UTF8_FLAG) ? CP_UTF8 : CP_ACP;
MultiByteToWideChar(codePage, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH);
while (WCHAR* pos = wcschr(buffer, L'/')) *pos = L'\\'; while (WCHAR* pos = wcschr(buffer, L'/')) *pos = L'\\';
return true; return true;
} }
@ -713,11 +716,14 @@ bool DialogInstall::InstallPackage()
// Helper to sets buffer with current file name // Helper to sets buffer with current file name
auto getFileInfo = [&]()->bool auto getFileInfo = [&]()->bool
{ {
char cBuffer[MAX_PATH]; char cBuffer[MAX_PATH * 3];
unz_file_info ufi; unz_file_info ufi;
if (unzGetCurrentFileInfo(m_PackageUnzFile, &ufi, cBuffer, MAX_PATH, nullptr, 0, nullptr, 0) == UNZ_OK) if (unzGetCurrentFileInfo(
m_PackageUnzFile, &ufi, cBuffer, _countof(cBuffer), nullptr, 0, nullptr, 0) == UNZ_OK)
{ {
MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); const uLong ZIP_UTF8_FLAG = 1 << 11;
const DWORD codePage = (ufi.flag & ZIP_UTF8_FLAG) ? CP_UTF8 : CP_ACP;
MultiByteToWideChar(codePage, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH);
while (WCHAR* pos = wcschr(buffer, L'/')) *pos = L'\\'; while (WCHAR* pos = wcschr(buffer, L'/')) *pos = L'\\';
return true; return true;
} }

View File

@ -17,6 +17,7 @@
*/ */
#include "StdAfx.h" #include "StdAfx.h"
#include "../Common/StringUtil.h"
#include "Application.h" #include "Application.h"
#include "DialogPackage.h" #include "DialogPackage.h"
#include "DialogInstall.h" #include "DialogInstall.h"
@ -37,7 +38,8 @@ DialogPackage::DialogPackage(HWND wnd) : Dialog(wnd),
m_LoadLayout(false), m_LoadLayout(false),
m_MergeSkins(false), m_MergeSkins(false),
m_PackagerThread(), m_PackagerThread(),
m_ZipFile() m_ZipFile(),
m_AllowNonAsciiFilenames(false)
{ {
} }
@ -263,12 +265,16 @@ bool DialogPackage::CreatePackage()
WritePrivateProfileString(L"rmskin", L"MinimumRainmeter", m_MinimumRainmeter.c_str(), tempFile); WritePrivateProfileString(L"rmskin", L"MinimumRainmeter", m_MinimumRainmeter.c_str(), tempFile);
WritePrivateProfileString(L"rmskin", L"MinimumWindows", m_MinimumWindows.c_str(), tempFile); WritePrivateProfileString(L"rmskin", L"MinimumWindows", m_MinimumWindows.c_str(), tempFile);
// Only Skin Installer in Rainmeter 3.0.1 support UTF-8 filenames.
m_AllowNonAsciiFilenames = DialogInstall::CompareVersions(m_MinimumRainmeter, L"3.0.1") != -1;
// Create archive and add options file and header bitmap // Create archive and add options file and header bitmap
m_ZipFile = zipOpen(ConvertToAscii(m_TargetFile.c_str()).c_str(), APPEND_STATUS_CREATE); m_ZipFile = zipOpen(ConvertToAscii(m_TargetFile.c_str()).c_str(), APPEND_STATUS_CREATE);
auto cleanup = [&]()->bool auto cleanup = [&]()->bool
{ {
zipClose(m_ZipFile, nullptr); zipClose(m_ZipFile, nullptr);
DeleteFile(m_TargetFile.c_str());
return false; return false;
}; };
@ -379,17 +385,30 @@ unsigned __stdcall DialogPackage::PackagerThreadProc(void* pParam)
bool DialogPackage::AddFileToPackage(const WCHAR* filePath, const WCHAR* zipPath) bool DialogPackage::AddFileToPackage(const WCHAR* filePath, const WCHAR* zipPath)
{ {
std::string zipPathAscii = ConvertToAscii(zipPath); std::string zipPathUTF8 = StringUtil::NarrowUTF8(zipPath);
for (int i = 0, isize = zipPathAscii.length(); i < isize; ++i) for (int i = 0, isize = zipPathUTF8.length(); i < isize; ++i)
{ {
if (zipPathAscii[i] == '\\') if ((zipPathUTF8[i] & 0x80) != 0)
{ {
zipPathAscii[i] = '/'; // UTF-8 lead bit is not zero so the string is non-ASCII.
if (!m_AllowNonAsciiFilenames)
{
return false;
}
}
if (zipPathUTF8[i] == '\\')
{
zipPathUTF8[i] = '/';
} }
} }
int open = zipOpenNewFileInZip(m_ZipFile, zipPathAscii.c_str(), nullptr, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION); const uLong ZIP_UTF8_FLAG = 1 << 11;
if (open != ZIP_OK) zip_fileinfo fi = {0};
if (zipOpenNewFileInZip4(
m_ZipFile, zipPathUTF8.c_str(), &fi,
nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION,
0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, 0, ZIP_UTF8_FLAG) != ZIP_OK)
{ {
return false; return false;
} }

View File

@ -121,6 +121,7 @@ private:
HANDLE m_PackagerThread; HANDLE m_PackagerThread;
zipFile m_ZipFile; zipFile m_ZipFile;
bool m_AllowNonAsciiFilenames;
}; };
#endif #endif

View File

@ -122,6 +122,7 @@
</Manifest> </Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\Common\StringUtil.cpp" />
<ClCompile Include="..\Library\Dialog.cpp" /> <ClCompile Include="..\Library\Dialog.cpp" />
<ClCompile Include="Application.cpp" /> <ClCompile Include="Application.cpp" />
<ClCompile Include="DialogInstall.cpp" /> <ClCompile Include="DialogInstall.cpp" />

View File

@ -19,6 +19,9 @@
<Filter Include="zlib\minizip"> <Filter Include="zlib\minizip">
<UniqueIdentifier>{b726e25d-2977-424a-b45b-8ee60ce6bd49}</UniqueIdentifier> <UniqueIdentifier>{b726e25d-2977-424a-b45b-8ee60ce6bd49}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Common">
<UniqueIdentifier>{b69ece81-b900-41d8-9ccd-61476261c411}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Application.cpp"> <ClCompile Include="Application.cpp">
@ -81,6 +84,9 @@
<ClCompile Include="DialogPackage.cpp"> <ClCompile Include="DialogPackage.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Common\StringUtil.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="resource.h"> <ClInclude Include="resource.h">