Changeset 349


Ignore:
Timestamp:
Nov 26, 2009, 12:34:37 AM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib/codec: Implemented the "System" text codec which is always used as the default codec for the locale and uses the OS/2 ULS API to perform conversions from the process codepage to Unicode and back. The encoding part of the LANG variable is no longer recognized (#46).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/src/corelib/codecs/qtextcodec.cpp

    r340 r349  
    5959#endif
    6060
     61#if defined(Q_OS_OS2)
     62#  include <unidef.h>
     63#  include <uconv.h>
     64#  include "qvector.h"
     65#endif
     66
    6167#include "qutfcodec_p.h"
    6268#include "qsimplecodec_p.h"
     
    392398}
    393399
     400#elif defined(Q_OS_OS2)
     401
     402class QOs2LocalCodec: public QTextCodec
     403{
     404public:
     405    QOs2LocalCodec();
     406    ~QOs2LocalCodec();
     407
     408    QString convertToUnicode(const char *, int, ConverterState *) const;
     409    QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const;
     410
     411    QByteArray name() const;
     412    int mibEnum() const;
     413
     414private:
     415    UconvObject uoSubYes;
     416    UconvObject uoSubNo;
     417};
     418
     419QOs2LocalCodec::QOs2LocalCodec() : uoSubYes(0), uoSubNo(0)
     420{
     421    // create the conversion object for the process code page that performs
     422    // substitution of invalid characters with '?'
     423    UniCreateUconvObject((UniChar *)L"@sub=yes", &uoSubYes);
     424    // same as above but doesn't perform substitution
     425    UniCreateUconvObject((UniChar *)L"@sub=no", &uoSubNo);
     426}
     427
     428QOs2LocalCodec::~QOs2LocalCodec()
     429{
     430    UniFreeUconvObject(uoSubNo);
     431    UniFreeUconvObject(uoSubYes);
     432}
     433
     434static void qOs2LocalCodecStateFree(QTextCodec::ConverterState *state)
     435{
     436    delete reinterpret_cast<char *>(state->d);
     437}
     438
     439QString QOs2LocalCodec::convertToUnicode(const char *chars, int length,
     440                                         ConverterState *state) const
     441{
     442    QString res;
     443
     444    if (!chars)
     445        return res;
     446    if (!length)
     447        return QLatin1String("");
     448
     449    UconvObject uo = uoSubYes;
     450    if (state && (state->flags & ConvertInvalidToNull))
     451        uo = uoSubNo;
     452    Q_ASSERT(uo);
     453    if (!uo)
     454        return res;
     455
     456    int remainingChars = 0;
     457    char *remainingBuffer = 0;
     458
     459    if (state) {
     460        // stateful conversion
     461        remainingBuffer = reinterpret_cast<char *>(&state->d);
     462        if (remainingBuffer) {
     463            // restore state
     464            remainingChars = state->remainingChars;
     465        } else {
     466            // first time, add the destructor for state->d
     467            state->flags |= FreeFunction;
     468            QTextCodecUnalignedPointer::encode(state->state_data,
     469                                               qOs2LocalCodecStateFree);
     470        }
     471    }
     472
     473    const char *mbPtr = chars;
     474    size_t mbLeft = length;
     475
     476    QByteArray mbExtra;
     477    if (remainingChars) {
     478        // we have to prepend the remaining bytes from the previous conversion
     479        mbLeft += remainingChars;
     480        mbExtra.resize(mbLeft);
     481        mbPtr = mbExtra.data();
     482
     483        memcpy(mbExtra.data(), remainingBuffer, remainingChars);
     484        memcpy(mbExtra.data() + remainingChars, chars, length);
     485
     486        remainingBuffer = 0;
     487        remainingChars = 0;
     488    }
     489
     490    size_t ucLen = mbLeft;
     491    QString ucBuf(ucLen, '\0');
     492    UniChar *ucPtr = reinterpret_cast<UniChar *>(ucBuf.data());
     493    size_t ucLeft = ucLen;
     494
     495    size_t nonIdent = 0;
     496    int rc;
     497
     498    while (mbLeft) {
     499        rc = UniUconvToUcs(uo, (void**)&mbPtr, &mbLeft, &ucPtr, &ucLeft,
     500                           &nonIdent);
     501        if (rc == ULS_BUFFERFULL) {
     502            size_t ucDone = ucLen - ucLeft;
     503            size_t mbDone = length - mbLeft;
     504            // assume that mbLeft/ucLeft is an approximation of mbDone/ucDone
     505            ucLen = ucDone + (mbLeft * ucDone) / mbDone;
     506            ucBuf.resize(ucLen);
     507            ucPtr = reinterpret_cast<UniChar *>(ucBuf.data() + ucDone);
     508        } else if (rc == ULS_ILLEGALSEQUENCE && state) {
     509            // conversion stopped because the remaining inBytesLeft make up
     510            // an incomplete multi-byte sequence; save them for later
     511            remainingBuffer = new char[mbLeft];
     512            memcpy(remainingBuffer, mbPtr, mbLeft);
     513            remainingChars = mbLeft;
     514            break;
     515        } else if (rc != ULS_SUCCESS) {
     516            // just fail on an unexpected error (will return what we've got)
     517            qWarning("QOs2LocalCodec::convertToUnicode: UniUconvToUcs failed "
     518                     "with %d", rc);
     519            break;
     520        }
     521    }
     522
     523    ucBuf.resize(ucLen - ucLeft);
     524    res = ucBuf;
     525
     526    if (state) {
     527        // update the state
     528        state->invalidChars = nonIdent;
     529        state->remainingChars = remainingChars;
     530        state->d = remainingBuffer;
     531    }
     532
     533    return res;
     534}
     535
     536QByteArray QOs2LocalCodec::convertFromUnicode(const QChar *uchars, int length,
     537                                              ConverterState *state) const
     538{
     539    QByteArray res;
     540
     541    if (!uchars)
     542        return res;
     543    if (!length)
     544        return QByteArray("");
     545
     546    UconvObject uo = uoSubYes;
     547    if (state && (state->flags & ConvertInvalidToNull))
     548        uo = uoSubNo;
     549    Q_ASSERT(uo);
     550    if (!uo)
     551        return res;
     552
     553    const UniChar *ucPtr = reinterpret_cast<const UniChar *>(uchars);
     554    size_t ucLeft = length;
     555
     556    QVector<QChar> ucExtra;
     557    if (state && state->remainingChars) {
     558        // we have one surrogate char to be prepended
     559        Q_ASSERT(state->remainingChars == 1);
     560        ucLeft += 1;
     561        ucExtra.resize(ucLeft);
     562        ucPtr = reinterpret_cast<const UniChar *>(ucExtra.data());
     563
     564        ucExtra[0] = state->state_data[0];
     565        memcpy(ucExtra.data() + 1, uchars, length * sizeof(QChar));
     566
     567        state->remainingChars = 0;
     568    }
     569
     570    // be optimistic (imply that one byte is necessary per every Unicode char)
     571    size_t mbLen = length;
     572    QByteArray mbBuf(mbLen, '\0');
     573    char *mbPtr = mbBuf.data();
     574    size_t mbLeft = mbLen;
     575
     576    size_t nonIdent = 0;
     577    int rc;
     578
     579    while (ucLeft) {
     580        rc = UniUconvFromUcs(uo, const_cast<UniChar **>(&ucPtr), &ucLeft,
     581                             (void**)&mbPtr, &mbLeft, &nonIdent);
     582        if (rc == ULS_BUFFERFULL) {
     583            size_t mbDone = mbLen - mbLeft;
     584            size_t ucDone = length - ucLeft;
     585            size_t newLen = mbLen;
     586            if (ucDone) {
     587                // assume that ucLeft/mbLeft is an approximation of ucDone/mbDone
     588                newLen = mbDone + (ucLeft * mbDone) / ucDone;
     589            }
     590            if (newLen == mbLen) {
     591                // could not process a single Unicode char, double the size
     592                mbLen *= 2;
     593            } else {
     594                mbLen = newLen;
     595            }
     596            mbBuf.resize(mbLen);
     597            mbPtr = mbBuf.data() + mbDone;
     598            mbLeft = mbLen - mbDone;
     599        } else if (rc == ULS_ILLEGALSEQUENCE && state) {
     600            // buffer ends in a surrogate
     601            Q_ASSERT(ucLeft == 2);
     602            state->state_data[0] = *ucPtr;
     603            state->remainingChars = 1;
     604            break;
     605        } else if (rc != ULS_SUCCESS) {
     606            // just fail on an unexpected error (will return what we've got)
     607            qWarning("QOs2LocalCodec::convertFromUnicode: UniUconvFromUcs failed "
     608                     "with %d", rc);
     609            break;
     610        }
     611    }
     612
     613    mbBuf.resize(mbLen - mbLeft);
     614    res = mbBuf;
     615
     616    if (state) {
     617        // update the state
     618        state->invalidChars = nonIdent;
     619    }
     620
     621    return res;
     622}
     623
     624QByteArray QOs2LocalCodec::name() const
     625{
     626    return "System";
     627}
     628
     629int QOs2LocalCodec::mibEnum() const
     630{
     631    return 0;
     632}
     633
    394634#else
    395635
     
    509749#endif
    510750
    511 #if !defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)
     751#if !defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) && !defined(Q_OS_OS2)
    512752static QTextCodec *checkForCodec(const char *name) {
    513753    QTextCodec *c = QTextCodec::codecForName(name);
     
    529769{
    530770#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
     771    localeMapper = QTextCodec::codecForName("System");
     772#elif defined(Q_OS_OS2)
    531773    localeMapper = QTextCodec::codecForName("System");
    532774#else
     
    712954    (void) new QWindowsLocalCodec;
    713955#endif // Q_OS_WIN32
     956
     957#if defined(Q_OS_OS2)
     958    (void) new QOs2LocalCodec;
     959#endif // Q_OS_OS2
    714960
    715961    (void)new QUtf16Codec;
Note: See TracChangeset for help on using the changeset viewer.