webengine/osswebengine/WebCore/platform/symbian/StreamingTextCodecSymbian.cpp
changeset 0 dd21522fd290
child 5 10e98eab6f85
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "config.h"
       
    20 #include "StreamingTextCodecSymbian.h"
       
    21 #include "CharsetData.h"
       
    22 #include "CString.h"
       
    23 #include "PlatformString.h"
       
    24 #include "TextEncoding.h"
       
    25 #include "TextEncodingRegistry.h"
       
    26 #include <EIKENV.H>
       
    27 #include <wtf/Assertions.h>
       
    28 
       
    29 using std::auto_ptr;
       
    30 using std::min;
       
    31 
       
    32 static const size_t ConversionBufferSize = 16384;
       
    33 
       
    34 namespace WebCore {
       
    35     
       
    36 // static data
       
    37 CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* TextCodecSymbian::s_availableCharsets = 0;
       
    38 
       
    39 static auto_ptr<TextCodec> newTextCodecSymbian(const TextEncoding&, const void* additionalData)
       
    40 {
       
    41     return auto_ptr<TextCodec>(new TextCodecSymbian(*static_cast<const TUint*>(additionalData)));
       
    42 }
       
    43 
       
    44 void TextCodecSymbian::registerEncodingNames(EncodingNameRegistrar registrar)
       
    45 {
       
    46     TInt lastEncoding = -1;
       
    47     const char* lastName = 0;
       
    48 
       
    49     for (size_t i = 0; CharsetTable[i].name; ++i) {
       
    50         if (CharsetTable[i].encoding != lastEncoding) {
       
    51             lastEncoding = CharsetTable[i].encoding;
       
    52             lastName = CharsetTable[i].name;
       
    53         }
       
    54         registrar(CharsetTable[i].name, lastName);
       
    55     }
       
    56 }
       
    57 
       
    58 void TextCodecSymbian::registerCodecs(TextCodecRegistrar registrar)
       
    59 {
       
    60     TInt lastEncoding = -1;
       
    61 
       
    62     for (size_t i = 0; CharsetTable[i].name; ++i)
       
    63         if (CharsetTable[i].encoding != lastEncoding) {
       
    64             registrar(CharsetTable[i].name, newTextCodecSymbian, &CharsetTable[i].encoding);
       
    65             lastEncoding = CharsetTable[i].encoding;
       
    66         }
       
    67 }
       
    68 
       
    69 TextCodecSymbian::TextCodecSymbian(TUint encoding)
       
    70     : m_converter(0)
       
    71     , m_state(CCnvCharacterSetConverter::KStateDefault)
       
    72     , m_encoding(encoding)
       
    73     , m_firstChunkDecoded(EFalse)
       
    74     , m_numBufferedBytes(0)
       
    75 {
       
    76 }
       
    77 
       
    78 TextCodecSymbian::~TextCodecSymbian()
       
    79 {
       
    80     delete m_converter;
       
    81     m_fallbackCodec.clear();
       
    82 }
       
    83 
       
    84 bool TextCodecSymbian::initializeConverter()
       
    85 {
       
    86     if( m_firstChunkDecoded ) return true;
       
    87 
       
    88     // Removed the call to CEikonEnv::Static()->FsSession() which should not be
       
    89     // called in a thread where UiKon static env does not exist. This gets called
       
    90     // by the icon database thread which does not have it. Also, the file
       
    91     // server session is not needed anymore. It exists only for backward compatibility
       
    92     RFs fsSession;
       
    93 
       
    94     // FIXME: find a way to free the global availableCharsets array
       
    95     if( !m_converter ) {
       
    96         // first time call to charconv
       
    97         if( ( m_converter = 
       
    98             CCnvCharacterSetConverter::NewL() ) == NULL ) 
       
    99             return false;
       
   100 
       
   101         // caching the available charsets table
       
   102         if( !s_availableCharsets )
       
   103             s_availableCharsets = CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL( fsSession );
       
   104     }
       
   105    
       
   106     // check decoder avialability
       
   107     checkSupportedEncoding();
       
   108 
       
   109     // prepare character conversion
       
   110     m_converter->PrepareToConvertToOrFromL( m_encoding, *s_availableCharsets, fsSession );
       
   111 
       
   112     return true;
       
   113 }
       
   114 
       
   115 String TextCodecSymbian::decode(const char* chs, size_t length, bool flush)
       
   116 {
       
   117     if( !initializeConverter() )
       
   118         return String();
       
   119 
       
   120     // FIXME: how to handle flush flag in Symbian converter?
       
   121     if( m_encoding == KCharacterSetIdentifierIso88591 ) {
       
   122         if( !m_fallbackCodec ) {
       
   123             m_fallbackCodec.set(newTextCodec(Latin1Encoding()).release());
       
   124         }
       
   125 
       
   126         return m_fallbackCodec->decode( chs, length, flush );
       
   127     }
       
   128 
       
   129     Vector<UChar> result;
       
   130 
       
   131     // prepare the input buffer for character converter,
       
   132     // the leftover bytes need to be decoded first.
       
   133     TPtrC8 inBuf(0,0);
       
   134     char* inputString = 0;
       
   135     if( m_numBufferedBytes != 0 ) {
       
   136         const int fullLength = m_numBufferedBytes + length;
       
   137         inputString = (char*)malloc( fullLength );
       
   138         if( !inputString ) return String();
       
   139         memcpy( inputString, m_bufferedBytes, m_numBufferedBytes );
       
   140         memcpy( inputString + m_numBufferedBytes, chs, length );
       
   141         inBuf.Set( (const TUint8*)inputString, fullLength );
       
   142         m_numBufferedBytes = 0;
       
   143     }
       
   144     else {
       
   145         inBuf.Set( (const TUint8*)chs, length );
       
   146     }
       
   147 
       
   148     // output buffer
       
   149     UChar* buffer = (UChar*)malloc( ConversionBufferSize*sizeof(UChar) );
       
   150     if( !buffer ) return String();
       
   151     TPtr16 outBuf( (TUint16*)buffer, 0, ConversionBufferSize );
       
   152     
       
   153     for(;;) {
       
   154         int rep = 0;
       
   155         int rIndx = 0;
       
   156         
       
   157         int retValue = m_converter->ConvertToUnicode( outBuf, inBuf, m_state, rep, rIndx );
       
   158 
       
   159         if( retValue == CCnvCharacterSetConverter::EErrorIllFormedInput ) {
       
   160             if (inBuf.Length() < strlen((char*) m_bufferedBytes))
       
   161             {
       
   162             memcpy( m_bufferedBytes, inBuf.Ptr(), inBuf.Length() );
       
   163             m_numBufferedBytes = inBuf.Length();
       
   164             }
       
   165             break;
       
   166         }
       
   167         else if( retValue == 0 ) {
       
   168             // decoded fully, exit
       
   169             appendOmittingBOM( result, buffer, outBuf.Length() );
       
   170             break;
       
   171         }
       
   172         else {
       
   173             // prepare for next round
       
   174             appendOmittingBOM( result, buffer, outBuf.Length() );
       
   175             outBuf.SetLength(0);
       
   176             inBuf.Set( inBuf.Right(retValue) );
       
   177         }
       
   178     }
       
   179     
       
   180     free( buffer );
       
   181     free( inputString );
       
   182 
       
   183     if(!m_firstChunkDecoded )
       
   184         m_firstChunkDecoded = true;
       
   185 
       
   186     String resultString = String::adopt(result);
       
   187     return resultString;
       
   188 }
       
   189 
       
   190 CString TextCodecSymbian::encode(const UChar* data, size_t length, bool allowEntities)
       
   191 {
       
   192     if( !initializeConverter() )
       
   193         return CString();
       
   194 
       
   195     // FIXME: how to handle allowEntities flag in Symbian converter?
       
   196     // We should figure out a good way to use SetReplacementForUnconvertibleUnicodeCharactersL()
       
   197     if( m_encoding == KCharacterSetIdentifierIso88591 ) {
       
   198         if( !m_fallbackCodec ) {
       
   199             m_fallbackCodec.set(newTextCodec(Latin1Encoding()).release());
       
   200         }
       
   201 
       
   202         return m_fallbackCodec->encode( data, length, allowEntities );
       
   203     }
       
   204     
       
   205     Vector<char> result;
       
   206     
       
   207     // input buffer
       
   208     TPtrC inBuf( (const TUint16*)data, length );
       
   209 
       
   210     // output buffer
       
   211     char* buffer = (char*)malloc( ConversionBufferSize*sizeof(char) );
       
   212     if( !buffer ) return CString();
       
   213     size_t size = 0;
       
   214     TPtr8 outBuf( (TUint8*)buffer, 0, ConversionBufferSize );
       
   215 
       
   216     for(;;) {
       
   217         TInt retValue = m_converter->ConvertFromUnicode( outBuf, inBuf );
       
   218         const int olen = outBuf.Length();
       
   219         
       
   220         if( retValue == CCnvCharacterSetConverter::EErrorIllFormedInput )
       
   221             break;
       
   222         
       
   223         result.resize( size + olen );
       
   224         memcpy( result.data() + size, buffer, olen );
       
   225         size += olen;
       
   226 
       
   227         if( retValue == 0 )
       
   228             break;
       
   229         else {
       
   230             outBuf.SetLength(0);
       
   231             inBuf.Set( inBuf.Right(retValue) );
       
   232         }
       
   233     }
       
   234 
       
   235     free( buffer );
       
   236 
       
   237     if( !m_firstChunkDecoded )
       
   238         m_firstChunkDecoded = true;
       
   239 
       
   240     return CString( result.data(), size );
       
   241 }
       
   242 
       
   243 void TextCodecSymbian::checkSupportedEncoding()
       
   244 {
       
   245     int count = s_availableCharsets->Count();
       
   246 
       
   247     for (int index = 0; index < count; index++) {
       
   248         if (m_encoding == ((CCnvCharacterSetConverter::SCharacterSet)(s_availableCharsets->At(index))).Identifier())
       
   249             return;
       
   250     }
       
   251 
       
   252     // otherwise fall back to iso88591
       
   253     m_encoding = KCharacterSetIdentifierIso88591;
       
   254 }
       
   255 
       
   256 
       
   257 }
       
   258 
       
   259 // END OF FILE