143 lines
2.9 KiB
C++
143 lines
2.9 KiB
C++
#include "codec.h"
|
|
#include <fstream>
|
|
#include <stdexcept>
|
|
|
|
#ifdef _WIN32
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
static std::wstring mb_to_wide(UINT code_page, const std::string& s)
|
|
{
|
|
if (s.empty()) {
|
|
return {};
|
|
}
|
|
|
|
const DWORD flags = (code_page == CP_UTF8) ? MB_ERR_INVALID_CHARS : 0;
|
|
|
|
const int wide_len = MultiByteToWideChar(
|
|
code_page,
|
|
flags,
|
|
s.data(),
|
|
static_cast<int>(s.size()),
|
|
nullptr,
|
|
0
|
|
);
|
|
|
|
if (wide_len <= 0) {
|
|
throw std::runtime_error("MultiByteToWideChar failed");
|
|
}
|
|
|
|
std::wstring w(static_cast<size_t>(wide_len), L'\0');
|
|
|
|
const int written = MultiByteToWideChar(
|
|
code_page,
|
|
flags,
|
|
s.data(),
|
|
static_cast<int>(s.size()),
|
|
w.data(),
|
|
wide_len
|
|
);
|
|
|
|
if (written <= 0) {
|
|
throw std::runtime_error("MultiByteToWideChar failed");
|
|
}
|
|
|
|
return w;
|
|
}
|
|
|
|
|
|
static std::string wide_to_mb(UINT code_page, const std::wstring& w)
|
|
{
|
|
if (w.empty()) {
|
|
return {};
|
|
}
|
|
|
|
const int mb_len = WideCharToMultiByte(
|
|
code_page,
|
|
0,
|
|
w.data(),
|
|
static_cast<int>(w.size()),
|
|
nullptr,
|
|
0,
|
|
nullptr,
|
|
nullptr
|
|
);
|
|
|
|
if (mb_len <= 0) {
|
|
throw std::runtime_error("WideCharToMultiByte failed");
|
|
}
|
|
|
|
std::string s(static_cast<size_t>(mb_len), '\0');
|
|
|
|
const int written = WideCharToMultiByte(
|
|
code_page,
|
|
0,
|
|
w.data(),
|
|
static_cast<int>(w.size()),
|
|
s.data(),
|
|
mb_len,
|
|
nullptr,
|
|
nullptr
|
|
);
|
|
|
|
if (written <= 0) {
|
|
throw std::runtime_error("WideCharToMultiByte failed");
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
#endif
|
|
|
|
namespace Psc {
|
|
|
|
// 项目内部 UTF-8 -> 平台窄字符串
|
|
// Windows: UTF-8 -> UTF-16 -> ACP / 当前系统 ANSI code page
|
|
// Linux/macOS: UTF-8 原样返回
|
|
std::string utf8_2_platform(const std::string& utf8_path)
|
|
{
|
|
#ifdef _WIN32
|
|
return wide_to_mb(CP_ACP, mb_to_wide(CP_UTF8, utf8_path));
|
|
#else
|
|
return utf8_path;
|
|
#endif
|
|
}
|
|
|
|
|
|
// 平台窄字符串 -> 项目内部 UTF-8
|
|
// Windows: ACP / 当前系统 ANSI code page -> UTF-16 -> UTF-8
|
|
// Linux/macOS: UTF-8 原样返回
|
|
std::string platform_2_utf8(const std::string& platform_path)
|
|
{
|
|
#ifdef _WIN32
|
|
return wide_to_mb(CP_UTF8, mb_to_wide(CP_ACP, platform_path));
|
|
#else
|
|
return platform_path;
|
|
#endif
|
|
}
|
|
|
|
|
|
// 如果外部接口传进来的是 UTF-8 字符串,用这个构造 fs::path
|
|
std::filesystem::path path_from_utf8(const std::string& utf8_path)
|
|
{
|
|
return std::filesystem::path(utf8_2_platform(utf8_path));
|
|
}
|
|
|
|
|
|
// fs::path -> 项目内部 UTF-8
|
|
std::string path_to_utf8(const std::filesystem::path& p)
|
|
{
|
|
#ifdef _WIN32
|
|
// Windows 下不要通过 p.string() 中转到 ACP,直接 wide -> UTF-8 更稳
|
|
return wide_to_mb(CP_UTF8, p.wstring());
|
|
#else
|
|
return p.string();
|
|
#endif
|
|
}
|
|
} |