blob: 6b7a54b710474c9920c86b04d314b852067d1516 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 nxtControl GmbH, ACIN
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Stanislav Meduna, Ingo Hegny, Alois Zoitl
* - initial implementation and rework communication infrastructure
*******************************************************************************/
#include "unicode_utils.h"
#include <string.h>
const TForteUInt32 CUnicodeUtilities::scm_unBOMMarker = 0xfeff;
const TForteUInt32 CUnicodeUtilities::scm_unBOMMarkerSwapped = 0xfffe;
/* RFC 3629
Char. number range | UTF-8 octet sequence
(hexadecimal) | (binary)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
int CUnicodeUtilities::parseUTF8Codepoint(const TForteByte *pa_pacCodepoint, TForteUInt32 &pa_rValue) {
if ((pa_pacCodepoint[0] & 0x80) == 0) {
pa_rValue = (pa_pacCodepoint[0] & 0x7f);
return 1;
} else if ((pa_pacCodepoint[0] & 0xe0) == 0xc0) {
if((pa_pacCodepoint[1] & 0xc0) != 0x80) {
return -1;
}
pa_rValue = ((pa_pacCodepoint[0] & 0x1f) << 6) |
(pa_pacCodepoint[1] & 0x3f);
return 2;
} else if ((pa_pacCodepoint[0] & 0xf0) == 0xe0) {
if ((pa_pacCodepoint[1] & 0xc0) != 0x80 ||
(pa_pacCodepoint[2] & 0xc0) != 0x80) {
return -1;
}
pa_rValue = ((pa_pacCodepoint[0] & 0x0f) << 12) |
((pa_pacCodepoint[1] & 0x3f) << 6) |
(pa_pacCodepoint[2] & 0x3f);
return 3;
} else if ((pa_pacCodepoint[0] & 0xf8) == 0xf0) {
if ((pa_pacCodepoint[1] & 0xc0) != 0x80 ||
(pa_pacCodepoint[2] & 0xc0) != 0x80 ||
(pa_pacCodepoint[3] & 0xc0) != 0x80) {
return -1;
}
pa_rValue = ((pa_pacCodepoint[0] & 0x07) << 18) |
((pa_pacCodepoint[1] & 0x3f) << 12) |
((pa_pacCodepoint[2] & 0x3f) << 6) |
(pa_pacCodepoint[3] & 0x3f);
return 4;
}
pa_rValue = 0;
return -1;
}
int CUnicodeUtilities::encodeUTF8Codepoint(TForteByte *pa_pacCodepoint, unsigned int pa_nBufferSize, TForteUInt32 pa_nValue) {
if (pa_nValue < 0x80) {
if (pa_pacCodepoint) {
if(pa_nBufferSize < 1) {
return -1;
}
pa_pacCodepoint[0] = (TForteByte) pa_nValue;
}
return 1;
} else if (pa_nValue < 0x800) {
if (pa_pacCodepoint) {
if(pa_nBufferSize < 2) {
return -1;
}
pa_pacCodepoint[0] = (TForteByte) (0xc0 | ((pa_nValue >> 6) & 0x1f));
pa_pacCodepoint[1] = (TForteByte) (0x80 | ((pa_nValue ) & 0x3f));
}
return 2;
} else if (pa_nValue < 0x10000) {
if (pa_pacCodepoint) {
if(pa_nBufferSize < 3) {
return -1;
}
pa_pacCodepoint[0] = (TForteByte) (0xe0 | ((pa_nValue >> 12) & 0x1f));
pa_pacCodepoint[1] = (TForteByte) (0x80 | ((pa_nValue >> 6) & 0x3f));
pa_pacCodepoint[2] = (TForteByte) (0x80 | ((pa_nValue ) & 0x3f));
}
return 3;
} else if (pa_nValue < 0x110000) {
if (pa_pacCodepoint) {
if(pa_nBufferSize < 4) {
return -1;
}
pa_pacCodepoint[0] = (TForteByte) (0xf0 | ((pa_nValue >> 18) & 0x1f));
pa_pacCodepoint[1] = (TForteByte) (0x80 | ((pa_nValue >> 12) & 0x3f));
pa_pacCodepoint[2] = (TForteByte) (0x80 | ((pa_nValue >> 6) & 0x3f));
pa_pacCodepoint[3] = (TForteByte) (0x80 | ((pa_nValue ) & 0x3f));
}
return 4;
}
return -1;
}
/*
* UTF-16 converts > 0xffff into two 16-bit code units, called a surrogate pair, by the following scheme:
*
* 0x10000 is subtracted from the code point, leaving a 20 bit number in the range 0..0xFFFFF.
* The top ten bits (a number in the range 0..0x3FF) are added to 0xD800 to give the first code unit
* or high surrogate, which will be in the range 0xD800..0xDBFF.
* The low ten bits (also in the range 0..0x3FF) are added to 0xDC00 to give the second
* code unit or low surrogate, which will be in the range 0xDC00..0xDFFF.
*/
int CUnicodeUtilities::parseUTF16Codepoint(const TForteByte *pa_pacCodepoint, TForteUInt32 &pa_rValue, bool pa_bLittleEndian) {
TForteUInt16 nFirstWord = static_cast<TForteUInt16>(pa_bLittleEndian ?
(pa_pacCodepoint[0] | (pa_pacCodepoint[1] << 8)) :
((pa_pacCodepoint[0] << 8) | pa_pacCodepoint[1]));
if ((nFirstWord & 0xfc00) == 0xd800) {
TForteUInt16 nSecondWord = static_cast<TForteUInt16>(pa_bLittleEndian ?
(pa_pacCodepoint[2] | (pa_pacCodepoint[3] << 8)) :
((pa_pacCodepoint[2] << 8) | pa_pacCodepoint[3]));
if((nSecondWord & 0xfc00) != 0xdc00) {
return -1;
}
pa_rValue = 0x10000 + (((nFirstWord & 0x3ff) << 10) | (nSecondWord & 0x3ff));
return 4;
}
pa_rValue = nFirstWord;
return 2;
}
int CUnicodeUtilities::encodeUTF16Codepoint(TForteByte *pa_pacCodepoint, unsigned int pa_nBufferSize, TForteUInt32 pa_nValue, bool pa_bLittleEndian) {
if((pa_nValue >= 0xd800 && pa_nValue < 0xe000) || pa_nValue >= 0x110000) {
return -1;
}
if (pa_nValue < 0x10000) {
if (pa_pacCodepoint) {
if(pa_nBufferSize < 2) {
return -1;
}
if (pa_bLittleEndian) {
pa_pacCodepoint[0] = (TForteByte) ((pa_nValue ) & 0xff);
pa_pacCodepoint[1] = (TForteByte) ((pa_nValue >> 8) & 0xff);
} else {
pa_pacCodepoint[0] = (TForteByte) ((pa_nValue >> 8) & 0xff);
pa_pacCodepoint[1] = (TForteByte) ((pa_nValue ) & 0xff);
}
}
return 2;
} else {
if (pa_pacCodepoint) {
TForteUInt32 nVal = pa_nValue - 0x10000;
TForteUInt16 nHighSurrogate = static_cast<TForteUInt16>(0xd800 | ((nVal >> 10) & 0x3ff));
TForteUInt16 nLowSurrogate = static_cast<TForteUInt16>(0xdc00 | ((nVal ) & 0x3ff));
if(pa_nBufferSize < 4) {
return -1;
}
if (pa_bLittleEndian) {
pa_pacCodepoint[0] = (TForteByte) ((nHighSurrogate ) & 0xff);
pa_pacCodepoint[1] = (TForteByte) ((nHighSurrogate >> 8) & 0xff);
pa_pacCodepoint[2] = (TForteByte) ((nLowSurrogate ) & 0xff);
pa_pacCodepoint[3] = (TForteByte) ((nLowSurrogate >> 8) & 0xff);
} else {
pa_pacCodepoint[0] = (TForteByte) ((nHighSurrogate >> 8) & 0xff);
pa_pacCodepoint[1] = (TForteByte) ((nHighSurrogate ) & 0xff);
pa_pacCodepoint[2] = (TForteByte) ((nLowSurrogate >> 8) & 0xff);
pa_pacCodepoint[3] = (TForteByte) ((nLowSurrogate ) & 0xff);
}
}
return 4;
}
}
int CUnicodeUtilities::checkUTF8(const char *pa_pacValue, int pa_nLength, unsigned int &pa_rnMaxWidth) {
const TForteByte *pRunner = (const TForteByte *) pa_pacValue;
size_t nRemLen = (pa_nLength == -1) ? strlen(pa_pacValue) : (size_t) pa_nLength;
TForteUInt32 nCodepoint;
int nRetVal = 0;
size_t i = 0;
pa_rnMaxWidth = 7;
while (i < nRemLen) {
int nRes = parseUTF8Codepoint(pRunner, nCodepoint);
if (nRes < 0 || nRes + i > nRemLen) {
return -1;
}
if(nCodepoint != CUnicodeUtilities::scm_unBOMMarker) {
if(nCodepoint >= 0x10000) {
pa_rnMaxWidth = 21;
} else if(nCodepoint >= 0x100 && pa_rnMaxWidth < 16) {
pa_rnMaxWidth = 16;
} else if(nCodepoint >= 0x80 && pa_rnMaxWidth < 8) {
pa_rnMaxWidth = 8;
}
}
i += nRes;
pRunner += nRes;
++nRetVal;
}
return nRetVal;
}