webengine/osswebengine/WebCore/platform/symbian/StreamingTextCodecSymbian.cpp
changeset 0 dd21522fd290
child 5 10e98eab6f85
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/symbian/StreamingTextCodecSymbian.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,259 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+*
+*/
+
+
+#include "config.h"
+#include "StreamingTextCodecSymbian.h"
+#include "CharsetData.h"
+#include "CString.h"
+#include "PlatformString.h"
+#include "TextEncoding.h"
+#include "TextEncodingRegistry.h"
+#include <EIKENV.H>
+#include <wtf/Assertions.h>
+
+using std::auto_ptr;
+using std::min;
+
+static const size_t ConversionBufferSize = 16384;
+
+namespace WebCore {
+    
+// static data
+CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* TextCodecSymbian::s_availableCharsets = 0;
+
+static auto_ptr<TextCodec> newTextCodecSymbian(const TextEncoding&, const void* additionalData)
+{
+    return auto_ptr<TextCodec>(new TextCodecSymbian(*static_cast<const TUint*>(additionalData)));
+}
+
+void TextCodecSymbian::registerEncodingNames(EncodingNameRegistrar registrar)
+{
+    TInt lastEncoding = -1;
+    const char* lastName = 0;
+
+    for (size_t i = 0; CharsetTable[i].name; ++i) {
+        if (CharsetTable[i].encoding != lastEncoding) {
+            lastEncoding = CharsetTable[i].encoding;
+            lastName = CharsetTable[i].name;
+        }
+        registrar(CharsetTable[i].name, lastName);
+    }
+}
+
+void TextCodecSymbian::registerCodecs(TextCodecRegistrar registrar)
+{
+    TInt lastEncoding = -1;
+
+    for (size_t i = 0; CharsetTable[i].name; ++i)
+        if (CharsetTable[i].encoding != lastEncoding) {
+            registrar(CharsetTable[i].name, newTextCodecSymbian, &CharsetTable[i].encoding);
+            lastEncoding = CharsetTable[i].encoding;
+        }
+}
+
+TextCodecSymbian::TextCodecSymbian(TUint encoding)
+    : m_converter(0)
+    , m_state(CCnvCharacterSetConverter::KStateDefault)
+    , m_encoding(encoding)
+    , m_firstChunkDecoded(EFalse)
+    , m_numBufferedBytes(0)
+{
+}
+
+TextCodecSymbian::~TextCodecSymbian()
+{
+    delete m_converter;
+    m_fallbackCodec.clear();
+}
+
+bool TextCodecSymbian::initializeConverter()
+{
+    if( m_firstChunkDecoded ) return true;
+
+    // Removed the call to CEikonEnv::Static()->FsSession() which should not be
+    // called in a thread where UiKon static env does not exist. This gets called
+    // by the icon database thread which does not have it. Also, the file
+    // server session is not needed anymore. It exists only for backward compatibility
+    RFs fsSession;
+
+    // FIXME: find a way to free the global availableCharsets array
+    if( !m_converter ) {
+        // first time call to charconv
+        if( ( m_converter = 
+            CCnvCharacterSetConverter::NewL() ) == NULL ) 
+            return false;
+
+        // caching the available charsets table
+        if( !s_availableCharsets )
+            s_availableCharsets = CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL( fsSession );
+    }
+   
+    // check decoder avialability
+    checkSupportedEncoding();
+
+    // prepare character conversion
+    m_converter->PrepareToConvertToOrFromL( m_encoding, *s_availableCharsets, fsSession );
+
+    return true;
+}
+
+String TextCodecSymbian::decode(const char* chs, size_t length, bool flush)
+{
+    if( !initializeConverter() )
+        return String();
+
+    // FIXME: how to handle flush flag in Symbian converter?
+    if( m_encoding == KCharacterSetIdentifierIso88591 ) {
+        if( !m_fallbackCodec ) {
+            m_fallbackCodec.set(newTextCodec(Latin1Encoding()).release());
+        }
+
+        return m_fallbackCodec->decode( chs, length, flush );
+    }
+
+    Vector<UChar> result;
+
+    // prepare the input buffer for character converter,
+    // the leftover bytes need to be decoded first.
+    TPtrC8 inBuf(0,0);
+    char* inputString = 0;
+    if( m_numBufferedBytes != 0 ) {
+        const int fullLength = m_numBufferedBytes + length;
+        inputString = (char*)malloc( fullLength );
+        if( !inputString ) return String();
+        memcpy( inputString, m_bufferedBytes, m_numBufferedBytes );
+        memcpy( inputString + m_numBufferedBytes, chs, length );
+        inBuf.Set( (const TUint8*)inputString, fullLength );
+        m_numBufferedBytes = 0;
+    }
+    else {
+        inBuf.Set( (const TUint8*)chs, length );
+    }
+
+    // output buffer
+    UChar* buffer = (UChar*)malloc( ConversionBufferSize*sizeof(UChar) );
+    if( !buffer ) return String();
+    TPtr16 outBuf( (TUint16*)buffer, 0, ConversionBufferSize );
+    
+    for(;;) {
+        int rep = 0;
+        int rIndx = 0;
+        
+        int retValue = m_converter->ConvertToUnicode( outBuf, inBuf, m_state, rep, rIndx );
+
+        if( retValue == CCnvCharacterSetConverter::EErrorIllFormedInput ) {
+            if (inBuf.Length() < strlen((char*) m_bufferedBytes))
+            {
+            memcpy( m_bufferedBytes, inBuf.Ptr(), inBuf.Length() );
+            m_numBufferedBytes = inBuf.Length();
+            }
+            break;
+        }
+        else if( retValue == 0 ) {
+            // decoded fully, exit
+            appendOmittingBOM( result, buffer, outBuf.Length() );
+            break;
+        }
+        else {
+            // prepare for next round
+            appendOmittingBOM( result, buffer, outBuf.Length() );
+            outBuf.SetLength(0);
+            inBuf.Set( inBuf.Right(retValue) );
+        }
+    }
+    
+    free( buffer );
+    free( inputString );
+
+    if(!m_firstChunkDecoded )
+        m_firstChunkDecoded = true;
+
+    String resultString = String::adopt(result);
+    return resultString;
+}
+
+CString TextCodecSymbian::encode(const UChar* data, size_t length, bool allowEntities)
+{
+    if( !initializeConverter() )
+        return CString();
+
+    // FIXME: how to handle allowEntities flag in Symbian converter?
+    // We should figure out a good way to use SetReplacementForUnconvertibleUnicodeCharactersL()
+    if( m_encoding == KCharacterSetIdentifierIso88591 ) {
+        if( !m_fallbackCodec ) {
+            m_fallbackCodec.set(newTextCodec(Latin1Encoding()).release());
+        }
+
+        return m_fallbackCodec->encode( data, length, allowEntities );
+    }
+    
+    Vector<char> result;
+    
+    // input buffer
+    TPtrC inBuf( (const TUint16*)data, length );
+
+    // output buffer
+    char* buffer = (char*)malloc( ConversionBufferSize*sizeof(char) );
+    if( !buffer ) return CString();
+    size_t size = 0;
+    TPtr8 outBuf( (TUint8*)buffer, 0, ConversionBufferSize );
+
+    for(;;) {
+        TInt retValue = m_converter->ConvertFromUnicode( outBuf, inBuf );
+        const int olen = outBuf.Length();
+        
+        if( retValue == CCnvCharacterSetConverter::EErrorIllFormedInput )
+            break;
+        
+        result.resize( size + olen );
+        memcpy( result.data() + size, buffer, olen );
+        size += olen;
+
+        if( retValue == 0 )
+            break;
+        else {
+            outBuf.SetLength(0);
+            inBuf.Set( inBuf.Right(retValue) );
+        }
+    }
+
+    free( buffer );
+
+    if( !m_firstChunkDecoded )
+        m_firstChunkDecoded = true;
+
+    return CString( result.data(), size );
+}
+
+void TextCodecSymbian::checkSupportedEncoding()
+{
+    int count = s_availableCharsets->Count();
+
+    for (int index = 0; index < count; index++) {
+        if (m_encoding == ((CCnvCharacterSetConverter::SCharacterSet)(s_availableCharsets->At(index))).Identifier())
+            return;
+    }
+
+    // otherwise fall back to iso88591
+    m_encoding = KCharacterSetIdentifierIso88591;
+}
+
+
+}
+
+// END OF FILE