8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-30 19:23:03 +01:00
firebird-mirror/src/intl/cv_icu.cpp

181 lines
4.2 KiB
C++
Raw Normal View History

/*
* 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(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 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) * 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;
2008-01-16 08:15:01 +01:00
switch (status)
{
case U_INVALID_CHAR_FOUND:
*errCode = CS_CONVERT_ERROR;
2008-01-16 08:15:01 +01:00
break;
case U_TRUNCATED_CHAR_FOUND:
*errCode = CS_TRUNCATION_ERROR;
2008-01-16 08:15:01 +01:00
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 / 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();
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();
cs->charset_from_unicode.csconvert_impl->cs = cs;
}