775 lines
24 KiB
C++
775 lines
24 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
|
** Copyright (C) 2013 Intel Corporation
|
|
** Contact: http://www.qt-project.org/legal
|
|
**
|
|
** This file is part of the QtCore module of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qutfcodec_p.h"
|
|
#include "qlist.h"
|
|
#include "qendian.h"
|
|
#include "qchar.h"
|
|
|
|
#include "private/qsimd_p.h"
|
|
#include "private/qstringiterator_p.h"
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
enum { Endian = 0, Data = 1 };
|
|
|
|
static const uchar utf8bom[] = { 0xef, 0xbb, 0xbf };
|
|
|
|
#if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSE2)
|
|
static inline bool simdEncodeAscii(uchar *&dst, const ushort *&nextAscii, const ushort *&src, const ushort *end)
|
|
{
|
|
// do sixteen characters at a time
|
|
for ( ; end - src >= 16; src += 16, dst += 16) {
|
|
__m128i data1 = _mm_loadu_si128((__m128i*)src);
|
|
__m128i data2 = _mm_loadu_si128(1+(__m128i*)src);
|
|
|
|
|
|
// check if everything is ASCII
|
|
// the highest ASCII value is U+007F
|
|
// Do the packing directly:
|
|
// The PACKUSWB instruction has packs a signed 16-bit integer to an unsigned 8-bit
|
|
// with saturation. That is, anything from 0x0100 to 0x7fff is saturated to 0xff,
|
|
// while all negatives (0x8000 to 0xffff) get saturated to 0x00. To detect non-ASCII,
|
|
// we simply do a signed greater-than comparison to 0x00. That means we detect NULs as
|
|
// "non-ASCII", but it's an acceptable compromise.
|
|
__m128i packed = _mm_packus_epi16(data1, data2);
|
|
__m128i nonAscii = _mm_cmpgt_epi8(packed, _mm_setzero_si128());
|
|
|
|
// n will contain 1 bit set per character in [data1, data2] that is non-ASCII (or NUL)
|
|
ushort n = ~_mm_movemask_epi8(nonAscii);
|
|
if (n) {
|
|
// copy the front part that is still ASCII
|
|
while (!(n & 1)) {
|
|
*dst++ = *src++;
|
|
n >>= 1;
|
|
}
|
|
|
|
// find the next probable ASCII character
|
|
// we don't want to load 32 bytes again in this loop if we know there are non-ASCII
|
|
// characters still coming
|
|
n = _bit_scan_reverse(n);
|
|
nextAscii = src + n + 1;
|
|
return false;
|
|
}
|
|
|
|
// pack
|
|
_mm_storeu_si128((__m128i*)dst, packed);
|
|
}
|
|
return src == end;
|
|
}
|
|
|
|
static inline bool simdDecodeAscii(ushort *&dst, const uchar *&nextAscii, const uchar *&src, const uchar *end)
|
|
{
|
|
// do sixteen characters at a time
|
|
for ( ; end - src >= 16; src += 16, dst += 16) {
|
|
__m128i data = _mm_loadu_si128((__m128i*)src);
|
|
|
|
// check if everything is ASCII
|
|
// movemask extracts the high bit of every byte, so n is non-zero if something isn't ASCII
|
|
uint n = _mm_movemask_epi8(data);
|
|
if (n) {
|
|
// copy the front part that is still ASCII
|
|
while (!(n & 1)) {
|
|
*dst++ = *src++;
|
|
n >>= 1;
|
|
}
|
|
|
|
// find the next probable ASCII character
|
|
// we don't want to load 16 bytes again in this loop if we know there are non-ASCII
|
|
// characters still coming
|
|
n = _bit_scan_reverse(n);
|
|
nextAscii = src + n + 1;
|
|
return false;
|
|
}
|
|
|
|
// unpack
|
|
_mm_storeu_si128((__m128i*)dst, _mm_unpacklo_epi8(data, _mm_setzero_si128()));
|
|
_mm_storeu_si128(1+(__m128i*)dst, _mm_unpackhi_epi8(data, _mm_setzero_si128()));
|
|
}
|
|
return src == end;
|
|
}
|
|
#else
|
|
static inline bool simdEncodeAscii(uchar *, const ushort *, const ushort *, const ushort *)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline bool simdDecodeAscii(ushort *, const uchar *, const uchar *, const uchar *)
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len)
|
|
{
|
|
// create a QByteArray with the worst case scenario size
|
|
QByteArray result(len * 3, Qt::Uninitialized);
|
|
uchar *dst = reinterpret_cast<uchar *>(const_cast<char *>(result.constData()));
|
|
const ushort *src = reinterpret_cast<const ushort *>(uc);
|
|
const ushort *const end = src + len;
|
|
|
|
while (src != end) {
|
|
const ushort *nextAscii = end;
|
|
if (simdEncodeAscii(dst, nextAscii, src, end))
|
|
break;
|
|
|
|
do {
|
|
ushort uc = *src++;
|
|
int res = QUtf8Functions::toUtf8<QUtf8BaseTraits>(uc, dst, src, end);
|
|
if (res < 0) {
|
|
// encoding error - append '?'
|
|
*dst++ = '?';
|
|
}
|
|
} while (src < nextAscii);
|
|
}
|
|
|
|
result.truncate(dst - reinterpret_cast<uchar *>(const_cast<char *>(result.constData())));
|
|
return result;
|
|
}
|
|
|
|
QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state)
|
|
{
|
|
uchar replacement = '?';
|
|
int rlen = 3*len;
|
|
int surrogate_high = -1;
|
|
if (state) {
|
|
if (state->flags & QTextCodec::ConvertInvalidToNull)
|
|
replacement = 0;
|
|
if (!(state->flags & QTextCodec::IgnoreHeader))
|
|
rlen += 3;
|
|
if (state->remainingChars)
|
|
surrogate_high = state->state_data[0];
|
|
}
|
|
|
|
|
|
QByteArray rstr(rlen, Qt::Uninitialized);
|
|
uchar *cursor = reinterpret_cast<uchar *>(const_cast<char *>(rstr.constData()));
|
|
const ushort *src = reinterpret_cast<const ushort *>(uc);
|
|
const ushort *const end = src + len;
|
|
|
|
int invalid = 0;
|
|
if (state && !(state->flags & QTextCodec::IgnoreHeader)) {
|
|
// append UTF-8 BOM
|
|
*cursor++ = utf8bom[0];
|
|
*cursor++ = utf8bom[1];
|
|
*cursor++ = utf8bom[2];
|
|
}
|
|
|
|
const ushort *nextAscii = src;
|
|
while (src != end) {
|
|
int res;
|
|
ushort uc;
|
|
if (surrogate_high != -1) {
|
|
uc = surrogate_high;
|
|
surrogate_high = -1;
|
|
res = QUtf8Functions::toUtf8<QUtf8BaseTraits>(uc, cursor, src, end);
|
|
} else {
|
|
if (src >= nextAscii && simdEncodeAscii(cursor, nextAscii, src, end))
|
|
break;
|
|
|
|
uc = *src++;
|
|
res = QUtf8Functions::toUtf8<QUtf8BaseTraits>(uc, cursor, src, end);
|
|
}
|
|
if (Q_LIKELY(res >= 0))
|
|
continue;
|
|
|
|
if (res == QUtf8BaseTraits::Error) {
|
|
// encoding error
|
|
++invalid;
|
|
*cursor++ = replacement;
|
|
} else if (res == QUtf8BaseTraits::EndOfString) {
|
|
surrogate_high = uc;
|
|
break;
|
|
}
|
|
}
|
|
|
|
rstr.resize(cursor - (const uchar*)rstr.constData());
|
|
if (state) {
|
|
state->invalidChars += invalid;
|
|
state->flags |= QTextCodec::IgnoreHeader;
|
|
state->remainingChars = 0;
|
|
if (surrogate_high >= 0) {
|
|
state->remainingChars = 1;
|
|
state->state_data[0] = surrogate_high;
|
|
}
|
|
}
|
|
return rstr;
|
|
}
|
|
|
|
QString QUtf8::convertToUnicode(const char *chars, int len)
|
|
{
|
|
QString result(len + 1, Qt::Uninitialized); // worst case
|
|
ushort *dst = reinterpret_cast<ushort *>(const_cast<QChar *>(result.constData()));
|
|
const uchar *src = reinterpret_cast<const uchar *>(chars);
|
|
const uchar *end = src + len;
|
|
|
|
// attempt to do a full decoding in SIMD
|
|
const uchar *nextAscii = end;
|
|
if (!simdDecodeAscii(dst, nextAscii, src, end)) {
|
|
// at least one non-ASCII entry
|
|
// check if we failed to decode the UTF-8 BOM; if so, skip it
|
|
if (Q_UNLIKELY(src == reinterpret_cast<const uchar *>(chars))
|
|
&& end - src >= 3
|
|
&& Q_UNLIKELY(src[0] == utf8bom[0] && src[1] == utf8bom[1] && src[2] == utf8bom[2])) {
|
|
src += 3;
|
|
}
|
|
|
|
while (src < end) {
|
|
nextAscii = end;
|
|
if (simdDecodeAscii(dst, nextAscii, src, end))
|
|
break;
|
|
|
|
do {
|
|
uchar b = *src++;
|
|
int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, dst, src, end);
|
|
if (res < 0) {
|
|
// decoding error
|
|
*dst++ = QChar::ReplacementCharacter;
|
|
}
|
|
} while (src < nextAscii);
|
|
}
|
|
}
|
|
|
|
result.truncate(dst - reinterpret_cast<const ushort *>(result.constData()));
|
|
return result;
|
|
}
|
|
|
|
QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state)
|
|
{
|
|
bool headerdone = false;
|
|
ushort replacement = QChar::ReplacementCharacter;
|
|
int need = 0;
|
|
int invalid = 0;
|
|
int res;
|
|
uchar ch = 0;
|
|
|
|
QString result(need + len + 1, Qt::Uninitialized); // worst case
|
|
ushort *dst = reinterpret_cast<ushort *>(const_cast<QChar *>(result.constData()));
|
|
const uchar *src = reinterpret_cast<const uchar *>(chars);
|
|
const uchar *end = src + len;
|
|
|
|
if (state) {
|
|
if (state->flags & QTextCodec::IgnoreHeader)
|
|
headerdone = true;
|
|
if (state->flags & QTextCodec::ConvertInvalidToNull)
|
|
replacement = QChar::Null;
|
|
if (state->remainingChars) {
|
|
// handle incoming state first
|
|
uchar remainingCharsData[4]; // longest UTF-8 sequence possible
|
|
int remainingCharsCount = state->remainingChars;
|
|
int newCharsToCopy = qMin<int>(sizeof(remainingCharsData) - remainingCharsCount, end - src);
|
|
|
|
memset(remainingCharsData, 0, sizeof(remainingCharsData));
|
|
memcpy(remainingCharsData, &state->state_data[0], remainingCharsCount);
|
|
memcpy(remainingCharsData + remainingCharsCount, src, newCharsToCopy);
|
|
|
|
const uchar *begin = &remainingCharsData[1];
|
|
res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(remainingCharsData[0], dst, begin,
|
|
static_cast<const uchar *>(remainingCharsData) + remainingCharsCount + newCharsToCopy);
|
|
if (res == QUtf8BaseTraits::EndOfString) {
|
|
// if we got EndOfString again, then there were too few bytes in src;
|
|
// copy to our state and return
|
|
state->remainingChars = remainingCharsCount + newCharsToCopy;
|
|
memcpy(&state->state_data[0], remainingCharsData, state->remainingChars);
|
|
return QString();
|
|
} else if (res == QUtf8BaseTraits::Error) {
|
|
++invalid;
|
|
*dst++ = replacement;
|
|
} else if (!headerdone && res >= 0) {
|
|
// eat the UTF-8 BOM
|
|
headerdone = true;
|
|
if (dst[-1] == 0xfeff)
|
|
--dst;
|
|
}
|
|
|
|
// adjust src now that we have maybe consumed a few chars
|
|
//Q_ASSERT(res > remainingCharsCount)
|
|
src += res - remainingCharsCount;
|
|
}
|
|
}
|
|
|
|
// main body, stateless decoding
|
|
res = 0;
|
|
const uchar *nextAscii = src;
|
|
while (res >= 0 && src < end) {
|
|
if (src >= nextAscii && simdDecodeAscii(dst, nextAscii, src, end))
|
|
break;
|
|
|
|
ch = *src++;
|
|
res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(ch, dst, src, end);
|
|
if (!headerdone && res >= 0) {
|
|
headerdone = true;
|
|
// eat the UTF-8 BOM
|
|
if (dst[-1] == 0xfeff)
|
|
--dst;
|
|
}
|
|
if (res == QUtf8BaseTraits::Error) {
|
|
res = 0;
|
|
++invalid;
|
|
*dst++ = replacement;
|
|
}
|
|
}
|
|
|
|
if (!state && res == QUtf8BaseTraits::EndOfString) {
|
|
// unterminated UTF sequence
|
|
*dst++ = QChar::ReplacementCharacter;
|
|
while (src++ < end)
|
|
*dst++ = QChar::ReplacementCharacter;
|
|
}
|
|
|
|
result.truncate(dst - (ushort *)result.unicode());
|
|
if (state) {
|
|
state->invalidChars += invalid;
|
|
if (headerdone)
|
|
state->flags |= QTextCodec::IgnoreHeader;
|
|
if (res == QUtf8BaseTraits::EndOfString) {
|
|
--src; // unread the byte in ch
|
|
state->remainingChars = end - src;
|
|
memcpy(&state->state_data[0], src, end - src);
|
|
} else {
|
|
state->remainingChars = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QByteArray QUtf16::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e)
|
|
{
|
|
DataEndianness endian = e;
|
|
int length = 2*len;
|
|
if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) {
|
|
length += 2;
|
|
}
|
|
if (e == DetectEndianness) {
|
|
endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
|
|
}
|
|
|
|
QByteArray d;
|
|
d.resize(length);
|
|
char *data = d.data();
|
|
if (!state || !(state->flags & QTextCodec::IgnoreHeader)) {
|
|
QChar bom(QChar::ByteOrderMark);
|
|
if (endian == BigEndianness) {
|
|
data[0] = bom.row();
|
|
data[1] = bom.cell();
|
|
} else {
|
|
data[0] = bom.cell();
|
|
data[1] = bom.row();
|
|
}
|
|
data += 2;
|
|
}
|
|
if (endian == BigEndianness) {
|
|
for (int i = 0; i < len; ++i) {
|
|
*(data++) = uc[i].row();
|
|
*(data++) = uc[i].cell();
|
|
}
|
|
} else {
|
|
for (int i = 0; i < len; ++i) {
|
|
*(data++) = uc[i].cell();
|
|
*(data++) = uc[i].row();
|
|
}
|
|
}
|
|
|
|
if (state) {
|
|
state->remainingChars = 0;
|
|
state->flags |= QTextCodec::IgnoreHeader;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
QString QUtf16::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e)
|
|
{
|
|
DataEndianness endian = e;
|
|
bool half = false;
|
|
uchar buf = 0;
|
|
bool headerdone = false;
|
|
if (state) {
|
|
headerdone = state->flags & QTextCodec::IgnoreHeader;
|
|
if (endian == DetectEndianness)
|
|
endian = (DataEndianness)state->state_data[Endian];
|
|
if (state->remainingChars) {
|
|
half = true;
|
|
buf = state->state_data[Data];
|
|
}
|
|
}
|
|
if (headerdone && endian == DetectEndianness)
|
|
endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
|
|
|
|
QString result(len, Qt::Uninitialized); // worst case
|
|
QChar *qch = (QChar *)result.unicode();
|
|
while (len--) {
|
|
if (half) {
|
|
QChar ch;
|
|
if (endian == LittleEndianness) {
|
|
ch.setRow(*chars++);
|
|
ch.setCell(buf);
|
|
} else {
|
|
ch.setRow(buf);
|
|
ch.setCell(*chars++);
|
|
}
|
|
if (!headerdone) {
|
|
headerdone = true;
|
|
if (endian == DetectEndianness) {
|
|
if (ch == QChar::ByteOrderSwapped) {
|
|
endian = LittleEndianness;
|
|
} else if (ch == QChar::ByteOrderMark) {
|
|
endian = BigEndianness;
|
|
} else {
|
|
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
|
endian = BigEndianness;
|
|
} else {
|
|
endian = LittleEndianness;
|
|
ch = QChar((ch.unicode() >> 8) | ((ch.unicode() & 0xff) << 8));
|
|
}
|
|
*qch++ = ch;
|
|
}
|
|
} else if (ch != QChar::ByteOrderMark) {
|
|
*qch++ = ch;
|
|
}
|
|
} else {
|
|
*qch++ = ch;
|
|
}
|
|
half = false;
|
|
} else {
|
|
buf = *chars++;
|
|
half = true;
|
|
}
|
|
}
|
|
result.truncate(qch - result.unicode());
|
|
|
|
if (state) {
|
|
if (headerdone)
|
|
state->flags |= QTextCodec::IgnoreHeader;
|
|
state->state_data[Endian] = endian;
|
|
if (half) {
|
|
state->remainingChars = 1;
|
|
state->state_data[Data] = buf;
|
|
} else {
|
|
state->remainingChars = 0;
|
|
state->state_data[Data] = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QByteArray QUtf32::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e)
|
|
{
|
|
DataEndianness endian = e;
|
|
int length = 4*len;
|
|
if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) {
|
|
length += 4;
|
|
}
|
|
if (e == DetectEndianness) {
|
|
endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
|
|
}
|
|
|
|
QByteArray d(length, Qt::Uninitialized);
|
|
char *data = d.data();
|
|
if (!state || !(state->flags & QTextCodec::IgnoreHeader)) {
|
|
if (endian == BigEndianness) {
|
|
data[0] = 0;
|
|
data[1] = 0;
|
|
data[2] = (char)0xfe;
|
|
data[3] = (char)0xff;
|
|
} else {
|
|
data[0] = (char)0xff;
|
|
data[1] = (char)0xfe;
|
|
data[2] = 0;
|
|
data[3] = 0;
|
|
}
|
|
data += 4;
|
|
}
|
|
|
|
QStringIterator i(uc, uc + len);
|
|
if (endian == BigEndianness) {
|
|
while (i.hasNext()) {
|
|
uint cp = i.next();
|
|
|
|
*(data++) = cp >> 24;
|
|
*(data++) = (cp >> 16) & 0xff;
|
|
*(data++) = (cp >> 8) & 0xff;
|
|
*(data++) = cp & 0xff;
|
|
}
|
|
} else {
|
|
while (i.hasNext()) {
|
|
uint cp = i.next();
|
|
|
|
*(data++) = cp & 0xff;
|
|
*(data++) = (cp >> 8) & 0xff;
|
|
*(data++) = (cp >> 16) & 0xff;
|
|
*(data++) = cp >> 24;
|
|
}
|
|
}
|
|
|
|
if (state) {
|
|
state->remainingChars = 0;
|
|
state->flags |= QTextCodec::IgnoreHeader;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e)
|
|
{
|
|
DataEndianness endian = e;
|
|
uchar tuple[4];
|
|
int num = 0;
|
|
bool headerdone = false;
|
|
if (state) {
|
|
headerdone = state->flags & QTextCodec::IgnoreHeader;
|
|
if (endian == DetectEndianness) {
|
|
endian = (DataEndianness)state->state_data[Endian];
|
|
}
|
|
num = state->remainingChars;
|
|
memcpy(tuple, &state->state_data[Data], 4);
|
|
}
|
|
if (headerdone && endian == DetectEndianness)
|
|
endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness;
|
|
|
|
QString result;
|
|
result.resize((num + len) >> 2 << 1); // worst case
|
|
QChar *qch = (QChar *)result.unicode();
|
|
|
|
const char *end = chars + len;
|
|
while (chars < end) {
|
|
tuple[num++] = *chars++;
|
|
if (num == 4) {
|
|
if (!headerdone) {
|
|
if (endian == DetectEndianness) {
|
|
if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) {
|
|
endian = LittleEndianness;
|
|
num = 0;
|
|
continue;
|
|
} else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LittleEndianness) {
|
|
endian = BigEndianness;
|
|
num = 0;
|
|
continue;
|
|
} else if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
|
endian = BigEndianness;
|
|
} else {
|
|
endian = LittleEndianness;
|
|
}
|
|
} else if (((endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) {
|
|
num = 0;
|
|
continue;
|
|
}
|
|
}
|
|
uint code = (endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple);
|
|
if (QChar::requiresSurrogates(code)) {
|
|
*qch++ = QChar::highSurrogate(code);
|
|
*qch++ = QChar::lowSurrogate(code);
|
|
} else {
|
|
*qch++ = code;
|
|
}
|
|
num = 0;
|
|
}
|
|
}
|
|
result.truncate(qch - result.unicode());
|
|
|
|
if (state) {
|
|
if (headerdone)
|
|
state->flags |= QTextCodec::IgnoreHeader;
|
|
state->state_data[Endian] = endian;
|
|
state->remainingChars = num;
|
|
memcpy(&state->state_data[Data], tuple, 4);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
#ifndef QT_NO_TEXTCODEC
|
|
|
|
QUtf8Codec::~QUtf8Codec()
|
|
{
|
|
}
|
|
|
|
QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
|
|
{
|
|
return QUtf8::convertFromUnicode(uc, len, state);
|
|
}
|
|
|
|
void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const
|
|
{
|
|
*target += QUtf8::convertToUnicode(chars, len, state);
|
|
}
|
|
|
|
QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
|
|
{
|
|
return QUtf8::convertToUnicode(chars, len, state);
|
|
}
|
|
|
|
QByteArray QUtf8Codec::name() const
|
|
{
|
|
return "UTF-8";
|
|
}
|
|
|
|
int QUtf8Codec::mibEnum() const
|
|
{
|
|
return 106;
|
|
}
|
|
|
|
QUtf16Codec::~QUtf16Codec()
|
|
{
|
|
}
|
|
|
|
QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
|
|
{
|
|
return QUtf16::convertFromUnicode(uc, len, state, e);
|
|
}
|
|
|
|
QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
|
|
{
|
|
return QUtf16::convertToUnicode(chars, len, state, e);
|
|
}
|
|
|
|
int QUtf16Codec::mibEnum() const
|
|
{
|
|
return 1015;
|
|
}
|
|
|
|
QByteArray QUtf16Codec::name() const
|
|
{
|
|
return "UTF-16";
|
|
}
|
|
|
|
QList<QByteArray> QUtf16Codec::aliases() const
|
|
{
|
|
return QList<QByteArray>();
|
|
}
|
|
|
|
int QUtf16BECodec::mibEnum() const
|
|
{
|
|
return 1013;
|
|
}
|
|
|
|
QByteArray QUtf16BECodec::name() const
|
|
{
|
|
return "UTF-16BE";
|
|
}
|
|
|
|
QList<QByteArray> QUtf16BECodec::aliases() const
|
|
{
|
|
QList<QByteArray> list;
|
|
return list;
|
|
}
|
|
|
|
int QUtf16LECodec::mibEnum() const
|
|
{
|
|
return 1014;
|
|
}
|
|
|
|
QByteArray QUtf16LECodec::name() const
|
|
{
|
|
return "UTF-16LE";
|
|
}
|
|
|
|
QList<QByteArray> QUtf16LECodec::aliases() const
|
|
{
|
|
QList<QByteArray> list;
|
|
return list;
|
|
}
|
|
|
|
QUtf32Codec::~QUtf32Codec()
|
|
{
|
|
}
|
|
|
|
QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const
|
|
{
|
|
return QUtf32::convertFromUnicode(uc, len, state, e);
|
|
}
|
|
|
|
QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const
|
|
{
|
|
return QUtf32::convertToUnicode(chars, len, state, e);
|
|
}
|
|
|
|
int QUtf32Codec::mibEnum() const
|
|
{
|
|
return 1017;
|
|
}
|
|
|
|
QByteArray QUtf32Codec::name() const
|
|
{
|
|
return "UTF-32";
|
|
}
|
|
|
|
QList<QByteArray> QUtf32Codec::aliases() const
|
|
{
|
|
QList<QByteArray> list;
|
|
return list;
|
|
}
|
|
|
|
int QUtf32BECodec::mibEnum() const
|
|
{
|
|
return 1018;
|
|
}
|
|
|
|
QByteArray QUtf32BECodec::name() const
|
|
{
|
|
return "UTF-32BE";
|
|
}
|
|
|
|
QList<QByteArray> QUtf32BECodec::aliases() const
|
|
{
|
|
QList<QByteArray> list;
|
|
return list;
|
|
}
|
|
|
|
int QUtf32LECodec::mibEnum() const
|
|
{
|
|
return 1019;
|
|
}
|
|
|
|
QByteArray QUtf32LECodec::name() const
|
|
{
|
|
return "UTF-32LE";
|
|
}
|
|
|
|
QList<QByteArray> QUtf32LECodec::aliases() const
|
|
{
|
|
QList<QByteArray> list;
|
|
return list;
|
|
}
|
|
|
|
#endif //QT_NO_TEXTCODEC
|
|
|
|
QT_END_NAMESPACE
|