realtimenetprots/sipfw/SigComp/SigCompEngine/src/Udvm.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SigComp/SigCompEngine/src/Udvm.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,2174 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// Name        : Udvm.cpp
+// Part of     : SigComp / UDVM
+// UDVM core
+// Version     : 1.0
+//
+
+
+
+
+// INCLUDE FILES
+#include "Udvm.h"
+#include "UdvmMemory.h"
+#include "sigcompcompartment.h"
+#include "StateMgr.h"
+#include "Crc.h"
+#include "MessageReader.h"
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+void CUdvm::ConstructL(CStateMgr* aStateMgr,
+                       TUint aMemSize,
+                       TUint aCyclesPerBit)
+    {
+    iExecuteOpcode[EOpcode_DECOMPRESSION_FAILURE] =
+                   &CUdvm::ExecuteOpcodeDecompressionFailureL;
+    iExecuteOpcode[EOpcode_AND] = &CUdvm::ExecuteOpcodeAndL;
+    iExecuteOpcode[EOpcode_OR] = &CUdvm::ExecuteOpcodeOrL;
+    iExecuteOpcode[EOpcode_NOT] = &CUdvm::ExecuteOpcodeNotL;
+    iExecuteOpcode[EOpcode_LSHIFT] = &CUdvm::ExecuteOpcodeLShiftL;
+    iExecuteOpcode[EOpcode_RSHIFT] = &CUdvm::ExecuteOpcodeRShiftL;
+    iExecuteOpcode[EOpcode_ADD] = &CUdvm::ExecuteOpcodeAddL;
+    iExecuteOpcode[EOpcode_SUBTRACT] = &CUdvm::ExecuteOpcodeSubtractL;
+    iExecuteOpcode[EOpcode_MULTIPLY] = &CUdvm::ExecuteOpcodeMultiplyL;
+    iExecuteOpcode[EOpcode_DIVIDE] = &CUdvm::ExecuteOpcodeDivideL;
+    iExecuteOpcode[EOpcode_REMAINDER] = &CUdvm::ExecuteOpcodeRemainderL;
+    iExecuteOpcode[EOpcode_SORT_ASCENDING] = &CUdvm::ExecuteOpcodeAscendingL;
+    iExecuteOpcode[EOpcode_SORT_DESCENDING] = &CUdvm::ExecuteOpcodeDescendingL;
+    iExecuteOpcode[EOpcode_SHA_1] = &CUdvm::ExecuteOpcodeSha1L;
+    iExecuteOpcode[EOpcode_LOAD] = &CUdvm::ExecuteOpcodeLoadL;
+    iExecuteOpcode[EOpcode_MULTILOAD] = &CUdvm::ExecuteOpcodeMultiloadL;
+    iExecuteOpcode[EOpcode_PUSH] = &CUdvm::ExecuteOpcodePushL;
+    iExecuteOpcode[EOpcode_POP] = &CUdvm::ExecuteOpcodePopL;
+    iExecuteOpcode[EOpcode_COPY] = &CUdvm::ExecuteOpcodeCopyL;
+    iExecuteOpcode[EOpcode_COPY_LITERAL] = &CUdvm::ExecuteOpcodeCopyLiteralL;
+    iExecuteOpcode[EOpcode_COPY_OFFSET] = &CUdvm::ExecuteOpcodeCopyOffsetL;
+    iExecuteOpcode[EOpcode_MEMSET] = &CUdvm::ExecuteOpcodeMemsetL;
+    iExecuteOpcode[EOpcode_JUMP] = &CUdvm::ExecuteOpcodeJumpL;
+    iExecuteOpcode[EOpcode_COMPARE] = &CUdvm::ExecuteOpcodeCompareL;
+    iExecuteOpcode[EOpcode_CALL] = &CUdvm::ExecuteOpcodeCallL;
+    iExecuteOpcode[EOpcode_RETURN] = &CUdvm::ExecuteOpcodeReturnL;
+    iExecuteOpcode[EOpcode_SWITCH] = &CUdvm::ExecuteOpcodeSwitchL;
+    iExecuteOpcode[EOpcode_CRC] = &CUdvm::ExecuteOpcodeCrcL;
+    iExecuteOpcode[EOpcode_INPUT_BYTES] = &CUdvm::ExecuteOpcodeInputBytesL;
+    iExecuteOpcode[EOpcode_INPUT_BITS] = &CUdvm::ExecuteOpcodeInputBitsL;
+    iExecuteOpcode[EOpcode_INPUT_HUFFMAN] = &CUdvm::ExecuteOpcodeInputHuffmanL;
+    iExecuteOpcode[EOpcode_STATE_ACCESS] = &CUdvm::ExecuteOpcodeStateAccessL;
+    iExecuteOpcode[EOpcode_STATE_CREATE] = &CUdvm::ExecuteOpcodeStateCreateL;
+    iExecuteOpcode[EOpcode_STATE_FREE] = &CUdvm::ExecuteOpcodeStateFreeL;
+    iExecuteOpcode[EOpcode_OUTPUT] = &CUdvm::ExecuteOpcodeOutputL;
+    iExecuteOpcode[EOpcode_END_MESSAGE] = &CUdvm::ExecuteOpcodeEndMessageL;
+
+    iStateMgr = aStateMgr;
+    iUdvmMemory = CUdvmMemory::NewL(aMemSize);
+
+    iCyclesPerBit = aCyclesPerBit;
+
+    iSHA1 = CSHA1::NewL();
+    }
+
+CUdvm::CUdvm() : iReturnedFeedback(NULL, 0),
+                 iRequestedFeedback(NULL, 0),
+                 iReturnedParameters(NULL, 0)
+    {
+    }
+
+CUdvm* CUdvm::NewLC(CStateMgr* aStateMgr,
+                    TUint aMemSize,
+                    TUint aCyclesPerBit)
+    {
+    CUdvm* self= new (ELeave) CUdvm();
+    CleanupStack::PushL(self);
+    self->ConstructL(aStateMgr, aMemSize, aCyclesPerBit);
+    return self;
+    }
+
+CUdvm* CUdvm::NewL(CStateMgr* aStateMgr, TUint aMemSize, TUint aCyclesPerBit)
+    {
+    CUdvm* self= NewLC(aStateMgr, aMemSize, aCyclesPerBit);
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Destructor
+CUdvm::~CUdvm()
+    {
+
+    DenyStateOperations();
+
+    delete iUdvmMemory;
+    delete iSHA1;
+    }
+
+
+// ---------------------------------------------------------------------------
+
+/*
+     0   1   2   3   4   5   6   7       0   1   2   3   4   5   6   7
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+   | 1   1   1   1   1 | T |  len  |   | 1   1   1   1   1 | T |   0   |
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+   |                               |   |                               |
+   :    returned feedback item     :   :    returned feedback item     :
+   |                               |   |                               |
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+   |                               |   |           code_len            |
+   :   partial state identifier    :   +---+---+---+---+---+---+---+---+
+   |                               |   |   code_len    |  destination  |
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+   |                               |   |                               |
+   :   remaining SigComp message   :   :    uploaded UDVM bytecode     :
+   |                               |   |                               |
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+                                       |                               |
+                                       :   remaining SigComp message   :
+                                       |                               |
+                                       +---+---+---+---+---+---+---+---+
+
+     0   1   2   3   4   5   6   7       0   1   2   3   4   5   6   7
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+   | 0 |  returned_feedback_field  |   | 1 | returned_feedback_length  |
+   +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
+                                       |                               |
+                                       :    returned_feedback_field    :
+                                       |                               |
+                                       +---+---+---+---+---+---+---+---+
+
+   Encoding:   Length of partial state identifier
+
+   01          6 bytes
+   10          9 bytes
+   11          12 bytes
+
+   Encoding:   Destination address:
+
+   0000        reserved
+   0001        2  *  64  =  128
+   0010        3  *  64  =  196
+   0011        4  *  64  =  256
+     :                :
+   1111        16 *  64  =  1024
+
+   Note that the encoding 0000 is reserved for future SigComp versions,
+   and causes a decompression failure in Version 0x01.
+*/
+
+void CUdvm::SetReturnedFeedbackL(TBool aT, CMessageReader* aMsgReader)
+    {
+
+    if (aT)
+        {
+        // returned feedback item
+
+        TUint rff;
+        if (aMsgReader->ReadByte(rff) != KErrNone)
+            {
+            User::Leave(CSigComp::EIncompleteMessage);
+            }
+
+        if (rff & KReturnedFeedbackFieldMask)
+            {
+            // long form
+
+            // use decompression memory after udvm memory to store returned
+            // feedback
+            TUint8* udvmMem = iUdvmMemory->MemoryPtr();
+            TUint udvmFreeMemSize = iUdvmMemory->FreeMemorySize();
+            iReturnedFeedback.Set(&udvmMem[udvmFreeMemSize],
+                                  0, rff & KReturnedFeedbackLengthMask);
+            if (aMsgReader->ReadBlock(iReturnedFeedback) != KErrNone)
+                {
+                User::Leave(CSigComp::EIncompleteMessage);
+                }
+            }
+        else
+            {
+            // short form
+
+            // use decompression memory after udvm memory to store returned
+            // feedback
+            TUint8* udvmMem = iUdvmMemory->MemoryPtr();
+            TUint udvmFreeMemSize = iUdvmMemory->FreeMemorySize();
+            iReturnedFeedback.Set(&udvmMem[udvmFreeMemSize], 0, 1);
+            iReturnedFeedback.Append(rff);
+            }
+        }
+    else
+        {
+        iReturnedFeedback.Set(NULL, 0, 0);
+        }
+    }
+
+void CUdvm::UploadStateInMessageL(TUint aLen, CMessageReader* aMsgReader)
+    {
+
+    // RFC3320:
+    // The len field encodes the number of transmitted bytes as follows:
+    //
+    //   Encoding:   Length of partial state identifier
+    //   01          6 bytes
+    //   10          9 bytes
+    //   11          12 bytes
+    TUint id_len = (aLen + 1) * 3;
+
+    TBuf8<12> psi;
+    if (aMsgReader->ReadBlock(psi, id_len) != KErrNone)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+        }
+
+    // upload state item
+    UploadStateL(id_len, psi.Ptr());
+    }
+
+void CUdvm::UploadBytecodeInMessageL(CMessageReader* aMsgReader)
+    {
+
+    TUint tmp;
+
+    // get first byte of 16-bit big-endian value
+    if (aMsgReader->ReadByte(tmp) != KErrNone)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+        }
+
+    // code length is most significant 12 bits
+    TUint code_len = tmp << 4;
+
+    // get second byte of 16-bit big-endian value
+    if (aMsgReader->ReadByte(tmp) != KErrNone)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+        }
+
+    code_len |= tmp >> 4;
+
+    // destination is less significant 4 bits
+    TUint destination = tmp & 0x000f;
+
+    // The destination field is encoded as follows:
+    //
+    //                     Encoding:   Destination address:
+    //                     0000        reserved
+    //                     0001        2  *  64  =  128
+    //                     0010        3  *  64  =  196
+    //                     0011        4  *  64  =  256
+    //                       :                :
+    //                     1111        16 *  64  =  1024
+    //
+    //   Note that the encoding 0000 is reserved for future SigComp versions,
+    //   and causes a decompression failure in Version 0x01.
+
+    if (destination == 0)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    // destination decoding - see above
+    destination = (destination + 1) * 64;
+
+    // upload code_len bytes of bytecode at destination
+    UploadCodeL(destination, code_len, aMsgReader);
+    }
+
+// ----------------------------------------------------------------------------
+// CUdvm::DecompressL
+// dispatch message and run bytecode
+// ----------------------------------------------------------------------------
+//
+
+CBufBase* CUdvm::DecompressL(const TDesC8& aMessage, TUint& aBytesConsumed,
+                             TBool aStreamBasedProtocol)
+    {
+
+    CMessageReader* msgReader = new (ELeave)CMessageReader(aMessage,
+                                                         aStreamBasedProtocol);
+    CleanupStack::PushL(msgReader);
+
+    if (msgReader->SkipDelimiters() != KErrNone)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+        }
+
+    TUint tmp;
+    if (msgReader->ReadByte(tmp) != KErrNone)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+        }
+
+    //is sigcomp message?
+    if ((tmp & KSigCompHeaderMask) != KSigCompHeaderMask)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+        }
+
+    // get T bit from header
+    TBool t = tmp & KSigCompHeaderTMask;
+    // partial state identifier length
+    TUint len = tmp & KSigCompHeaderLenMask;
+
+    // initialize udvm memory
+    if (aStreamBasedProtocol)
+        {
+        iUdvmMemory->InitMemoryL(iUdvmMemory->MemorySize()/2, iCyclesPerBit);
+        }
+    else
+        {
+        iUdvmMemory->InitMemoryL(aMessage.Length(), iCyclesPerBit);
+        }
+    // T bit set, returned feedback present
+    SetReturnedFeedbackL(t, msgReader);
+
+    if (len)
+        {
+        // partial state identifier
+        UploadStateInMessageL(len, msgReader);
+        }
+    else
+        {
+        // bytecode
+        UploadBytecodeInMessageL(msgReader);
+        }
+
+    // available cycles, as defined in RFC3220 chapter 8.6
+    iAvailableCycles = (8 * aMessage.Length() + 1000) * iCyclesPerBit;
+
+    // prepare output buffer
+    CBufFlat* outputBuffer = CBufFlat::NewL(128);
+    CleanupStack::PushL(outputBuffer);
+    outputBuffer->SetReserveL(128);
+    iOutputBuffer = outputBuffer; // used for parameter passing to Opcodes
+
+    // execute code
+    ExecuteCodeL(msgReader);
+
+    iOutputBuffer = NULL;
+    CleanupStack::Pop(outputBuffer);
+
+    // skip end delimiter
+    if (aStreamBasedProtocol)
+        {
+        msgReader->SkipDelimiters(1);
+        }
+
+    // get message bytes consumed
+    aBytesConsumed = msgReader->Pos();
+
+    outputBuffer->Compress();
+
+    CleanupStack::PopAndDestroy(msgReader);
+
+    return outputBuffer;
+    }
+
+// ----------------------------------------------------------------------------
+// CUdvm::ByteCopyingFragmentL
+//
+// ----------------------------------------------------------------------------
+//
+
+inline TUint CUdvm::ByteCopyingFragmentL(TUint& aAddress,
+                                         TUint& aLength,
+                                         TUint aBcl,
+                                         TUint aBcr) const
+    {
+
+    TUint len;
+
+    if (((aAddress + 1) <= aBcr) && ((aAddress + aLength) > aBcr))
+        {
+        len = aBcr - aAddress;
+        }
+    else
+        {
+        len = aLength;
+        }
+
+    if ((aAddress + len) > iUdvmMemory->FreeMemorySize())
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    aLength -= len;
+    aAddress = aBcl;
+
+    return len;
+    }
+
+// ----------------------------------------------------------------------------
+// CUdvm::UploadCodeL
+// upload bytecode, initialize UDVM memory and registers
+// ----------------------------------------------------------------------------
+//
+
+void CUdvm::UploadCodeL(TUint aDest, TUint aLen, CMessageReader* aMsgReader)
+    {
+
+    // init memory
+    iUdvmMemory->WriteMem16L(EMem_partial_state_ID_length, 0x0000);
+    iUdvmMemory->WriteMem16L(EMem_state_length, 0x0000);
+
+    // upload code
+    iUdvmMemory->CheckMemAccessL(aDest & KMaxUdvmMemoryMask, aLen);
+    TPtr8 codePtr(iUdvmMemory->MemoryPtr() +
+                  (aDest & KMaxUdvmMemoryMask), aLen);
+    if (aMsgReader->ReadBlock(codePtr) != KErrNone)
+        {
+        User::Leave(CSigComp::EIncompleteMessage);
+                }
+
+    iCodeStart = aDest;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::UploadStateL
+// upload state item, initialize UDVM memory and registers
+// ----------------------------------------------------------------------------
+//
+
+void CUdvm::UploadStateL(TUint aStateLen, const TUint8* aState)
+    {
+
+    TStateItem* si = iStateMgr->FindStateItem(TPtrC8(aState, aStateLen));
+
+    if (si == NULL)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TestStateAccessLenL(si, aStateLen);
+
+    // init memory
+    iUdvmMemory->WriteMem16L(EMem_partial_state_ID_length, aStateLen);
+    iUdvmMemory->WriteMem16L(EMem_state_length, si->iStateLength);
+
+    // upload state value
+    iUdvmMemory->CopyToMemL(si->iStateAddress & KMaxUdvmMemoryMask,
+                            si->iStateValue,
+                            si->iStateLength);
+
+    iCodeStart = si->iStateInstruction;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::TestStateAccessLenL
+// test state access lenght
+// ----------------------------------------------------------------------------
+//
+
+void CUdvm::TestStateAccessLenL(const TStateItem* aStateItem,
+                                TUint aAccessLen) const
+    {
+
+    if (aAccessLen < aStateItem->iMinimumAccessLength)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::InputMessageBitsL
+// input message bits
+// ----------------------------------------------------------------------------
+//
+
+TUint CUdvm::InputMessageBitsL(TUint aSize, TUint aP, TUint aF)
+    {
+    // aP and aF are flags from input_bit_order UDVM register
+
+    // iLastUsedInputBit is number of used bits from readed byte,
+    // zero if need to read next byte
+
+    //output value
+    TUint val = 0;
+
+    //it may be needed later, depending on aF flag.
+    TUint l = aSize;
+
+    //to store the return value of ReadByte function
+    TInt ret = 0;
+
+    // get aSize bits, aF aP flags indicates from which side bits are taken
+    // (MSB or LSB order)
+    // as described in RFC 3220 chapter 8.2.
+    while (aSize)
+        {
+        if (iLastUsedInputBit == 0)
+            {
+            ret = iInputMessageReader->ReadByte(iLastInputByte);
+
+            if(ret != KErrNone)
+            	User::Leave( ret );
+            }
+
+        if (aP)
+            {
+            if (aF)
+                {
+                // put LSB of input byte as MSB of output 16-bit word
+                val >>= 1;
+                val |= ((iLastInputByte & 1) << 15);
+                }
+            else
+                {
+                // put LSB of input byte as LSB of output 16-bit word
+                val <<= 1;
+                val |= (iLastInputByte & 1);
+                }
+
+            iLastInputByte >>= 1;
+            }
+        else
+            {
+            if (aF)
+                {
+                // put MSB of input byte as MSB of output 16-bit word
+                val >>= 1;
+                val |= ((iLastInputByte & 0x80) << 8);
+                }
+            else
+                {
+                // put MSB of input byte as LSB of output 16-bit word
+                val <<= 1;
+                val |= ((iLastInputByte & 0x80) >> 7);
+                }
+
+            iLastInputByte <<= 1;
+            }
+
+        //next bit
+        iLastUsedInputBit++;
+
+        if (iLastUsedInputBit > 7)
+            {
+            iLastUsedInputBit = 0;
+            }
+
+        aSize--;
+        }
+
+    //if MSB we have to move it to the right.
+    if (aF)
+        {
+        val >>= (16 - l);
+        }
+
+    return val;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::DecodeLiteralOperandL
+// decode literal bytecode operand
+// ----------------------------------------------------------------------------
+//
+
+TUint CUdvm::DecodeLiteralOperandL(TUint& aAddress) const
+    {
+
+    TUint value = 0;
+    TUint8 tmp = iUdvmMemory->ReadMem8L(aAddress++);
+
+        // Bytecode:                       Operand value:      Range:
+
+    if ((tmp & 0x80) == 0x00)
+        {
+        // 0nnnnnnn                        N                   0 - 127
+        value = tmp & 0x7f;
+        }
+    else if ((tmp & 0xc0) == 0x80)
+        {
+        // 10nnnnnn nnnnnnnn               N                   0 - 16383
+        value = ((tmp & 0x3f) << 8) + iUdvmMemory->ReadMem8L(aAddress++);
+        }
+    else if ((tmp & 0xff) == 0xc0)
+        {
+        // 11000000 nnnnnnnn nnnnnnnn      N                   0 - 65535
+        value = (iUdvmMemory->ReadMem8L(aAddress) << 8)+
+                 iUdvmMemory->ReadMem8L(aAddress + 1);
+        aAddress += 2;
+        }
+    else
+        {
+        // argument error
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    return value;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::DecodeReferenceOperandL
+// decode reference bytecode operand
+// ----------------------------------------------------------------------------
+//
+
+TUint CUdvm::DecodeReferenceOperandL(TUint& aAddress) const
+    {
+
+    TUint value = 0;
+    TUint8 tmp = iUdvmMemory->ReadMem8L(aAddress++);
+
+        // Bytecode:                       Operand value:      Range:
+
+    if ((tmp & 0x80) == 0x00)
+        {
+        // 0nnnnnnn                        memory[2 * N]       0 - 65535
+        value = (tmp & 0x7f) * 2;
+        }
+    else if ((tmp & 0xc0) == 0x80)
+        {
+        // 10nnnnnn nnnnnnnn               memory[2 * N]       0 - 65535
+        value = (((tmp & 0x3f) << 8) + iUdvmMemory->ReadMem8L(aAddress++)) * 2;
+        }
+    else if ((tmp & 0xff) == 0xc0)
+        {
+        // 11000000 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535
+        value = (iUdvmMemory->ReadMem8L(aAddress) << 8)+
+                 iUdvmMemory->ReadMem8L(aAddress + 1);
+        aAddress += 2;
+        }
+    else
+        {
+        // argument error
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    return value;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::DecodeMultitypeOperandL
+// decode multitype bytecode operand
+// ----------------------------------------------------------------------------
+//
+
+TUint CUdvm::DecodeMultitypeOperandL(TUint& aAddress) const
+    {
+
+    TUint value = 0;
+    TUint8 tmp = iUdvmMemory->ReadMem8L(aAddress++);
+
+        // Bytecode:                       Operand value:      Range:
+
+    if ((tmp & 0xc0) == 0x00)
+        {
+        // 00nnnnnn                        N                   0 - 63
+        value = tmp & 0x3f;
+        }
+    else if ((tmp & 0xc0) == 0x40)
+        {
+        // 01nnnnnn                        memory[2 * N]       0 - 65535
+        value = iUdvmMemory->ReadMem16L((tmp & 0x3f) * 2);
+        }
+    else if ((tmp & 0xfe) == 0x86)
+        {
+        // 1000011n                        2 ^ (N + 6)        64 , 128
+        value = 1 << ((tmp & 0x01) + 6);
+        }
+    else if ((tmp & 0xf8) == 0x88)
+        {
+        // 10001nnn                        2 ^ (N + 8)    256 , ... , 32768
+        value = 1 << ((tmp & 0x07) + 8);
+        }
+    else if ((tmp & 0xe0) == 0xe0)
+        {
+        // 111nnnnn                        N + 65504       65504 - 65535
+        value = (tmp & 0x1f) + 65504;
+        }
+    else if ((tmp & 0xf0) == 0x90)
+        {
+        // 1001nnnn nnnnnnnn               N + 61440       61440 - 65535
+        value = ((tmp & 0x0f) << 8) + iUdvmMemory->ReadMem8L(aAddress++) +
+                61440;
+        }
+    else if ((tmp & 0xe0) == 0xa0)
+        {
+        // 101nnnnn nnnnnnnn               N                   0 - 8191
+        value = ((tmp & 0x1f) << 8) + iUdvmMemory->ReadMem8L(aAddress++);
+        }
+    else if ((tmp & 0xe0) == 0xc0)
+        {
+        // 110nnnnn nnnnnnnn               memory[N]           0 - 65535
+        value = iUdvmMemory->ReadMem16L(((tmp & 0x1f) << 8)+
+                                        iUdvmMemory->ReadMem8L(aAddress++));
+        }
+    else if ((tmp & 0xff) == 0x80)
+        {
+        // 10000000 nnnnnnnn nnnnnnnn      N                   0 - 65535
+        value = (iUdvmMemory->ReadMem8L(aAddress) << 8)+
+                 iUdvmMemory->ReadMem8L(aAddress + 1);
+        aAddress += 2;
+        }
+    else if ((tmp & 0xff) == 0x81)
+        {
+        // 10000001 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535
+        value = iUdvmMemory->ReadMem16L((iUdvmMemory->ReadMem8L(aAddress) << 8)
+                + iUdvmMemory->ReadMem8L(aAddress + 1));
+        aAddress += 2;
+        }
+    else
+        {
+        // argument error
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    return value;
+    }
+
+// ----------------------------------------------------------------------------
+// CUdvm::DecodeAddressOperandL
+// decode address bytecode operand
+// ----------------------------------------------------------------------------
+//
+
+TUint CUdvm::DecodeAddressOperandL(TUint aPc, TUint& aAddress) const
+    {
+    return (DecodeMultitypeOperandL(aAddress) + aPc) & KMaxUdvmMemoryMask;
+    }
+
+
+// ----------------------------------------------------------------------------
+
+TBool CUdvm::ExecuteOpcodeDecompressionFailureL(TUint& /*aPc2*/)
+    {
+    iCycles += 1;
+    User::Leave(CSigComp::EDecompressionFailure);
+    return EFalse; //not covered, never called because of above Leave().
+    }
+
+TBool CUdvm::ExecuteOpcodeAndL(TUint& aPc2)
+    {
+    // AND ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, iUdvmMemory->ReadMem16L(op1) & op2);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeOrL(TUint& aPc2)
+    {
+    // OR ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, iUdvmMemory->ReadMem16L(op1) | op2);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeNotL(TUint& aPc2)
+    {
+    // NOT ($operand_1)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, iUdvmMemory->ReadMem16L(op1) ^
+                                              KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeLShiftL(TUint& aPc2)
+    {
+    // LSHIFT ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) << op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeRShiftL(TUint& aPc2)
+    {
+    // RSHIFT ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) >> op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeAddL(TUint& aPc2)
+    {
+    // ADD ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) + op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeSubtractL(TUint& aPc2)
+    {
+    // SUBTRACT ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) - op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeMultiplyL(TUint& aPc2)
+    {
+    // MULTIPLY ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) * op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeDivideL(TUint& aPc2)
+    {
+    // DIVIDE ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    if (op2 == 0)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) / op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeRemainderL(TUint& aPc2)
+    {
+    // REMAINDER ($operand_1, %operand_2)
+
+    TUint op1 = DecodeReferenceOperandL(aPc2);
+    TUint op2 = DecodeMultitypeOperandL(aPc2);
+
+    if (op2 == 0)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    iUdvmMemory->WriteMem16L(op1, (iUdvmMemory->ReadMem16L(op1) % op2) &
+                                                           KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeAscendingL(TUint& aPc2)
+    {
+    // SORT-ASCENDING (%start, %n, %k)
+
+    TUint start = DecodeMultitypeOperandL(aPc2);
+    TUint n = DecodeMultitypeOperandL(aPc2);
+    TUint k = DecodeMultitypeOperandL(aPc2);
+
+    TBool sort;
+    TUint16 a;
+    TUint16 b;
+
+    do
+        {
+        sort = EFalse;
+
+        for (TUint i = 0; i < (k - 1); i++)
+            {
+            a = iUdvmMemory->ReadMem16L(start + 2 * i);
+            b = iUdvmMemory->ReadMem16L(start + 2 * (i + 1));
+
+            if (a > b)
+                {
+                iUdvmMemory->WriteMem16L(start + i * 2, b);
+                iUdvmMemory->WriteMem16L(start + (i + 1) * 2, a);
+                for (TUint j = 1; j < n; j++)
+                    {
+                    a = iUdvmMemory->ReadMem16L(start + j * k * 2 + i * 2);
+                    iUdvmMemory->WriteMem16L(start + j * k * 2 + i * 2,
+                    iUdvmMemory->ReadMem16L(start + j * k * 2 + (i + 1) * 2));
+                    iUdvmMemory->WriteMem16L(start + j * k * 2 + (i + 1) * 2,
+                                                                            a);
+                    }
+                sort = ETrue;
+                }
+            }
+        }
+    while (sort);
+
+    //cost = 1 + k * (ceiling(log2(k)) + n)
+    TInt i;
+    for (i = 15; i >= 0 && !(k & (1 << i));)
+        {
+        i--;
+        }
+
+    if (k & (~(1 << i)))
+        {
+        i++;
+        }
+
+    iCycles += (1 + (k * (i + n)));
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeDescendingL(TUint& aPc2)
+    {
+    // SORT-DESCENDING (%start, %n, %k)
+
+    TUint start = DecodeMultitypeOperandL(aPc2);
+    TUint n = DecodeMultitypeOperandL(aPc2);
+    TUint k = DecodeMultitypeOperandL(aPc2);
+
+    TBool sort;
+    TUint16 a;
+    TUint16 b;
+
+    do
+        {
+        sort = EFalse;
+
+        for (TUint i = 0; i < (k - 1); i++)
+            {
+            a = iUdvmMemory->ReadMem16L(start + i * 2);
+            b = iUdvmMemory->ReadMem16L(start + (i + 1) * 2);
+
+            if (a < b)
+                {
+                iUdvmMemory->WriteMem16L(start + i * 2, b);
+                iUdvmMemory->WriteMem16L(start + (i + 1) * 2, a);
+                for (TUint j = 1; j < n; j++)
+                    {
+                    a = iUdvmMemory->ReadMem16L(start + j * k * 2 + i * 2);
+                    iUdvmMemory->WriteMem16L(start + j * k * 2 + i * 2,
+                    iUdvmMemory->ReadMem16L(start + j * k * 2 + (i + 1) * 2));
+                    iUdvmMemory->WriteMem16L(start + j * k * 2 + (i + 1) * 2,
+                                                                            a);
+                    }
+                sort = ETrue;
+                }
+            }
+        }
+    while (sort);
+
+    // cost = 1 + k * (ceiling(log2(k)) + n)
+    TInt i;
+    for (i = 15; i >= 0 && !(k & (1 << i));)
+        {
+        i--;
+        }
+
+    if (k & (~(1 << i)))
+        {
+        i++;
+        }
+    iCycles += 1 + k * (i + n);
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeSha1L(TUint& aPc2)
+    {
+    // SHA-1 (%position, %length, %destination)
+    // NOTE: byte copying
+
+    TUint position = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint destination = DecodeMultitypeOperandL(aPc2);
+
+    iCycles += 1 + length;
+
+    TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+    TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+    iSHA1->Reset();
+
+    while (length)
+        {
+        TUint nextpos = position;
+        TUint len = ByteCopyingFragmentL(nextpos,
+                                         length,
+                                         bcl,
+                                         bcr);
+
+        if (len)
+            {
+            TPtrC8 data = TPtrC8(&iUdvmMemory->MemoryPtr()[position], len);
+            iSHA1->Hash(data);
+            }
+
+        position = nextpos;
+        }
+
+    TPtrC8 hash = iSHA1->Hash(KNullDesC8);
+    const TUint8* SHA1result = hash.Ptr();
+
+    TUint respos = 0;
+    length = 20;
+
+    while (length)
+        {
+        TUint newdest = destination;
+        TUint len = ByteCopyingFragmentL(newdest,
+                                         length,
+                                         bcl,
+                                         bcr);
+
+        for (TUint i = 0; i < len; i++)
+            {
+            iUdvmMemory->MemoryPtr()[destination + i] = SHA1result[respos + i];
+            }
+
+        destination = newdest;
+        respos += len;
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeLoadL(TUint& aPc2)
+    {
+    // LOAD (%address, %value)
+
+    TUint address = DecodeMultitypeOperandL(aPc2);
+    TUint value = DecodeMultitypeOperandL(aPc2);
+
+    iUdvmMemory->WriteMem16L(address, value);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeMultiloadL(TUint& aPc2)
+    {
+    // MULTILOAD (%address, #n, %value_0, ..., %value_n-1)
+
+    TUint pc = aPc2 - 1;
+
+    TUint address = DecodeMultitypeOperandL(aPc2);
+    TUint n = DecodeLiteralOperandL(aPc2);
+
+    for (TUint i = 0; i < n; i++)
+        {
+        TUint value = DecodeMultitypeOperandL(aPc2);
+
+        // check overlaping instruction location
+        if (!((address >= aPc2) || ((address + n * 2) <= pc)))
+            {
+            User::Leave(CSigComp::EDecompressionFailure);
+            }
+
+        iUdvmMemory->WriteMem16L(address + i * 2, value);
+        }
+    iCycles += 1 + n;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodePushL(TUint& aPc2)
+    {
+    // PUSH (%value)
+
+    TUint value = DecodeMultitypeOperandL(aPc2);
+
+    TUint sl = iUdvmMemory->ReadMem16L(EReg_stack_location);
+    TUint sf = iUdvmMemory->ReadMem16L(sl);
+
+    iUdvmMemory->WriteMem16L((sl + 2 + sf * 2) & KMaxUdvmMemoryMask, value);
+    iUdvmMemory->WriteMem16L(sl, (sf + 1) & KMax16BitValueMask);
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodePopL(TUint& aPc2)
+    {
+    // POP (%address)
+
+    TUint address = DecodeMultitypeOperandL(aPc2);
+
+    TUint sl = iUdvmMemory->ReadMem16L(EReg_stack_location);
+    TUint sf = (iUdvmMemory->ReadMem16L(sl) - 1) & KMaxUdvmMemoryMask;
+
+    iUdvmMemory->WriteMem16L(sl, sf);
+    iUdvmMemory->WriteMem16L(address,
+                        iUdvmMemory->ReadMem16L((sl + 2 + sf * 2) &
+                                                     KMaxUdvmMemoryMask));
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeCopyL(TUint& aPc2)
+    {
+    // COPY (%position, %length, %destination)
+    // NOTE: byte copying
+
+    TUint position = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint destination = DecodeMultitypeOperandL(aPc2);
+
+    iCycles += 1 + length;
+
+    TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+    TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+    while (length)
+        {
+        iUdvmMemory->WriteMem8L(destination, iUdvmMemory->ReadMem8L(position));
+
+        destination++;
+        destination &= KMaxUdvmMemoryMask;
+        position++;
+        position &= KMaxUdvmMemoryMask;
+
+        length--;
+
+        if (destination == bcr)
+            {
+            destination = bcl;
+            }
+
+        if (position == bcr)
+            {
+            position = bcl;
+            }
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeCopyLiteralL(TUint& aPc2)
+    {
+    // COPY-LITERAL (%position, %length, $destination)
+    // NOTE: byte copying
+
+    TUint position = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint destination = DecodeReferenceOperandL(aPc2);
+
+    iCycles += 1 + length;
+
+    if (length)
+        {
+        TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+        TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+        TUint dest = iUdvmMemory->ReadMem16L(destination);
+
+        while (length)
+            {
+            iUdvmMemory->WriteMem8L(dest, iUdvmMemory->ReadMem8L(position));
+
+            dest++;
+            dest &= KMaxUdvmMemoryMask;
+            position++;
+            position &= KMaxUdvmMemoryMask;
+
+            length--;
+
+            if (dest == bcr)
+                {
+                dest = bcl;
+                }
+
+            if (position == bcr)
+                {
+                position = bcl;
+                }
+            }
+        iUdvmMemory->WriteMem16L(destination, dest);
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeCopyOffsetL(TUint& aPc2)
+    {
+    // COPY-OFFSET (%offset, %length, $destination)
+    // NOTE: byte copying
+
+    TUint offset = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint destination = DecodeReferenceOperandL(aPc2);
+
+    iCycles += 1 + length;    // not 1+length+offset !!!
+
+    if (length)
+        {
+        TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+        TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+        TUint dest = iUdvmMemory->ReadMem16L(destination);
+
+        TUint position = dest;
+        while (offset)
+            {
+            if (position == bcl)
+                {
+                position = (bcr - 1) & KMaxUdvmMemoryMask;
+                }
+            else
+                {
+                position--;
+                }
+            offset--;
+            }
+
+        while (length)
+            {
+            iUdvmMemory->WriteMem8L(dest, iUdvmMemory->ReadMem8L(position));
+
+            dest++;
+            dest &= KMaxUdvmMemoryMask;
+            position++;
+            position &= KMaxUdvmMemoryMask;
+
+            length--;
+
+            if (dest == bcr)
+                {
+                dest = bcl;
+                }
+
+            if (position == bcr)
+                {
+                position = bcl;
+                }
+            }
+
+        iUdvmMemory->WriteMem16L(destination, dest);
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeMemsetL(TUint& aPc2)
+    {
+    // MEMSET (%address, %length, %start_value, %offset)
+    // NOTE: byte copying
+
+    TUint address = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint value = DecodeMultitypeOperandL(aPc2);
+    TUint offset = DecodeMultitypeOperandL(aPc2);
+
+    iCycles += 1 + length;
+
+    if (length)
+        {
+        TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+        TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+        while (length)
+            {
+            iUdvmMemory->WriteMem8L(address, value);
+            value = (value + offset) & KMax8BitValueMask;
+
+            address++;
+            address &= KMaxUdvmMemoryMask;
+            length--;
+
+            if (address == bcr)
+                {
+                address = bcl;
+                }
+            }
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeCompareL(TUint& aPc2)
+    {
+    /*
+    COMPARE (%value_1, %value_2, @address_1,
+             @address_2, @address_3)
+    */
+
+    TUint pc = aPc2 - 1;
+
+    TUint value1 = DecodeMultitypeOperandL(aPc2);
+    TUint value2 = DecodeMultitypeOperandL(aPc2);
+    TUint address1 = DecodeAddressOperandL(pc, aPc2);
+    TUint address2 = DecodeAddressOperandL(pc, aPc2);
+    TUint address3 = DecodeAddressOperandL(pc, aPc2);
+
+    if (value1 < value2)
+        {
+        aPc2 = address1;
+        }
+    else if (value1 == value2)
+        {
+        aPc2 = address2;
+        }
+    else // if (value1 > value2)
+        {
+        aPc2 = address3;
+        }
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeCallL(TUint& aPc2)
+    {
+    // CALL (@address)
+
+    TUint pc = aPc2 - 1;
+
+    TUint address = DecodeAddressOperandL(pc, aPc2);
+
+    TUint sl = iUdvmMemory->ReadMem16L(EReg_stack_location);
+    TUint sf = iUdvmMemory->ReadMem16L(sl);
+
+    iUdvmMemory->WriteMem16L((sl + 2 + sf * 2) & KMaxUdvmMemoryMask, aPc2);
+    iUdvmMemory->WriteMem16L(sl, (sf + 1) & KMax16BitValueMask);
+
+    aPc2 = address;
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeReturnL(TUint& aPc2)
+    {
+    // RETURN
+
+    TUint sl = iUdvmMemory->ReadMem16L(EReg_stack_location);
+    TUint sf = (iUdvmMemory->ReadMem16L(sl) - 1) & KMaxUdvmMemoryMask;
+
+    iUdvmMemory->WriteMem16L(sl, sf);
+    aPc2 = iUdvmMemory->ReadMem16L((sl + 2 + sf * 2) & KMaxUdvmMemoryMask);
+
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeSwitchL(TUint& aPc2)
+    {
+    // SWITCH (#n, %j, @address_0, @address_1, ... , @address_n-1)
+
+    TUint pc = aPc2 - 1;
+
+    TUint n = DecodeLiteralOperandL(aPc2);
+    TUint j = DecodeMultitypeOperandL(aPc2);
+
+    if (j >= n)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TUint address;
+    do
+        {
+        address = DecodeAddressOperandL(pc, aPc2);
+        }
+    while (j--);
+
+    aPc2 = address;
+
+    iCycles += 1 + n;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeCrcL(TUint& aPc2)
+    {
+    // CRC (%value, %position, %length, @address)
+    // NOTE: byte copying
+
+    TUint pc = aPc2 - 1;
+
+    TUint value = DecodeMultitypeOperandL(aPc2);
+    TUint position = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint address = DecodeAddressOperandL(pc, aPc2);
+
+    iCycles += 1 + length;
+
+    TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+    TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+    TUint16 crc = Crc::KFcsInit;
+
+    while (length)
+        {
+        TUint nextpos = position;
+        TUint len = ByteCopyingFragmentL(nextpos,
+                                         length,
+                                         bcl,
+                                         bcr);
+
+        if (len)
+            {
+            crc = Crc::Calc(&iUdvmMemory->MemoryPtr()[position], len, crc);
+            }
+
+        position = nextpos;
+        }
+
+    if (crc != value)
+        {
+        aPc2 = address;
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeInputBytesL(TUint& aPc2)
+    {
+    // INPUT-BYTES (%length, %destination, @address)
+    // NOTE: byte copying
+
+    TUint pc = aPc2 - 1;
+
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint destination = DecodeMultitypeOperandL(aPc2);
+    TUint address = DecodeAddressOperandL(pc, aPc2);
+
+    iCycles += 1 + length;
+
+    if (iLastUsedInputBit)
+        {
+        iLastUsedInputBit = 0;
+        }
+
+    if (iInputMessageReader->Avail(length) != KErrNone)
+        {
+        aPc2 = address;
+        }
+    else
+        {
+        TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+        TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+        while (length)
+            {
+            TUint nextdest = destination;
+            TUint len = ByteCopyingFragmentL(nextdest,
+                                             length,
+                                             bcl,
+                                             bcr);
+
+            if (len)
+                {
+                TPtr8 blockPtr(iUdvmMemory->MemoryPtr() + destination, len);
+                iInputMessageReader->ReadBlock(blockPtr);
+                }
+
+            destination = nextdest;
+            }
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeInputBitsL(TUint& aPc2)
+    {
+    // INPUT-BITS (%length, %destination, @address)
+
+    TUint pc = aPc2 - 1;
+
+    TUint length = DecodeMultitypeOperandL(aPc2);
+    TUint destination = DecodeMultitypeOperandL(aPc2);
+    TUint address = DecodeAddressOperandL(pc, aPc2);
+
+    iCycles += 1;
+
+    if (length > 16)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TUint ibo = iUdvmMemory->ReadMem16L(EReg_input_bit_order);
+
+    if (ibo & (~(EIBOFlag_P | EIBOFlag_H | EIBOFlag_F)))
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    if ((iLastIBO ^ ibo) & EIBOFlag_P)
+        {
+        // P bit changed
+        iLastUsedInputBit = 0;
+        }
+
+    // bytes to read
+    TUint btr = (length - ((8 - iLastUsedInputBit) & 7) + 7) >> 3;
+
+    if (iInputMessageReader->Avail(btr) != KErrNone)
+        {
+        aPc2 = address;
+        }
+    else
+        {
+        iUdvmMemory->WriteMem16L(destination,
+                                 InputMessageBitsL(length,
+                                                   ibo&EIBOFlag_P,
+                                                   ibo&EIBOFlag_F));
+        }
+    iLastIBO = ibo;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeInputHuffmanL(TUint& aPc2)
+    {
+    // INPUT-HUFFMAN (%destination, @address, #n,
+    // bits_1, %lower_bound_1,%upper_bound_1, %uncompressed_1, ...,
+    // bits_n, %lower_bound_n,%upper_bound_n, %uncompressed_n)
+
+    TUint pc = aPc2 - 1;
+
+    TUint destination = DecodeMultitypeOperandL(aPc2);
+    TUint address = DecodeAddressOperandL(pc, aPc2);
+    TUint n = DecodeLiteralOperandL(aPc2);
+
+    iCycles += 1 + n;
+
+    TUint ibo = iUdvmMemory->ReadMem16L(EReg_input_bit_order);
+
+    if (ibo & (~(EIBOFlag_P | EIBOFlag_H | EIBOFlag_F)))
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    if ((iLastIBO ^ ibo) & EIBOFlag_P)
+        {
+        // P bit changed
+        iLastUsedInputBit = 0;
+        }
+
+    TUint p = ibo & EIBOFlag_P;
+    TUint h = ibo & EIBOFlag_H;
+
+    TUint val = 0;
+    TUint bits = 0;
+    TUint len;
+    TUint lower;
+    TUint upper;
+    TUint uncompressed;
+
+    TBool quit = EFalse;
+    while (n && !quit)
+        {
+        len = DecodeMultitypeOperandL(aPc2);
+        lower = DecodeMultitypeOperandL(aPc2);
+        upper = DecodeMultitypeOperandL(aPc2);
+        uncompressed = DecodeMultitypeOperandL(aPc2);
+
+        bits += len;
+        if (bits > 16)
+            {
+            User::Leave(CSigComp::EDecompressionFailure);
+            }
+
+        // bytes to read
+        TUint btr = (len - ((8 - iLastUsedInputBit) & 7) + 7) >> 3;
+
+        if (iInputMessageReader->Avail(btr) != KErrNone)
+            {
+            aPc2 = address;
+            n = 1;
+            quit = ETrue;
+            }
+
+        if (!quit)
+            {
+            val = (val << len) | InputMessageBitsL(len, p, h);
+
+            if ((val >= lower) && (val <= upper))
+                {
+                iUdvmMemory->WriteMem16L(destination,
+                            (val + uncompressed - lower) & KMax16BitValueMask);
+                quit = ETrue;
+                }
+            if (!quit)
+                {
+                n--;
+                }
+            }
+        }
+
+    if (n == 0)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    n--;
+
+    while (n)
+        {
+        len = DecodeMultitypeOperandL(aPc2);
+        lower = DecodeMultitypeOperandL(aPc2);
+        upper = DecodeMultitypeOperandL(aPc2);
+        uncompressed = DecodeMultitypeOperandL(aPc2);
+        n--;
+        }
+
+    iLastIBO = ibo;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeStateAccessL(TUint& aPc2)
+    {
+    /*
+        STATE-ACCESS (%partial_identifier_start,
+                      %partial_identifier_length,
+                      state_begin,
+                      %state_length,
+                      %state_address, %state_instruction)
+        NOTE: byte copying
+    */
+
+    TUint partial_identifier_start = DecodeMultitypeOperandL(aPc2);
+    TUint partial_identifier_length = DecodeMultitypeOperandL(aPc2);
+    TUint state_begin = DecodeMultitypeOperandL(aPc2);
+    TUint state_length = DecodeMultitypeOperandL(aPc2);
+    TUint state_address = DecodeMultitypeOperandL(aPc2);
+    TUint state_instruction = DecodeMultitypeOperandL(aPc2);
+
+    if ((partial_identifier_length < KStateIdentifierMinLength) ||
+       (partial_identifier_length > KStateIdentifierMaxLength))
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    __ASSERT_ALWAYS(partial_identifier_start < iUdvmMemory->MemorySize(),
+                    User::Leave(CSigComp::EDecompressionFailure));
+
+
+    __ASSERT_ALWAYS(partial_identifier_start+partial_identifier_length <=
+                    iUdvmMemory->MemorySize(),
+                    User::Leave(CSigComp::EDecompressionFailure));
+
+    TStateItem* si = iStateMgr->FindStateItem(
+                    TPtrC8(&iUdvmMemory->MemoryPtr()[partial_identifier_start],
+                    partial_identifier_length));
+
+    if (si == NULL)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TestStateAccessLenL(si, partial_identifier_length);
+
+    if (state_length == 0)
+        {
+        state_length = si->iStateLength;
+        }
+
+    if (state_address == 0)
+        {
+        state_address = si->iStateAddress;
+        }
+
+    if (state_instruction == 0)
+        {
+        state_instruction = si->iStateInstruction;
+        }
+
+    if ((state_begin + state_length) > si->iStateLength)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    iCycles += 1 + state_length;
+
+    TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+    TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+    while (state_length)
+        {
+        TUint nextdest = state_address;
+        TUint len = ByteCopyingFragmentL(nextdest,
+                                         state_length,
+                                         bcl,
+                                         bcr);
+
+        if (len)
+            {
+            iUdvmMemory->CopyToMemL(state_address,
+                                    &si->iStateValue[state_begin],
+                                    len);
+            state_begin += len;
+            }
+
+        state_address = nextdest;
+        }
+
+    if (state_instruction)
+        {
+        aPc2 = state_instruction;
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeStateCreateL(TUint& aPc2)
+    {
+    /*
+        STATE-CREATE (%state_length,
+                      %state_address,
+                      %state_instruction,
+                      %minimum_access_length,
+                      %state_retention_priority)
+    */
+
+    if (iStateCreateRequestsNumber == KMaxStateOperations)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TUint state_length = DecodeMultitypeOperandL(aPc2);
+    TUint state_address = DecodeMultitypeOperandL(aPc2);
+    TUint state_instruction = DecodeMultitypeOperandL(aPc2);
+    TUint minimum_access_length = DecodeMultitypeOperandL(aPc2);
+    TUint state_retention_priority = DecodeMultitypeOperandL(aPc2);
+
+    if ((minimum_access_length < KStateIdentifierMinLength) ||
+       (minimum_access_length > KStateIdentifierMaxLength) ||
+       (state_retention_priority == KMaxUdvmMemoryMask))
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TUint i = iStateCreateRequestsNumber+iStateFreeRequestsNumber;
+    iStateOperationRequests[i].iOperation = EOpcode_STATE_CREATE;
+    iStateOperationRequests[i].iStateLength =
+                               static_cast<TUint16>(state_length);
+    iStateOperationRequests[i].iStateAddress =
+                               static_cast<TUint16>(state_address);
+    iStateOperationRequests[i].iStateInstruction =
+                               static_cast<TUint16>(state_instruction);
+    iStateOperationRequests[i].iMinimumAccessLength =
+                               static_cast<TUint16>(minimum_access_length);
+    iStateOperationRequests[i].iStateRetentionPriority =
+                               static_cast<TUint16>(state_retention_priority);
+    iStateOperationRequests[i].iStateValue = new (ELeave)
+                                             CArrayFixFlat<TUint8>(8);
+    iStateCreateRequestsNumber++;
+    iStateOperationRequests[i].iStateValue->ResizeL(state_length);
+
+    iCycles += 1 + state_length;
+
+    TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+    TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+    TUint state_begin = 0;
+    while (state_length)
+        {
+        TUint nextdest = state_address;
+        TUint len = ByteCopyingFragmentL(nextdest,
+                                         state_length,
+                                         bcl,
+                                         bcr);
+
+        if (len)
+            {
+            iUdvmMemory->CopyFromMemL(
+                      &iStateOperationRequests[i].iStateValue->At(state_begin),
+                      state_address,
+                      len);
+            state_begin += len;
+            }
+        state_address = nextdest;
+        }
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeEndMessageL(TUint& aPc2)
+    {
+    /*
+        END-MESSAGE (%requested_feedback_location,
+                     %returned_parameters_location,
+                     %state_length, %state_address,
+                     %state_instruction,
+                     %minimum_access_length,
+                    %state_retention_priority)
+        NOTE: byte copying
+    */
+
+    TUint requested_feedback_location = DecodeMultitypeOperandL(aPc2);
+    TUint returned_parameters_location = DecodeMultitypeOperandL(aPc2);
+    TUint state_length = DecodeMultitypeOperandL(aPc2);
+    TUint state_address = DecodeMultitypeOperandL(aPc2);
+    TUint state_instruction = DecodeMultitypeOperandL(aPc2);
+    TUint minimum_access_length = DecodeMultitypeOperandL(aPc2);
+    TUint state_retention_priority = DecodeMultitypeOperandL(aPc2);
+
+    iCycles += 1 + state_length;
+
+    if ((minimum_access_length >= KStateIdentifierMinLength) &&
+       (minimum_access_length <= KStateIdentifierMaxLength) &&
+       (state_retention_priority != 0xffff))
+        {
+        if (iStateCreateRequestsNumber == KMaxStateOperations)
+            {
+            User::Leave(CSigComp::EDecompressionFailure);
+            }
+
+        TUint i = iStateCreateRequestsNumber+iStateFreeRequestsNumber;
+        iStateOperationRequests[i].iOperation = EOpcode_STATE_CREATE;
+        iStateOperationRequests[i].iStateLength =
+                                       static_cast<TUint16>(state_length);
+        iStateOperationRequests[i].iStateAddress =
+                                       static_cast<TUint16>(state_address);
+        iStateOperationRequests[i].iStateInstruction =
+                                       static_cast<TUint16>(state_instruction);
+        iStateOperationRequests[i].iMinimumAccessLength =
+                                   static_cast<TUint16>(minimum_access_length);
+        iStateOperationRequests[i].iStateRetentionPriority =
+                                static_cast<TUint16>(state_retention_priority);
+        iStateOperationRequests[i].iStateValue = new (ELeave)
+                                                 CArrayFixFlat<TUint8>(8);
+        iStateCreateRequestsNumber++;
+        iStateOperationRequests[i].iStateValue->ResizeL(state_length);
+
+        TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+        TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+        TUint state_begin = 0;
+        while (state_length)
+            {
+            TUint nextdest = state_address;
+            TUint len = ByteCopyingFragmentL(nextdest,
+                                             state_length,
+                                             bcl,
+                                             bcr);
+
+            if (len)
+                {
+                iUdvmMemory->CopyFromMemL(
+                      &iStateOperationRequests[i].iStateValue->At(state_begin),
+                      state_address,
+                      len);
+                state_begin += len;
+                }
+
+            state_address = nextdest;
+            }
+        }
+
+    if (requested_feedback_location)
+        {
+        TUint rfl = requested_feedback_location;
+
+        TUint rf = iUdvmMemory->ReadMem8L(rfl);
+        rfl++;
+
+        if (rf & ERFFlag_Q)
+            {
+            // returned feedback item
+            TUint rff = iUdvmMemory->ReadMem8L(rfl);
+            rfl++;
+
+            if (rff & 0x80)
+                {
+                // long form
+                rfl += rff & 0x7f;
+                // check memory out of range
+                iUdvmMemory->ReadMem8L(rfl - 1);
+                }
+            }
+
+        iRequestedFeedback.Set(&iUdvmMemory->MemoryPtr()
+                                  [requested_feedback_location],
+                               rfl - requested_feedback_location,
+                               rfl - requested_feedback_location);
+        }
+    else
+        {
+        iRequestedFeedback.Set(NULL, 0, 0);
+        }
+
+    if (returned_parameters_location)
+        {
+        TUint rpl = returned_parameters_location;
+
+        iUdvmMemory->ReadMem8L(rpl);    // cpb dms sms
+        rpl++;
+
+        iUdvmMemory->ReadMem8L(rpl);    // version
+        rpl++;
+
+        TBool quit = EFalse;
+        TUint psi;
+        for (; !quit; )
+            {
+            psi = iUdvmMemory->ReadMem8L(rpl);
+            rpl++;
+
+            if ((psi < KStateIdentifierMinLength) ||
+                (psi > KStateIdentifierMaxLength))
+                {
+                quit = ETrue;
+                }
+            else
+                {
+                rpl += psi;
+                }
+            }
+
+        iReturnedParameters.Set(&iUdvmMemory->MemoryPtr()
+                                   [returned_parameters_location],
+                                rpl - returned_parameters_location,
+                                rpl - returned_parameters_location);
+        }
+    else
+        {
+        iReturnedParameters.Set(NULL, 0, 0);
+        }
+    return ETrue;
+    }
+
+TBool CUdvm::ExecuteOpcodeStateFreeL(TUint& aPc2)
+    {
+    /*
+        STATE-FREE (%partial_identifier_start,
+                    %partial_identifier_length)
+    */
+
+    if (iStateFreeRequestsNumber == KMaxStateOperations)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TUint partial_identifier_start = DecodeMultitypeOperandL(aPc2);
+    TUint partial_identifier_length = DecodeMultitypeOperandL(aPc2);
+
+    if ((partial_identifier_length < KStateIdentifierMinLength) ||
+        (partial_identifier_length > KStateIdentifierMaxLength))
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+        }
+
+    TUint i = iStateCreateRequestsNumber+iStateFreeRequestsNumber;
+    iStateOperationRequests[i].iOperation = EOpcode_STATE_FREE;
+    iStateOperationRequests[i].iPartialIdentifierStart =
+                               static_cast<TUint16>(partial_identifier_start);
+    iStateOperationRequests[i].iPartialIdentifierLength =
+                               static_cast<TUint16>(partial_identifier_length);
+    iStateFreeRequestsNumber++;
+    iCycles += 1;
+    return EFalse;
+    }
+
+TBool CUdvm::ExecuteOpcodeOutputL(TUint& aPc2)
+    {
+    // OUTPUT (%output_start, %output_length)
+    // NOTE: byte copying
+
+    TUint start = DecodeMultitypeOperandL(aPc2);
+    TUint length = DecodeMultitypeOperandL(aPc2);
+
+    iCycles += 1 + length;
+
+    TUint bcl = iUdvmMemory->ReadMem16L(EReg_byte_copy_left);
+    TUint bcr = iUdvmMemory->ReadMem16L(EReg_byte_copy_right);
+
+    while (length)
+        {
+        TUint nextstart = start;
+        TUint len = ByteCopyingFragmentL(nextstart, length, bcl, bcr);
+
+        if (len)
+            {
+            iOutputBuffer->InsertL(iOutputBuffer->Size(),
+                                   &iUdvmMemory->MemoryPtr()[start],
+                                   len);
+            }
+        start = nextstart;
+        }
+
+    // RFC 3320, chapter 9.4.8:
+    // Decompression failure occurs if the cumulative number of bytes
+    // provided to the dispatcher exceeds 65536 bytes.
+    if (iOutputBuffer->Size() > KMaxOutputSize)
+        {
+        User::Leave(CSigComp::EDecompressionFailure);
+                }
+
+    return EFalse;
+    }
+
+
+TBool CUdvm::ExecuteOpcodeJumpL(TUint& aPc2)
+    {
+    // JUMP (@address)
+    TUint pc = aPc2 - 1;
+    aPc2 = DecodeAddressOperandL(pc, aPc2);
+    iCycles += 1;
+    return EFalse;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::ExecuteCodeL
+// execute UDVM code
+// ----------------------------------------------------------------------------
+//
+
+void CUdvm::ExecuteCodeL(CMessageReader* aMsgReader)
+    {
+    iInputMessageReader = aMsgReader;
+    iLastUsedInputBit = 0;
+
+    TPtr8 retf(iReturnedFeedback);
+    DenyStateOperations();
+    iReturnedFeedback.Set(retf);
+
+    iOutputBuffer->Reset();
+
+    iCycles = 0;
+
+    TUint pc = iCodeStart;
+    TBool terminated = EFalse;
+
+    while (!terminated)
+        {
+        pc &= KMaxUdvmMemoryMask;
+        TUint8 opcode = iUdvmMemory->ReadMem8L(pc);
+        pc++;
+
+        if (opcode >= EOpcodesNumber)
+            {
+            // unknown opcode
+            User::Leave(CSigComp::EDecompressionFailure);
+            }
+
+        terminated = (this->*iExecuteOpcode[opcode])(pc);
+
+        if (iCycles > iAvailableCycles)
+            {
+            User::Leave(CSigComp::EDecompressionFailure);
+            }
+        }
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::AllowStateOperationsL
+// allow for state operations
+// ----------------------------------------------------------------------------
+//
+
+TInt CUdvm::AllowStateOperationsL(CSigCompCompartment* aCompartment)
+    {
+    TInt sso = 0;
+
+    if (iStateMgr && aCompartment)
+        {
+        TInt soNum = iStateCreateRequestsNumber + iStateFreeRequestsNumber;
+
+        for (TInt i = 0; i < soNum; i++)
+            {
+            if (iStateOperationRequests[i].iOperation == EOpcode_STATE_CREATE)
+                {
+                if (iStateMgr->CreateStateL(aCompartment,
+                   iStateOperationRequests[i].iStateLength,
+                   iStateOperationRequests[i].iStateAddress,
+                   iStateOperationRequests[i].iStateInstruction,
+                   iStateOperationRequests[i].iMinimumAccessLength,
+                   iStateOperationRequests[i].iStateLength ?
+                   &iStateOperationRequests[i].iStateValue->At(0) : NULL,
+                   iStateOperationRequests[i].iStateRetentionPriority) != NULL)
+                    {
+                    sso++;
+                    }
+                }
+
+            if (iStateOperationRequests[i].iOperation == EOpcode_STATE_FREE)
+                {
+                if (iStateMgr->FreeStateL(aCompartment,
+                                         TPtrC8(
+                          &iUdvmMemory->MemoryPtr()
+                          [iStateOperationRequests[i].iPartialIdentifierStart],
+                          iStateOperationRequests[i].iPartialIdentifierLength))
+                          == KErrNone)
+                    {
+                    sso++;
+                    }
+                }
+            }
+
+        if (sso == soNum)
+            {
+            iStateMgr->SetReturnedFeedbackL(*aCompartment,
+                                            iReturnedFeedback);
+            iStateMgr->SetRequestedFeedbackL(*aCompartment,
+                                             iRequestedFeedback);
+            iStateMgr->SetReturnedParametersL(*aCompartment,
+                                              iReturnedParameters);
+            }
+        }
+
+    return sso;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::DenyStateOperations
+// deny state operations
+// ----------------------------------------------------------------------------
+//
+
+void CUdvm::DenyStateOperations()
+    {
+
+    TUint soNum = iStateCreateRequestsNumber + iStateFreeRequestsNumber;
+
+    for (TUint i = 0; i < soNum; i++)
+        {
+        if (iStateOperationRequests[i].iOperation == EOpcode_STATE_CREATE)
+            {
+
+            delete iStateOperationRequests[i].iStateValue;
+            iStateOperationRequests[i].iStateValue = NULL;
+            }
+        }
+
+    iStateCreateRequestsNumber = 0;
+    iStateFreeRequestsNumber = 0;
+
+    iReturnedFeedback.Set(NULL, 0, 0);
+    iRequestedFeedback.Set(NULL, 0, 0);
+    iReturnedParameters.Set(NULL, 0, 0);
+    }
+
+
+// ----------------------------------------------------------------------------
+// CUdvm::CyclesConsumed
+// get consumed cycles number
+// ----------------------------------------------------------------------------
+//
+
+#if defined(SIGCOMP_DEBUG)
+
+TUint CUdvm::CyclesConsumed() const
+    {
+    return iCycles;
+    }
+
+#endif
+
+//  End of File