8
0
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:
asfernandes 2008-12-15 14:59:34 +00:00
parent 0a78fd7ba4
commit 84dfa0e092
6 changed files with 239 additions and 22 deletions

View File

@ -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 */

View File

@ -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,

View File

@ -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
}

View File

@ -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;
}

View File

@ -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];
}

View File

@ -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;