mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 22:03:03 +01:00
Fixed CORE-316 - Can't open database with MBCS/Extended characters in name.
Documentation soon.
This commit is contained in:
parent
0a78fd7ba4
commit
84dfa0e092
@ -107,6 +107,7 @@
|
||||
#define isc_dpb_process_name 74
|
||||
#define isc_dpb_trusted_role 75
|
||||
#define isc_dpb_org_filename 76
|
||||
#define isc_dpb_utf8_filename 77
|
||||
|
||||
/**************************************************/
|
||||
/* clumplet tags used inside isc_dpb_address_path */
|
||||
|
@ -39,6 +39,10 @@ bool ISC_check_if_remote(const Firebird::PathName&, bool);
|
||||
enum iscProtocol {ISC_PROTOCOL_LOCAL, ISC_PROTOCOL_TCPIP, ISC_PROTOCOL_WLAN};
|
||||
iscProtocol ISC_extract_host(Firebird::PathName&, Firebird::PathName&, bool);
|
||||
bool ISC_expand_filename(Firebird::PathName&, bool);
|
||||
void ISC_systemToUtf8(Firebird::PathName& pathName);
|
||||
void ISC_utf8ToSystem(Firebird::PathName& pathName);
|
||||
void ISC_escape(Firebird::PathName& pathName);
|
||||
void ISC_unescape(Firebird::PathName& pathName);
|
||||
|
||||
// This form of ISC_expand_filename makes epp files happy
|
||||
inline bool ISC_expand_filename(const TEXT* unexpanded,
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "../jrd/common.h"
|
||||
#include "gen/iberror.h"
|
||||
#include "../jrd/jrd.h"
|
||||
@ -159,6 +160,8 @@ extern "C" int mntctl(int, size_t, void*);
|
||||
#define MAXHOSTLEN 64
|
||||
#endif
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
namespace {
|
||||
typedef Firebird::PathName tstring;
|
||||
typedef tstring::size_type size;
|
||||
@ -1807,3 +1810,114 @@ static void share_name_from_unc(tstring& file_name,
|
||||
}
|
||||
#endif /* WIN_NT */
|
||||
|
||||
|
||||
// Converts a PathName from the system charset to UTF-8.
|
||||
void ISC_systemToUtf8(Firebird::PathName& pathName)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
WCHAR utf16Buffer[MAX_PATH];
|
||||
int len = MultiByteToWideChar(CP_ACP, 0, pathName.c_str(), pathName.length(),
|
||||
utf16Buffer, sizeof(utf16Buffer) / sizeof(WCHAR));
|
||||
|
||||
if (len == 0)
|
||||
status_exception::raise(Arg::Gds(isc_transliteration_failed));
|
||||
|
||||
char utf8Buffer[MAX_PATH];
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, utf16Buffer, len, utf8Buffer, sizeof(utf8Buffer),
|
||||
NULL, NULL);
|
||||
|
||||
pathName.assign(utf8Buffer, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Converts a PathName from UTF-8 to the system charset.
|
||||
void ISC_utf8ToSystem(Firebird::PathName& pathName)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
WCHAR utf16Buffer[MAX_PATH];
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, pathName.c_str(), pathName.length(),
|
||||
utf16Buffer, sizeof(utf16Buffer) / sizeof(WCHAR));
|
||||
|
||||
if (len == 0)
|
||||
status_exception::raise(Arg::Gds(isc_transliteration_failed));
|
||||
|
||||
char ansiBuffer[MAX_PATH];
|
||||
BOOL defaultCharUsed;
|
||||
len = WideCharToMultiByte(CP_ACP, 0, utf16Buffer, len, ansiBuffer, sizeof(ansiBuffer),
|
||||
NULL, &defaultCharUsed);
|
||||
|
||||
if (len == 0 || defaultCharUsed)
|
||||
status_exception::raise(Arg::Gds(isc_transliteration_failed));
|
||||
|
||||
pathName.assign(ansiBuffer, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Escape Unicode characters from a PathName
|
||||
void ISC_escape(PathName& pathName)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = pathName.find_first_of("#", pos)) != PathName::npos)
|
||||
{
|
||||
pathName.insert(pos, "#");
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unescape Unicode characters from a PathName
|
||||
void ISC_unescape(PathName& pathName)
|
||||
{
|
||||
// Macro copied from ICU headers.
|
||||
#define U8_APPEND_UNSAFE(s, i, c) { \
|
||||
if((unsigned int)(c)<=0x7f) { \
|
||||
(s)[(i)++]=(unsigned char)(c); \
|
||||
} else { \
|
||||
if((unsigned int)(c)<=0x7ff) { \
|
||||
(s)[(i)++]=(unsigned char)(((c)>>6)|0xc0); \
|
||||
} else { \
|
||||
if((unsigned int)(c)<=0xffff) { \
|
||||
(s)[(i)++]=(unsigned char)(((c)>>12)|0xe0); \
|
||||
} else { \
|
||||
(s)[(i)++]=(unsigned char)(((c)>>18)|0xf0); \
|
||||
(s)[(i)++]=(unsigned char)((((c)>>12)&0x3f)|0x80); \
|
||||
} \
|
||||
(s)[(i)++]=(unsigned char)((((c)>>6)&0x3f)|0x80); \
|
||||
} \
|
||||
(s)[(i)++]=(unsigned char)(((c)&0x3f)|0x80); \
|
||||
} \
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
while ((pos = pathName.find_first_of("#", pos)) != PathName::npos)
|
||||
{
|
||||
const char* p = pathName.c_str() + pos;
|
||||
|
||||
if (pos + 5 <= pathName.length() &&
|
||||
((p[1] >= '0' && p[1] <= '9') || (toupper(p[1]) >= 'A' && toupper(p[1]) <= 'F')) &&
|
||||
((p[2] >= '0' && p[2] <= '9') || (toupper(p[2]) >= 'A' && toupper(p[2]) <= 'F')) &&
|
||||
((p[3] >= '0' && p[3] <= '9') || (toupper(p[3]) >= 'A' && toupper(p[3]) <= 'F')) &&
|
||||
((p[4] >= '0' && p[4] <= '9') || (toupper(p[4]) >= 'A' && toupper(p[4]) <= 'F')))
|
||||
{
|
||||
char sCode[5];
|
||||
memcpy(sCode, p + 1, 4);
|
||||
sCode[4] = '\0';
|
||||
int code = strtol(sCode, NULL, 16);
|
||||
|
||||
char unicode[4];
|
||||
int len = 0;
|
||||
U8_APPEND_UNSAFE(unicode, len, code);
|
||||
|
||||
pathName.replace(pos, 5, PathName(unicode, len));
|
||||
pos += len;
|
||||
}
|
||||
else if (pos + 2 <= pathName.length() && p[1] == '#')
|
||||
pathName.erase(pos++, 1);
|
||||
else
|
||||
status_exception::raise(Arg::Gds(isc_transliteration_failed));
|
||||
}
|
||||
|
||||
#undef U8_APPEND_UNSAFE
|
||||
}
|
||||
|
@ -410,6 +410,7 @@ public:
|
||||
bool dpb_no_db_triggers;
|
||||
bool dpb_gbak_attach;
|
||||
bool dpb_trusted_role;
|
||||
bool dpb_utf8_filename;
|
||||
ULONG dpb_flags; // to OR'd with dbb_flags
|
||||
|
||||
// here begin compound objects
|
||||
@ -696,19 +697,38 @@ ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
|
||||
return user_status[1];
|
||||
}
|
||||
|
||||
const PathName file_name = options.dpb_org_filename.hasData() ?
|
||||
PathName file_name = options.dpb_org_filename.hasData() ?
|
||||
options.dpb_org_filename : filename;
|
||||
|
||||
if (options.dpb_utf8_filename)
|
||||
ISC_utf8ToSystem(file_name);
|
||||
else
|
||||
{
|
||||
ISC_systemToUtf8(file_name);
|
||||
ISC_unescape(file_name);
|
||||
ISC_utf8ToSystem(file_name);
|
||||
}
|
||||
|
||||
PathName expanded_name;
|
||||
|
||||
// Resolve given alias name
|
||||
const bool is_alias = ResolveDatabaseAlias(file_name, expanded_name);
|
||||
if (is_alias)
|
||||
{
|
||||
ISC_systemToUtf8(expanded_name);
|
||||
ISC_unescape(expanded_name);
|
||||
ISC_utf8ToSystem(expanded_name);
|
||||
ISC_expand_filename(expanded_name, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded_name = filename;
|
||||
|
||||
if (!options.dpb_utf8_filename)
|
||||
ISC_systemToUtf8(expanded_name);
|
||||
|
||||
ISC_unescape(expanded_name);
|
||||
ISC_utf8ToSystem(expanded_name);
|
||||
}
|
||||
|
||||
// Check database against conf file.
|
||||
@ -1670,18 +1690,37 @@ ISC_STATUS GDS_CREATE_DATABASE(ISC_STATUS* user_status,
|
||||
return user_status[1];
|
||||
}
|
||||
|
||||
const PathName file_name = options.dpb_org_filename.hasData() ? options.dpb_org_filename : filename;
|
||||
PathName file_name = options.dpb_org_filename.hasData() ? options.dpb_org_filename : filename;
|
||||
|
||||
if (options.dpb_utf8_filename)
|
||||
ISC_utf8ToSystem(file_name);
|
||||
else
|
||||
{
|
||||
ISC_systemToUtf8(file_name);
|
||||
ISC_unescape(file_name);
|
||||
ISC_utf8ToSystem(file_name);
|
||||
}
|
||||
|
||||
PathName expanded_name;
|
||||
|
||||
// Resolve given alias name
|
||||
const bool is_alias = ResolveDatabaseAlias(file_name, expanded_name);
|
||||
if (is_alias)
|
||||
{
|
||||
ISC_systemToUtf8(expanded_name);
|
||||
ISC_unescape(expanded_name);
|
||||
ISC_utf8ToSystem(expanded_name);
|
||||
ISC_expand_filename(expanded_name, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded_name = filename;
|
||||
|
||||
if (!options.dpb_utf8_filename)
|
||||
ISC_systemToUtf8(expanded_name);
|
||||
|
||||
ISC_unescape(expanded_name);
|
||||
ISC_utf8ToSystem(expanded_name);
|
||||
}
|
||||
|
||||
// Check database against conf file.
|
||||
@ -4520,6 +4559,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
|
||||
rdr.getPath(dpb_org_filename);
|
||||
break;
|
||||
|
||||
case isc_dpb_utf8_filename:
|
||||
dpb_utf8_filename = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1299,21 +1299,40 @@ ISC_STATUS API_ROUTINE GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
|
||||
utilities can modify it */
|
||||
|
||||
PathName org_filename(file_name, file_length ? file_length : strlen(file_name));
|
||||
org_filename.rtrim();
|
||||
|
||||
PathName expanded_filename;
|
||||
|
||||
if (!set_path(org_filename, expanded_filename))
|
||||
{
|
||||
expanded_filename = org_filename;
|
||||
ISC_expand_filename(expanded_filename, true);
|
||||
}
|
||||
|
||||
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE,
|
||||
reinterpret_cast<const UCHAR*>(dpb), dpb_length, isc_dpb_version1);
|
||||
|
||||
bool utfFilename = newDpb.find(isc_dpb_utf8_filename);
|
||||
|
||||
if (utfFilename)
|
||||
ISC_utf8ToSystem(org_filename);
|
||||
else
|
||||
newDpb.insertTag(isc_dpb_utf8_filename);
|
||||
|
||||
setLogin(newDpb);
|
||||
|
||||
org_filename.rtrim();
|
||||
|
||||
PathName expanded_filename;
|
||||
bool unescaped = false;
|
||||
|
||||
if (!set_path(org_filename, expanded_filename))
|
||||
{
|
||||
expanded_filename = org_filename;
|
||||
ISC_systemToUtf8(expanded_filename);
|
||||
ISC_unescape(expanded_filename);
|
||||
unescaped = true;
|
||||
ISC_utf8ToSystem(expanded_filename);
|
||||
ISC_expand_filename(expanded_filename, true);
|
||||
}
|
||||
|
||||
ISC_systemToUtf8(org_filename);
|
||||
ISC_systemToUtf8(expanded_filename);
|
||||
|
||||
if (unescaped)
|
||||
ISC_escape(expanded_filename);
|
||||
|
||||
if (org_filename != expanded_filename && !newDpb.find(isc_dpb_org_filename))
|
||||
{
|
||||
newDpb.insertPath(isc_dpb_org_filename, org_filename);
|
||||
@ -1860,21 +1879,40 @@ ISC_STATUS API_ROUTINE GDS_CREATE_DATABASE(ISC_STATUS* user_status,
|
||||
utilities can modify it */
|
||||
|
||||
PathName org_filename(file_name, file_length ? file_length : strlen(file_name));
|
||||
org_filename.rtrim();
|
||||
|
||||
PathName expanded_filename;
|
||||
|
||||
if (!set_path(org_filename, expanded_filename))
|
||||
{
|
||||
expanded_filename = org_filename;
|
||||
ISC_expand_filename(expanded_filename, true);
|
||||
}
|
||||
|
||||
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE,
|
||||
reinterpret_cast<const UCHAR*>(dpb), dpb_length, isc_dpb_version1);
|
||||
|
||||
bool utfFilename = newDpb.find(isc_dpb_utf8_filename);
|
||||
|
||||
if (utfFilename)
|
||||
ISC_utf8ToSystem(org_filename);
|
||||
else
|
||||
newDpb.insertTag(isc_dpb_utf8_filename);
|
||||
|
||||
setLogin(newDpb);
|
||||
|
||||
org_filename.rtrim();
|
||||
|
||||
PathName expanded_filename;
|
||||
bool unescaped = false;
|
||||
|
||||
if (!set_path(org_filename, expanded_filename))
|
||||
{
|
||||
expanded_filename = org_filename;
|
||||
ISC_systemToUtf8(expanded_filename);
|
||||
ISC_unescape(expanded_filename);
|
||||
unescaped = true;
|
||||
ISC_utf8ToSystem(expanded_filename);
|
||||
ISC_expand_filename(expanded_filename, true);
|
||||
}
|
||||
|
||||
ISC_systemToUtf8(org_filename);
|
||||
ISC_systemToUtf8(expanded_filename);
|
||||
|
||||
if (unescaped)
|
||||
ISC_escape(expanded_filename);
|
||||
|
||||
if (org_filename != expanded_filename && !newDpb.find(isc_dpb_org_filename))
|
||||
{
|
||||
newDpb.insertPath(isc_dpb_org_filename, org_filename);
|
||||
@ -1889,7 +1927,10 @@ ISC_STATUS API_ROUTINE GDS_CREATE_DATABASE(ISC_STATUS* user_status,
|
||||
#ifdef WIN_NT
|
||||
// Now we can expand, the file exists
|
||||
expanded_filename = org_filename;
|
||||
ISC_expand_filename(expanded_filename, true);
|
||||
ISC_unescape(expanded_filename);
|
||||
ISC_utf8ToSystem(expanded_filename);
|
||||
ISC_expand_filename(expanded_filename, true);
|
||||
ISC_systemToUtf8(expanded_filename);
|
||||
#endif
|
||||
|
||||
attachment = new Attachment(handle, public_handle, n);
|
||||
@ -6094,4 +6135,3 @@ ISC_STATUS API_ROUTINE fb_shutdown_callback(ISC_STATUS* user_status,
|
||||
|
||||
return status[1];
|
||||
}
|
||||
|
||||
|
@ -5727,6 +5727,21 @@ static bool init(ISC_STATUS* user_status,
|
||||
}
|
||||
#endif //TRUSTED_AUTH
|
||||
|
||||
if (port->port_protocol < PROTOCOL_VERSION12)
|
||||
{
|
||||
dpb.deleteWithTag(isc_dpb_utf8_filename);
|
||||
ISC_utf8ToSystem(file_name);
|
||||
|
||||
if (dpb.find(isc_dpb_org_filename))
|
||||
{
|
||||
PathName orgFilename;
|
||||
dpb.getPath(orgFilename);
|
||||
ISC_utf8ToSystem(orgFilename);
|
||||
dpb.deleteClumplet();
|
||||
dpb.insertPath(isc_dpb_org_filename, orgFilename);
|
||||
}
|
||||
}
|
||||
|
||||
// Make attach packet
|
||||
|
||||
P_ATCH* attach = &packet->p_atch;
|
||||
|
Loading…
Reference in New Issue
Block a user