mirror of
https://github.com/holub/mame
synced 2025-04-16 21:44:32 +03:00
Tidy up loose ends:
* Fixed a couple of fixed-size buffers in Windows OSD code. * Marked MAME as aware of long paths in Windows manifest. * Made a cleaner, thread-safe API for getting volume names. * Added compile-time option to disable recompiler W^X mode. * NuBus image device current directory doesn't need to be pinned.
This commit is contained in:
parent
542cf128ba
commit
8228719f03
@ -8,8 +8,9 @@
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
<dpiAware>true</dpiAware>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
|
@ -8,8 +8,9 @@
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
<dpiAware>true</dpiAware>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
|
@ -6,12 +6,26 @@
|
||||
HFS images, including floppy images (DD and HD) and vMac/Basilisk HDD
|
||||
volumes up to 256 MB in size.
|
||||
|
||||
TODO:
|
||||
* Get get directory and get listing commands have no way to indicate
|
||||
that the path/name is too long for the buffer.
|
||||
* The set directory command doesn't work well with host filesystems that
|
||||
have roots (e.g. Windows drive letters).
|
||||
* The set directory command assumes '/' is a valid host directory
|
||||
separator character.
|
||||
* The get listing commands have no way to indicate whether an entry is
|
||||
a directory.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "nubus_image.h"
|
||||
|
||||
#include "osdcore.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
#define IMAGE_ROM_REGION "image_rom"
|
||||
#define IMAGE_DISK0_TAG "nb_disk"
|
||||
|
||||
@ -189,10 +203,9 @@ void nubus_image_device::device_start()
|
||||
|
||||
m_image = subdevice<messimg_disk_image_device>(IMAGE_DISK0_TAG);
|
||||
|
||||
filectx.curdir[0] = '.';
|
||||
filectx.curdir[1] = '\0';
|
||||
filectx.dirp = nullptr;
|
||||
filectx.fd = nullptr;
|
||||
filectx.curdir = ".";
|
||||
filectx.dirp.reset();
|
||||
filectx.fd.reset();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -251,39 +264,37 @@ void nubus_image_device::file_cmd_w(uint32_t data)
|
||||
filectx.curcmd = data;
|
||||
switch (data) {
|
||||
case kFileCmdGetDir:
|
||||
strcpy((char*)filectx.filename, (char*)filectx.curdir);
|
||||
strncpy(filectx.filename, filectx.curdir.c_str(), ARRAY_LENGTH(filectx.filename));
|
||||
break;
|
||||
case kFileCmdSetDir:
|
||||
if ((filectx.filename[0] == '/') || (filectx.filename[0] == '$')) {
|
||||
strcpy((char*)filectx.curdir, (char*)filectx.filename);
|
||||
filectx.curdir.assign(std::begin(filectx.filename), std::find(std::begin(filectx.filename), std::end(filectx.filename), '\0'));
|
||||
} else {
|
||||
strcat((char*)filectx.curdir, "/");
|
||||
strcat((char*)filectx.curdir, (char*)filectx.filename);
|
||||
filectx.curdir += '/';
|
||||
filectx.curdir.append(std::begin(filectx.filename), std::find(std::begin(filectx.filename), std::end(filectx.filename), '\0'));
|
||||
}
|
||||
break;
|
||||
case kFileCmdGetFirstListing:
|
||||
filectx.dirp = osd::directory::open((const char *)filectx.curdir);
|
||||
filectx.dirp = osd::directory::open(filectx.curdir);
|
||||
[[fallthrough]];
|
||||
case kFileCmdGetNextListing:
|
||||
if (filectx.dirp) {
|
||||
osd::directory::entry const *const dp = filectx.dirp->read();
|
||||
if (dp) {
|
||||
strncpy((char*)filectx.filename, dp->name, sizeof(filectx.filename));
|
||||
strncpy(filectx.filename, dp->name, ARRAY_LENGTH(filectx.filename));
|
||||
} else {
|
||||
memset(filectx.filename, 0, sizeof(filectx.filename));
|
||||
std::fill(std::begin(filectx.filename), std::end(filectx.filename), '\0');
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(filectx.filename, 0, sizeof(filectx.filename));
|
||||
std::fill(std::begin(filectx.filename), std::end(filectx.filename), '\0');
|
||||
}
|
||||
break;
|
||||
case kFileCmdGetFile:
|
||||
{
|
||||
std::string fullpath;
|
||||
fullpath.reserve(1024);
|
||||
fullpath.assign((const char *)filectx.curdir);
|
||||
fullpath.append(PATH_SEPARATOR);
|
||||
fullpath.append((const char*)filectx.filename);
|
||||
std::string fullpath(filectx.curdir);
|
||||
fullpath += PATH_SEPARATOR;
|
||||
fullpath.append(std::begin(filectx.filename), std::find(std::begin(filectx.filename), std::end(filectx.filename), '\0'));
|
||||
if (osd_file::open(fullpath, OPEN_FLAG_READ, filectx.fd, filectx.filelen) != osd_file::error::NONE)
|
||||
osd_printf_error("Error opening %s\n", fullpath);
|
||||
filectx.bytecount = 0;
|
||||
@ -291,11 +302,9 @@ void nubus_image_device::file_cmd_w(uint32_t data)
|
||||
break;
|
||||
case kFileCmdPutFile:
|
||||
{
|
||||
std::string fullpath;
|
||||
fullpath.reserve(1024);
|
||||
fullpath.assign((const char *)filectx.curdir);
|
||||
fullpath.append(PATH_SEPARATOR);
|
||||
fullpath.append((const char*)filectx.filename);
|
||||
std::string fullpath(filectx.curdir);
|
||||
fullpath += PATH_SEPARATOR;
|
||||
fullpath.append(std::begin(filectx.filename), std::find(std::begin(filectx.filename), std::end(filectx.filename), '\0'));
|
||||
uint64_t filesize; // unused, but it's an output from the open call
|
||||
if (osd_file::open(fullpath, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, filectx.fd, filesize) != osd_file::error::NONE)
|
||||
osd_printf_error("Error opening %s\n", fullpath);
|
||||
@ -356,12 +365,10 @@ uint32_t nubus_image_device::file_len_r()
|
||||
|
||||
void nubus_image_device::file_name_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
((uint32_t*)(filectx.filename))[offset] = big_endianize_int32(data);
|
||||
reinterpret_cast<uint32_t *>(filectx.filename)[offset] = big_endianize_int32(data);
|
||||
}
|
||||
|
||||
uint32_t nubus_image_device::file_name_r(offs_t offset)
|
||||
{
|
||||
uint32_t ret;
|
||||
ret = big_endianize_int32(((uint32_t*)(filectx.filename))[offset]);
|
||||
return ret;
|
||||
return big_endianize_int32(reinterpret_cast<uint32_t const *>(filectx.filename)[offset]);
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ protected:
|
||||
struct nbfilectx
|
||||
{
|
||||
uint32_t curcmd;
|
||||
uint8_t filename[128];
|
||||
uint8_t curdir[1024];
|
||||
char filename[128];
|
||||
std::string curdir;
|
||||
osd::directory::ptr dirp;
|
||||
osd_file::ptr fd;
|
||||
uint64_t filelen;
|
||||
|
@ -14,6 +14,10 @@
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
// this improves performance of some emulated systems but doesn't work on W^X hosts
|
||||
//#define MAME_DRC_CACHE_RWX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T, typename U> constexpr T *ALIGN_PTR_UP(T *p, U align)
|
||||
@ -59,7 +63,11 @@ drc_cache::drc_cache(size_t bytes) :
|
||||
std::fill(std::begin(m_free), std::end(m_free), nullptr);
|
||||
std::fill(std::begin(m_nearfree), std::end(m_nearfree), nullptr);
|
||||
|
||||
#if defined(MAME_DRC_CACHE_RWX)
|
||||
m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE | osd::virtual_memory_allocation::EXECUTE);
|
||||
#else // defined(MAME_DRC_CACHE_RWX)
|
||||
m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
|
||||
#endif // defined(MAME_DRC_CACHE_RWX)
|
||||
}
|
||||
|
||||
|
||||
@ -84,11 +92,7 @@ void drc_cache::flush()
|
||||
|
||||
// just reset the top back to the base and re-seed
|
||||
m_top = m_base;
|
||||
if (m_executable)
|
||||
{
|
||||
m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
|
||||
m_executable = false;
|
||||
}
|
||||
codegen_init();
|
||||
}
|
||||
|
||||
|
||||
@ -174,11 +178,7 @@ void *drc_cache::alloc_temporary(size_t bytes)
|
||||
return nullptr;
|
||||
|
||||
// otherwise, update the cache top
|
||||
if (m_executable)
|
||||
{
|
||||
m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
|
||||
m_executable = false;
|
||||
}
|
||||
codegen_init();
|
||||
m_top = ALIGN_PTR_UP(ptr + bytes, CACHE_ALIGNMENT);
|
||||
return ptr;
|
||||
}
|
||||
@ -209,7 +209,9 @@ void drc_cache::codegen_init()
|
||||
{
|
||||
if (m_executable)
|
||||
{
|
||||
#if !defined(MAME_DRC_CACHE_RWX)
|
||||
m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
|
||||
#endif // !defined(MAME_DRC_CACHE_RWX)
|
||||
m_executable = false;
|
||||
}
|
||||
}
|
||||
@ -219,7 +221,9 @@ void drc_cache::codegen_complete()
|
||||
{
|
||||
if (!m_executable)
|
||||
{
|
||||
#if !defined(MAME_DRC_CACHE_RWX)
|
||||
m_cache.set_access(m_base - m_near, ALIGN_PTR_UP(m_top, m_cache.page_size()) - m_base, osd::virtual_memory_allocation::READ_EXECUTE);
|
||||
#endif // !defined(MAME_DRC_CACHE_RWX)
|
||||
m_executable = true;
|
||||
}
|
||||
}
|
||||
@ -240,11 +244,7 @@ drccodeptr *drc_cache::begin_codegen(uint32_t reserve_bytes)
|
||||
return nullptr;
|
||||
|
||||
// otherwise, return a pointer to the cache top
|
||||
if (m_executable)
|
||||
{
|
||||
m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
|
||||
m_executable = false;
|
||||
}
|
||||
codegen_init();
|
||||
m_codegen = m_top;
|
||||
return &m_top;
|
||||
}
|
||||
|
@ -384,13 +384,12 @@ void menu_add_change_folder::handle()
|
||||
void menu_add_change_folder::populate(float &customtop, float &custombottom)
|
||||
{
|
||||
// open a path
|
||||
const char *volume_name = nullptr;
|
||||
file_enumerator path(m_current_path.c_str());
|
||||
const osd::directory::entry *dirent;
|
||||
int folders_count = 0;
|
||||
|
||||
// add the drives
|
||||
for (int i = 0; (volume_name = osd_get_volume_name(i)) != nullptr; ++i)
|
||||
for (std::string const &volume_name : osd_get_volume_names())
|
||||
item_append(volume_name, "[DRIVE]", 0, (void *)(uintptr_t)++folders_count);
|
||||
|
||||
// add the directories
|
||||
|
@ -413,8 +413,7 @@ void menu_file_selector::populate(float &customtop, float &custombottom)
|
||||
selected_entry = &append_entry(SELECTOR_ENTRY_TYPE_SOFTWARE_LIST, "", "");
|
||||
|
||||
// add the drives
|
||||
int i = 0;
|
||||
for (char const *volume_name = osd_get_volume_name(i); volume_name; volume_name = osd_get_volume_name(++i))
|
||||
for (std::string const &volume_name : osd_get_volume_names())
|
||||
append_entry(SELECTOR_ENTRY_TYPE_DRIVE, volume_name, volume_name);
|
||||
|
||||
// mark first filename entry
|
||||
|
@ -993,13 +993,12 @@ void debug_imgui::refresh_filelist()
|
||||
{
|
||||
int x = 0;
|
||||
// add drives
|
||||
const char *volume_name;
|
||||
while((volume_name = osd_get_volume_name(x))!=nullptr)
|
||||
for(std::string const &volume_name : osd_get_volume_names())
|
||||
{
|
||||
file_entry temp;
|
||||
temp.type = file_entry_type::DRIVE;
|
||||
temp.basename = std::string(volume_name);
|
||||
temp.fullpath = std::string(volume_name);
|
||||
temp.basename = volume_name;
|
||||
temp.fullpath = volume_name;
|
||||
m_filelist.emplace_back(std::move(temp));
|
||||
x++;
|
||||
}
|
||||
|
@ -469,12 +469,22 @@ bool osd_is_absolute_path(std::string const &path)
|
||||
// osd_get_volume_name
|
||||
//============================================================
|
||||
|
||||
const char *osd_get_volume_name(int idx)
|
||||
std::string osd_get_volume_name(int idx)
|
||||
{
|
||||
if (idx == 0)
|
||||
return "/";
|
||||
else
|
||||
return nullptr;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// osd_get_volume_names
|
||||
//============================================================
|
||||
|
||||
std::vector<std::string> osd_get_volume_names()
|
||||
{
|
||||
return std::vector<std::string>{ "/" };
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class std_osd_file : public osd_file
|
||||
{
|
||||
public:
|
||||
@ -245,8 +246,19 @@ bool osd_is_absolute_path(std::string const &path)
|
||||
// osd_get_volume_name
|
||||
//============================================================
|
||||
|
||||
const char *osd_get_volume_name(int idx)
|
||||
std::string osd_get_volume_name(int idx)
|
||||
{
|
||||
// we don't expose volumes
|
||||
return nullptr;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// osd_get_volume_names
|
||||
//============================================================
|
||||
|
||||
std::vector<std::string> osd_get_volume_names()
|
||||
{
|
||||
// we don't expose volumes
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
// standard windows headers
|
||||
#include <windows.h>
|
||||
@ -31,6 +32,7 @@
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
//============================================================
|
||||
// TYPE DEFINITIONS
|
||||
//============================================================
|
||||
@ -399,16 +401,19 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path)
|
||||
|
||||
osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
|
||||
{
|
||||
// convert the path to TCHARs
|
||||
osd::text::tstring t_path = osd::text::to_tstring(path);
|
||||
// get the length of the full path
|
||||
std::wstring const w_path(osd::text::to_wstring(path));
|
||||
DWORD const length(GetFullPathNameW(w_path.c_str(), 0, nullptr, nullptr));
|
||||
if (!length)
|
||||
return win_error_to_file_error(GetLastError());
|
||||
|
||||
// canonicalize the path
|
||||
TCHAR buffer[MAX_PATH];
|
||||
if (!GetFullPathName(t_path.c_str(), ARRAY_LENGTH(buffer), buffer, nullptr))
|
||||
// allocate a buffer and get the canonical path
|
||||
std::unique_ptr<wchar_t []> buffer(std::make_unique<wchar_t []>(length));
|
||||
if (!GetFullPathNameW(w_path.c_str(), length, buffer.get(), nullptr))
|
||||
return win_error_to_file_error(GetLastError());
|
||||
|
||||
// convert the result back to UTF-8
|
||||
osd::text::from_tstring(dst, buffer);
|
||||
osd::text::from_wstring(dst, buffer.get());
|
||||
return osd_file::error::NONE;
|
||||
}
|
||||
|
||||
@ -420,8 +425,7 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
|
||||
|
||||
bool osd_is_absolute_path(std::string const &path)
|
||||
{
|
||||
osd::text::tstring t_path = osd::text::to_tstring(path);
|
||||
return !PathIsRelative(t_path.c_str());
|
||||
return !PathIsRelativeW(osd::text::to_wstring(path).c_str());
|
||||
}
|
||||
|
||||
|
||||
@ -430,20 +434,57 @@ bool osd_is_absolute_path(std::string const &path)
|
||||
// osd_get_volume_name
|
||||
//============================================================
|
||||
|
||||
const char *osd_get_volume_name(int idx)
|
||||
std::string osd_get_volume_name(int idx)
|
||||
{
|
||||
static char szBuffer[128];
|
||||
const char *p;
|
||||
std::vector<wchar_t> buffer;
|
||||
DWORD length(GetLogicalDriveStringsW(0, nullptr));
|
||||
while (length && (buffer.size() < (length + 1)))
|
||||
{
|
||||
buffer.clear();
|
||||
buffer.resize(length + 1);
|
||||
length = GetLogicalDriveStringsW(length, &buffer[0]);
|
||||
}
|
||||
if (!length)
|
||||
return std::string();
|
||||
|
||||
GetLogicalDriveStringsA(ARRAY_LENGTH(szBuffer), szBuffer);
|
||||
|
||||
p = szBuffer;
|
||||
while(idx--) {
|
||||
p += strlen(p) + 1;
|
||||
if (!*p) return nullptr;
|
||||
wchar_t const *p(&buffer[0]);
|
||||
while (idx-- && *p)
|
||||
{
|
||||
while (*p++) { }
|
||||
}
|
||||
|
||||
return p;
|
||||
std::string result;
|
||||
osd::text::from_wstring(result, p);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// osd_get_volume_names
|
||||
//============================================================
|
||||
|
||||
std::vector<std::string> osd_get_volume_names()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::vector<wchar_t> buffer;
|
||||
DWORD length(GetLogicalDriveStringsW(0, nullptr));
|
||||
while (length && (buffer.size() < (length + 1)))
|
||||
{
|
||||
buffer.clear();
|
||||
buffer.resize(length + 1);
|
||||
length = GetLogicalDriveStringsW(length, &buffer[0]);
|
||||
}
|
||||
if (!length)
|
||||
return result;
|
||||
|
||||
wchar_t const *p(&buffer[0]);
|
||||
std::wstring vol;
|
||||
while (*p)
|
||||
{
|
||||
osd::text::from_wstring(result.emplace_back(), p);
|
||||
while (*p++) { }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -380,9 +380,19 @@ bool osd_is_absolute_path(std::string const &path)
|
||||
// osd_get_volume_name
|
||||
//============================================================
|
||||
|
||||
const char *osd_get_volume_name(int idx)
|
||||
std::string osd_get_volume_name(int idx)
|
||||
{
|
||||
return nullptr;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// osd_get_volume_names
|
||||
//============================================================
|
||||
|
||||
std::vector<std::string> osd_get_volume_names()
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,8 +81,8 @@ public:
|
||||
|
||||
std::wstring enum_key(int index) const
|
||||
{
|
||||
WCHAR keyname[MAX_PATH];
|
||||
DWORD namelen = MAX_PATH;
|
||||
WCHAR keyname[256];
|
||||
DWORD namelen = ARRAY_LENGTH(keyname);
|
||||
if (RegEnumKeyEx(m_key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
return std::wstring(keyname, namelen);
|
||||
else
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
@ -312,9 +313,15 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path);
|
||||
|
||||
/// \brief Retrieves the volume name.
|
||||
///
|
||||
/// \param [in] idx Order number of volume.
|
||||
/// \return Pointer to volume name.
|
||||
const char *osd_get_volume_name(int idx);
|
||||
/// \param [in] idx Index number of volume.
|
||||
/// \return Volume name or empty string of out of range.
|
||||
std::string osd_get_volume_name(int idx);
|
||||
|
||||
|
||||
/// \brief Retrieves volume names.
|
||||
///
|
||||
/// \return Names of all mounted volumes.
|
||||
std::vector<std::string> osd_get_volume_names();
|
||||
|
||||
|
||||
#endif // MAME_OSD_OSDFILE_H
|
||||
|
@ -103,15 +103,19 @@ BOOL win_is_gui_application()
|
||||
//============================================================
|
||||
void osd_subst_env(std::string &dst, const std::string &src)
|
||||
{
|
||||
TCHAR buffer[MAX_PATH];
|
||||
|
||||
osd::text::tstring t_src = osd::text::to_tstring(src);
|
||||
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
|
||||
ExpandEnvironmentStrings(t_src.c_str(), buffer, ARRAY_LENGTH(buffer));
|
||||
#else
|
||||
wcsncpy(buffer, t_src.c_str(), ARRAY_LENGTH(buffer));
|
||||
#endif
|
||||
osd::text::from_tstring(dst, buffer);
|
||||
std::wstring const w_src = osd::text::to_wstring(src);
|
||||
std::vector<wchar_t> buffer(w_src.size() + 2);
|
||||
DWORD length(ExpandEnvironmentStringsW(w_src.c_str(), &buffer[0], buffer.size()));
|
||||
while (length && (buffer.size() < length))
|
||||
{
|
||||
buffer.clear();
|
||||
buffer.resize(length + 1);
|
||||
length = ExpandEnvironmentStringsW(w_src.c_str(), &buffer[0], buffer.size());
|
||||
}
|
||||
if (length)
|
||||
osd::text::from_wstring(dst, &buffer[0]);
|
||||
else
|
||||
dst.clear();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user