8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 04:43:02 +01:00
firebird-mirror/src/intl/cv_icu.cpp

188 lines
4.4 KiB
C++

/*
* PROGRAM: Firebird International support
* MODULE: cv_icu.cpp
* DESCRIPTION: Codeset conversion for ICU character sets.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2004 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../intl/ldcommon.h"
#include "ld_proto.h"
#include "cv_icu.h"
#include "unicode/ucnv.h"
namespace
{
struct CsConvertImpl
{
charset* cs;
};
}
static UConverter* create_converter(csconvert* cv, UErrorCode* status)
{
UConverter* conv = ucnv_open(
static_cast<CsConvertImpl*>(cv->csconvert_impl)->cs->charset_name, status);
const void* oldContext;
UConverterFromUCallback oldFromAction;
ucnv_setFromUCallBack(
conv,
UCNV_FROM_U_CALLBACK_STOP,
NULL,
&oldFromAction,
&oldContext,
status);
UConverterToUCallback oldToAction;
ucnv_setToUCallBack(
conv,
UCNV_TO_U_CALLBACK_STOP,
NULL,
&oldToAction,
&oldContext,
status);
fb_assert(U_SUCCESS(*status));
return conv;
}
static void convert_destroy(csconvert* cv)
{
delete static_cast<CsConvertImpl*>(cv->csconvert_impl);
}
static ULONG unicode_to_icu(csconvert* cv,
ULONG srcLen,
const BYTE* src,
ULONG dstLen,
BYTE* dst,
USHORT* errCode,
ULONG* errPosition)
{
*errCode = 0;
*errPosition = 0;
if (dst == NULL)
{
return srcLen / sizeof(UChar) *
static_cast<CsConvertImpl*>(cv->csconvert_impl)->cs->charset_max_bytes_per_char;
}
UErrorCode status = U_ZERO_ERROR;
UConverter* conv = create_converter(cv, &status);
ULONG len = ucnv_fromUChars(conv, reinterpret_cast<char*>(dst), dstLen,
Firebird::Aligner<UChar>(src, srcLen), srcLen / sizeof(UChar), &status);
if (!U_SUCCESS(status))
{
len = INTL_BAD_STR_LENGTH;
switch (status)
{
case U_INVALID_CHAR_FOUND:
*errCode = CS_CONVERT_ERROR;
break;
case U_TRUNCATED_CHAR_FOUND:
*errCode = CS_TRUNCATION_ERROR;
break;
default:
fb_assert(false);
*errCode = CS_CONVERT_ERROR;
}
}
ucnv_close(conv);
return len;
}
static ULONG icu_to_unicode(csconvert* cv,
ULONG srcLen,
const BYTE* src,
ULONG dstLen,
BYTE* dst,
USHORT* errCode,
ULONG* errPosition)
{
*errCode = 0;
*errPosition = 0;
if (dst == NULL)
{
return srcLen / static_cast<CsConvertImpl*>(cv->csconvert_impl)->cs->charset_min_bytes_per_char *
sizeof(UChar);
}
UErrorCode status = U_ZERO_ERROR;
UConverter* conv = create_converter(cv, &status);
ULONG len = ucnv_toUChars(conv, Firebird::OutAligner<UChar>(dst, dstLen), dstLen / sizeof(UChar),
reinterpret_cast<const char*>(src), srcLen, &status);
if (!U_SUCCESS(status))
{
len = INTL_BAD_STR_LENGTH;
if (status == U_INVALID_CHAR_FOUND)
*errCode = CS_BAD_INPUT;
else if (status == U_TRUNCATED_CHAR_FOUND)
*errCode = CS_TRUNCATION_ERROR;
else
{
fb_assert(false);
*errCode = CS_BAD_INPUT;
}
}
else
len *= sizeof(UChar);
ucnv_close(conv);
return len;
}
void CVICU_convert_init(charset* cs)
{
cs->charset_to_unicode.csconvert_version = CSCONVERT_VERSION_1;
cs->charset_to_unicode.csconvert_name = "ICU->UNICODE";
cs->charset_to_unicode.csconvert_fn_convert = icu_to_unicode;
cs->charset_to_unicode.csconvert_fn_destroy = convert_destroy;
cs->charset_to_unicode.csconvert_impl = new CsConvertImpl();
static_cast<CsConvertImpl*>(cs->charset_to_unicode.csconvert_impl)->cs = cs;
cs->charset_from_unicode.csconvert_version = CSCONVERT_VERSION_1;
cs->charset_from_unicode.csconvert_name = "UNICODE->ICU";
cs->charset_from_unicode.csconvert_fn_convert = unicode_to_icu;
cs->charset_from_unicode.csconvert_fn_destroy = convert_destroy;
cs->charset_from_unicode.csconvert_impl = new CsConvertImpl();
static_cast<CsConvertImpl*>(cs->charset_from_unicode.csconvert_impl)->cs = cs;
}