--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/iosrv/server/readwrite.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,1223 @@
+// readwrite.cpp
+//
+// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+#include "server.h"
+#include "pipe.h"
+#include "console.h"
+#include "readwrite.h"
+#include "session.h"
+#include "log.h"
+#include "persistentconsole.h"
+
+_LIT(KNewLine, "\r\n");
+_LIT(KLf, "\n");
+
+#ifdef IOSRV_LOGGING
+#define OBJ_NAME(x) TName objName((x).Name())
+#else
+#define OBJ_NAME(x)
+#endif
+
+#define __ASSERT_RETURN(x, y) {if (!(x)) {{y;};return;}}
+
+
+static void CleanupNullMessage(TAny* aMsgPtr)
+ {
+ *((RMsg*)aMsgPtr) = RMsg();
+ }
+
+static void CleanupNullMessagePushL(RMsg& aMsg)
+ {
+ CleanupStack::PushL(TCleanupItem(CleanupNullMessage, &aMsg));
+ }
+
+
+//
+// MIoEndPoint.
+//
+
+TBool MIoEndPoint::IoepIsConsole() const
+ {
+ return IoepIsType(RIoHandle::EConsole);
+ }
+
+
+//
+// MIoReadEndPoint.
+//
+
+void MIoReadEndPoint::IorepReadKeyL(MIoReader&)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+void MIoReadEndPoint::IorepSetConsoleModeL(RIoReadWriteHandle::TMode, MIoReader& aReader)
+ {
+ aReader.IorSetConsoleModeComplete(KErrNotSupported);
+ }
+
+TBool MIoReadEndPoint::AttachedToConsole(const MIoReadEndPoint* aEp)
+ {
+ if (!aEp) return EFalse;
+ if (aEp->IoepIsType(RIoHandle::EPersistentConsole))
+ {
+ CIoPersistentConsole* pcons = (CIoPersistentConsole*)aEp;
+ return AttachedToConsole(pcons->TransientReader());
+ }
+ else
+ {
+ return aEp->IoepIsConsole();
+ }
+ }
+
+
+//
+// MIoWriteEndPoint.
+//
+
+void MIoWriteEndPoint::IowepCursorPosL(MIoWriter& aWriter) const
+ {
+ TPoint pos = IowepCursorPos();
+ aWriter.IowCursorPos(KErrNone, pos);
+ }
+
+void MIoWriteEndPoint::IowepSetCursorPosAbsL(const TPoint& aPoint, MIoWriter& aWriter)
+ {
+ IowepSetCursorPosAbs(aPoint);
+ aWriter.IowSetCursorPosAbsComplete(KErrNone);
+ }
+
+void MIoWriteEndPoint::IowepSetCursorPosRelL(const TPoint& aPoint, MIoWriter& aWriter)
+ {
+ IowepSetCursorPosRel(aPoint);
+ aWriter.IowSetCursorPosRelComplete(KErrNone);
+ }
+
+void MIoWriteEndPoint::IowepSetCursorHeightL(TInt aPercentage, MIoWriter& aWriter)
+ {
+ IowepSetCursorHeight(aPercentage);
+ aWriter.IowSetCursorHeightComplete(KErrNone);
+ }
+
+void MIoWriteEndPoint::IowepSetTitleL(MIoWriter& aWriter)
+ {
+ HBufC* title = aWriter.IowTitleLC();
+ IowepSetTitle(*title);
+ CleanupStack::PopAndDestroy(title);
+ aWriter.IowSetTitleComplete(KErrNone);
+ }
+
+void MIoWriteEndPoint::IowepClearScreenL(MIoWriter& aWriter)
+ {
+ IowepClearScreen();
+ aWriter.IowClearScreenComplete(KErrNone);
+ }
+
+void MIoWriteEndPoint::IowepClearToEndOfLineL(MIoWriter& aWriter)
+ {
+ IowepClearToEndOfLine();
+ aWriter.IowClearToEndOfLineComplete(KErrNone);
+ }
+
+void MIoWriteEndPoint::IowepScreenSizeL(MIoWriter& aWriter) const
+ {
+ TSize size = IowepScreenSize();
+ aWriter.IowScreenSize(KErrNone, size);
+ }
+
+void MIoWriteEndPoint::IowepSetAttributesL(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor, MIoWriter& aWriter)
+ {
+ IowepSetAttributes(aAttributes, aForegroundColor, aBackgroundColor);
+ aWriter.IowSetAttributesComplete(KErrNone);
+ }
+
+TPoint MIoWriteEndPoint::IowepCursorPos() const
+ {
+ return TPoint(0, 0);
+ }
+
+void MIoWriteEndPoint::IowepSetCursorPosAbs(const TPoint&)
+ {
+ }
+
+void MIoWriteEndPoint::IowepSetCursorPosRel(const TPoint&)
+ {
+ }
+
+void MIoWriteEndPoint::IowepSetCursorHeight(TInt)
+ {
+ }
+
+void MIoWriteEndPoint::IowepSetTitle(const TDesC&)
+ {
+ }
+
+void MIoWriteEndPoint::IowepClearScreen()
+ {
+ }
+
+void MIoWriteEndPoint::IowepClearToEndOfLine()
+ {
+ }
+
+TSize MIoWriteEndPoint::IowepScreenSize() const
+ {
+ return TSize(0, 0);
+ }
+
+void MIoWriteEndPoint::IowepSetAttributes(TUint, ConsoleAttributes::TColor, ConsoleAttributes::TColor)
+ {
+ }
+
+TBool MIoWriteEndPoint::AttachedToConsole(const MIoWriteEndPoint* aEp)
+ {
+ if (!aEp) return EFalse;
+ if (aEp->IoepIsType(RIoHandle::EPersistentConsole))
+ {
+ CIoPersistentConsole* pcons = (CIoPersistentConsole*)aEp;
+ return AttachedToConsole(pcons->TransientWriter());
+ }
+ else
+ {
+ return aEp->IoepIsConsole();
+ }
+
+ }
+
+//
+// CIoReadWriteObject.
+//
+
+TUint CIoReadWriteObject::Id() const
+ {
+ return iId;
+ }
+
+CIoReadWriteObject::CIoReadWriteObject(TUint aId)
+ : iId(aId), iOwningThreadId(0)
+ {
+ }
+
+void CIoReadWriteObject::SetOwnerL(TThreadId aOwningThread)
+ {
+ iOwningThreadId = aOwningThread;
+ }
+
+TInt CIoReadWriteObject::Open(TThreadId aOwningThread)
+ {
+ TInt err = CObject::Open();
+ if ((err==KErrNone) && (IsOwner(aOwningThread)))
+ {
+ iOpenedByOwner = ETrue;
+ }
+ return err;
+ }
+
+void CIoReadWriteObject::SetModeL(const RMsg& aMessage)
+ {
+ TInt mode(aMessage.Int0());
+ if ((mode >= RIoWriteHandle::EText) && (mode <= RIoWriteHandle::EBinary))
+ {
+ iMode = static_cast<RIoWriteHandle::TMode>(mode);
+ Complete(aMessage, KErrNone);
+ }
+ else
+ {
+ Complete(aMessage, KErrNotSupported);
+ }
+ }
+
+void CIoReadWriteObject::DoDuplicateL(const CIoReadWriteObject& aDuplicate)
+ {
+ iConsole = aDuplicate.iConsole;
+ }
+
+TBool CIoReadWriteObject::IsOwner(TThreadId aOwningThread) const
+ {
+ return iOwningThreadId == aOwningThread;
+ }
+
+TBool CIoReadWriteObject::OpenedByOwner() const
+ {
+ return iOpenedByOwner;
+ }
+
+void CIoReadWriteObject::SetConsole(CIoConsole& aConsole)
+ {
+ iConsole = &aConsole;
+ }
+
+CIoConsole* CIoReadWriteObject::Console()
+ {
+ return iConsole;
+ }
+
+MIoEndPoint* CIoReadWriteObject::EndPoint()
+ {
+ return iEndPoint;
+ }
+
+const CIoConsole* CIoReadWriteObject::Console() const
+ {
+ return iConsole;
+ }
+
+#ifndef IOSRV_LOGGING
+void CIoReadWriteObject::Dump(const TDesC&) const
+ {
+ }
+#else
+void CIoReadWriteObject::Dump(const TDesC& aData) const
+ {
+ TBuf<80> out;
+ TBuf<16> ascii;
+ TInt dataIndex = 0;
+ TInt pos = 0;
+ do
+ {
+ out.Zero();
+ ascii.Zero();
+ out.AppendNumFixedWidthUC(pos, EHex, 8);
+ out.Append(_L(": "));
+ for (TInt i = 0; i < 16; ++i)
+ {
+ if (dataIndex < aData.Length())
+ {
+ TUint8 byte = (TUint8)aData[dataIndex++];
+ out.AppendNumFixedWidthUC(byte, EHex, 2);
+ out.Append(_L(" "));
+ if ((byte < 0x20) || (byte >= 0x7f) || byte == '%')
+ {
+ byte = '.';
+ }
+ ascii.Append(TChar(byte));
+ ++pos;
+ }
+ else
+ {
+ out.Append(_L(" "));
+ }
+ }
+ out.Append(ascii);
+ CIoLog::Printf(out);
+ }
+ while (dataIndex < aData.Length());
+ }
+#endif
+
+
+//
+// CIoReadObject.
+//
+
+CIoReadObject* CIoReadObject::NewLC(TInt aId)
+ {
+ CIoReadObject* self = new(ELeave) CIoReadObject(aId);
+ LOG(CIoLog::Printf(_L("Read object 0x%08x created"), self));
+ CleanupClosePushL(*self);
+ return self;
+ }
+
+CIoReadObject::~CIoReadObject()
+ {
+ OBJ_NAME(*this);
+ LOG(CIoLog::Printf(_L("Read object \"%S\" (0x%08x) destroying"), &objName, this));
+ if (iEndPoint)
+ {
+ ReadEndPoint()->IorepDetach(*this);
+ }
+
+ CompleteIfPending(iReadMessage, KErrSessionClosed);
+ CompleteIfPending(iReadKeyMessage, KErrSessionClosed);
+ CompleteIfPending(iChangeNotifyMessage, KErrSessionClosed);
+
+ delete iBuf;
+ delete iLineSeparator;
+ iCapturedKeys.Close();
+ iKeyBuffer.Close();
+ }
+
+void CIoReadObject::DuplicateL(const CIoReadObject& aDuplicate)
+ {
+ DoDuplicateL(aDuplicate);
+ if (aDuplicate.iEndPoint)
+ {
+ AttachL(*aDuplicate.ReadEndPoint(), RIoEndPoint::EBackground);
+ }
+ }
+
+void CIoReadObject::AttachL(MIoReadEndPoint& aEndPoint, RIoEndPoint::TReadMode aMode)
+ {
+ if (iEndPoint)
+ {
+ ReadEndPoint()->IorepDetach(*this);
+ }
+
+ aEndPoint.IorepAttachL(*this, aMode);
+ iEndPoint = &aEndPoint;
+ }
+
+void CIoReadObject::SetReadMode(RIoReadHandle::TReadMode aMode)
+ {
+ iReadMode = aMode;
+ }
+
+void CIoReadObject::SetToForegroundL()
+ {
+ if (iEndPoint)
+ {
+ ReadEndPoint()->IorepSetForegroundReaderL(*this);
+ }
+ }
+
+TBool CIoReadObject::IsForegroundL() const
+ {
+ if (iEndPoint)
+ {
+ return ReadEndPoint()->IorepIsForegroundL(*this);
+ }
+ return EFalse;
+ }
+
+void CIoReadObject::ReadL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicReadWhenNotAttached));
+ __ASSERT_RETURN(!MessagePending(iReadMessage) && !MessagePending(iReadKeyMessage), PanicClient(aMessage, EPanicReadAlreadyPending));
+
+ const TInt maxReadLength = MaxDesLengthL(aMessage, 0);
+ AllocateBufferL(maxReadLength);
+ iReadMessage = aMessage;
+ iMaxReadLength = maxReadLength;
+
+ if (iCompleteErr)
+ {
+ if ((iCompleteErr == KErrEof) && (iBuf->Length() > 0))
+ {
+ // the end point has reached the end of the stream
+ // but we haven't finished processing the data in our buffer yet
+ TryToCompleteRead();
+ }
+ else
+ {
+ iReadMessage.Complete(iCompleteErr);
+ }
+ }
+ else
+ {
+ ProcessRead();
+ }
+ }
+
+void CIoReadObject::ReadCancel(const CIoSession& aSession)
+ {
+ if (MessagePending(iReadMessage) && (iReadMessage.Session() == static_cast<const CSession2*>(&aSession)))
+ {
+ Complete(iReadMessage, KErrCancel);
+ iBuf->Des().Zero();
+ }
+ }
+
+void CIoReadObject::ProcessRead()
+ {
+ ASSERT((MessagePending(iReadMessage) || MessagePending(iReadKeyMessage)) && !(MessagePending(iReadMessage) && MessagePending(iReadKeyMessage)));
+
+ if (MessagePending(iReadMessage))
+ {
+ if (iCompleteErr)
+ {
+ iReadMessage.Complete(iCompleteErr);
+ }
+ else
+ {
+ TryToCompleteRead();
+
+ if (IorReadPending())
+ {
+ TRAPD(err, ReadEndPoint()->IorepReadL(*this));
+ if (err)
+ {
+ Complete(iReadMessage, err);
+ }
+ else if (IorReadPending())
+ {
+ TryToCompleteRead();
+ }
+ }
+ }
+ }
+ else
+ {
+ if (iCompleteErr)
+ {
+ iReadKeyMessage.Complete(iCompleteErr);
+ }
+ else
+ {
+ if (iKeyBuffer.Count() > 0)
+ {
+ CompleteReadKey(KErrNone, iKeyBuffer[0]);
+ iKeyBuffer.Remove(0);
+ }
+ else
+ {
+ TRAPD(err, ReadEndPoint()->IorepReadKeyL(*this));
+ if (err)
+ {
+ Complete(iReadKeyMessage, err);
+ }
+ }
+ }
+ }
+ }
+
+void CIoReadObject::SetLineSeparatorL(const RMsg& aMessage)
+ {
+ HBufC* separator = HBufC::NewLC(DesLengthL(aMessage, 0));
+ TPtr ptr(separator->Des());
+ MessageReadL(aMessage, 0, ptr);
+ delete iLineSeparator;
+ iLineSeparator = separator;
+ CleanupStack::Pop(separator);
+ Complete(aMessage, KErrNone);
+ }
+
+void CIoReadObject::ReadKeyL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicReadKeyWhenNotAttached));
+ __ASSERT_RETURN(!MessagePending(iReadMessage) && !MessagePending(iReadKeyMessage), PanicClient(aMessage, EPanicReadAlreadyPending));
+
+ iReadKeyMessage = aMessage;
+
+ if (iCompleteErr)
+ {
+ iReadKeyMessage.Complete(iCompleteErr);
+ }
+ else
+ {
+ ProcessRead();
+ }
+ }
+
+void CIoReadObject::ReadKeyCancel(const CIoSession& aSession)
+ {
+ if (MessagePending(iReadKeyMessage) && (iReadKeyMessage.Session() == &aSession))
+ {
+ Complete(iReadKeyMessage, KErrCancel);
+ }
+ }
+
+void CIoReadObject::CaptureKeyL(const RMsg& aMessage)
+ {
+ User::LeaveIfError(iCapturedKeys.Append(TCapturedKey(aMessage.Int0(), aMessage.Int1(), aMessage.Int2())));
+ Complete(aMessage, KErrNone);
+ }
+
+void CIoReadObject::CancelCaptureKey(const RMsg& aMessage)
+ {
+ TCapturedKey capturedKey(aMessage.Int0(), aMessage.Int1(), aMessage.Int2());
+ const TInt numCapturedKeys = iCapturedKeys.Count();
+ for (TInt i = 0; i < numCapturedKeys; ++i)
+ {
+ const TCapturedKey& thisCapturedKey = iCapturedKeys[i];
+ if ((capturedKey.iKeyCode == thisCapturedKey.iKeyCode) && (capturedKey.iModifiers == thisCapturedKey.iModifiers) && (capturedKey.iModifierMask == thisCapturedKey.iModifierMask))
+ {
+ iCapturedKeys.Remove(i);
+ Complete(aMessage, KErrNone);
+ return;
+ }
+ }
+
+ Complete(aMessage, KErrNotFound);
+ }
+
+void CIoReadObject::CaptureAllKeys(const RMsg& aMessage)
+ {
+ iCaptureAllKeys = ETrue;
+ Complete(aMessage, KErrNone);
+ }
+
+void CIoReadObject::CancelCaptureAllKeys(const RMsg& aMessage)
+ {
+ iCaptureAllKeys = EFalse;
+ Complete(aMessage, KErrNone);
+ }
+
+void CIoReadObject::NotifyChange(const RMsg& aMessage)
+ {
+ if (MessagePending(iChangeNotifyMessage))
+ {
+ Complete(aMessage, KErrAlreadyExists);
+ }
+ else
+ {
+ iChangeNotifyMessage = aMessage;
+ }
+ }
+
+void CIoReadObject::CancelNotifyChange(const CIoSession& aSession)
+ {
+ if (MessagePending(iChangeNotifyMessage) && (iChangeNotifyMessage.Session() == static_cast<const CSession2*>(&aSession)))
+ {
+ Complete(iChangeNotifyMessage, KErrCancel);
+ }
+ }
+
+void CIoReadObject::CancelSetMode(const CIoSession& aSession)
+ {
+ if (MessagePending(iSetModeMessage) && (iSetModeMessage.Session() == static_cast<const CSession2*>(&aSession)))
+ {
+ Complete(iSetModeMessage, KErrCancel);
+ }
+ }
+
+TBool CIoReadObject::IsType(RIoHandle::TType aType) const
+ {
+ return ((aType == RIoHandle::EReadWriteObject) || (aType == RIoHandle::EReadObject));
+ }
+
+void CIoReadObject::SessionClosed(const CIoSession& aSession)
+ {
+ ReadCancel(aSession);
+ ReadKeyCancel(aSession);
+ CancelNotifyChange(aSession);
+ CancelSetMode(aSession);
+ }
+
+void CIoReadObject::SetModeL(const RMsg& aMessage)
+ {
+ TInt mode(aMessage.Int0());
+ if ((mode >= RIoWriteHandle::EText) && (mode <= RIoWriteHandle::EBinary))
+ {
+ if (ReadEndPoint() && ReadEndPoint()->IorepIsForegroundL(*this))
+ {
+ __ASSERT_RETURN(!MessagePending(iSetModeMessage), PanicClient(aMessage, EPanicSetModeAlreadyPending));
+ ReadEndPoint()->IorepSetConsoleModeL((RIoReadWriteHandle::TMode)mode, *this);
+ iSetModeMessage = aMessage;
+ }
+ else
+ {
+ Complete(aMessage, KErrNone);
+ }
+
+ iMode = static_cast<RIoWriteHandle::TMode>(mode);
+ }
+ else
+ {
+ Complete(aMessage, KErrNotSupported);
+ }
+ }
+
+RIoReadWriteHandle::TMode CIoReadObject::IorwMode() const
+ {
+ return iMode;
+ }
+
+TBool CIoReadObject::IorReadPending() const
+ {
+ return (MessagePending(iReadMessage));
+ }
+
+TBool CIoReadObject::IorReadKeyPending() const
+ {
+ return (MessagePending(iReadKeyMessage));
+ }
+
+TDes& CIoReadObject::IorReadBuf()
+ {
+ ASSERT((iMaxReadLength - iBuf->Length()) > 0);
+ iPtr.Set(const_cast<TText*>(iBuf->Des().Ptr()) + iBuf->Length(), 0, iMaxReadLength - iBuf->Length());
+ return iPtr;
+ }
+
+void CIoReadObject::IorDataBuffered(TInt aLength)
+ {
+ iBuf->Des().SetLength(iBuf->Length() + aLength);
+ TryToCompleteRead();
+ }
+
+TBool CIoReadObject::IorDataIsBuffered() const
+ {
+ return (iBuf->Length() > 0);
+ }
+
+TBool CIoReadObject::IorIsKeyCaptured(TUint aKeyCode, TUint aModifiers)
+ {
+ if (iCaptureAllKeys)
+ {
+ return ETrue;
+ }
+ const TInt numCapturedKeys = iCapturedKeys.Count();
+ for (TInt i = 0; i < numCapturedKeys; ++i)
+ {
+ const TCapturedKey& thisCapturedKey = iCapturedKeys[i];
+ if ((aKeyCode == thisCapturedKey.iKeyCode) && ((aModifiers & thisCapturedKey.iModifierMask) == thisCapturedKey.iModifiers))
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+void CIoReadObject::IorReadComplete(TInt aError)
+ {
+ if ((aError == KErrNone) || (aError==KErrEof))
+ {
+ CompleteRead(aError, iBuf->Length());
+ }
+ else
+ {
+ CompleteRead(aError, 0);
+ }
+ }
+
+void CIoReadObject::IorReadKeyComplete(TInt aError, TUint aKeyCode, TUint aModifiers)
+ {
+ RIoConsoleReadHandle::TConsoleKey consoleKey;
+ consoleKey.iKeyCode = aKeyCode;
+ consoleKey.iModifiers = aModifiers;
+ if (IorReadKeyPending())
+ {
+ CompleteReadKey(aError, consoleKey);
+ }
+ else
+ {
+ if (aError)
+ {
+ LOG(CIoLog::Printf(_L("Error in IorReadKeyComplete %d"), aError));
+ if (IorReadPending()) CompleteRead(aError, 0);
+ // What state are we in if neither IorReadKeyPending or IorReadPending are true? Should we be setting iCompleteErr?
+ }
+ else
+ {
+ iKeyBuffer.Append(consoleKey);
+ if (IorReadPending())
+ {
+ TryToCompleteRead();
+ }
+ }
+ }
+ }
+
+TName CIoReadObject::IorName()
+ {
+ return Name();
+ }
+
+void CIoReadObject::IorReaderChange(TUint aChange)
+ {
+ if ((aChange == RIoReadHandle::EGainedForeground) && iEndPoint && ReadEndPoint()->IoepIsType(RIoHandle::EConsole))
+ {
+ ReadEndPoint()->IorepSetConsoleModeL(iMode, *this);
+ }
+
+ if (MessagePending(iChangeNotifyMessage))
+ {
+ TRAPD(err, MessageWriteL(iChangeNotifyMessage, 0, TPckg<TUint>(aChange)));
+ Complete(iChangeNotifyMessage, err);
+ }
+ }
+
+void CIoReadObject::IorSetConsoleModeComplete(TInt aError)
+ {
+ if (MessagePending(iSetModeMessage))
+ {
+ // The set mode request was explicitly requested, so complete it.
+ Complete(iSetModeMessage, aError);
+ }
+ else
+ {
+ // The set mode request was made because the read object has come to the foreground. If there was an error,
+ // report it via the next read request. However, only report errors when setting to binary mode. This is because
+ // every console must implicitly support text mode, but they may not support the extension interface and report
+ // KErrExtensionNotSupported even for text mode.
+
+ if (aError && (iMode == RIoReadWriteHandle::EBinary))
+ {
+ iCompleteErr = aError;
+ }
+ }
+ }
+
+CIoReadObject::CIoReadObject(TInt aId)
+ : CIoReadWriteObject(aId), iPtr(NULL, 0, 0)
+ {
+ }
+
+void CIoReadObject::AllocateBufferL(TInt aLength)
+ {
+ if (iBuf == NULL)
+ {
+ iBuf = HBufC::NewL(aLength);
+ }
+ else if (iBuf->Des().MaxLength() < aLength)
+ {
+ iBuf = iBuf->ReAllocL(aLength);
+ }
+ }
+
+void CIoReadObject::TryToCompleteRead()
+ {
+ if (iKeyBuffer.Count() > 0)
+ {
+ // There are buffered key events so copy them into the read buffer.
+ TDes& readBuf = IorReadBuf();
+ while (iKeyBuffer.Count())
+ {
+ const RIoConsoleReadHandle::TConsoleKey& consoleKey = iKeyBuffer[0];
+ if ((IorwMode() == RIoReadWriteHandle::EText) && (consoleKey.iKeyCode == EKeyEnter))
+ {
+ if ((readBuf.Length() + KNewLine().Length()) <= readBuf.MaxLength())
+ {
+ // If there's enough room, expand EKeyEnter into "\r\n" (otherwise RIoReadHandle::ELine reads won't complete).
+ readBuf.Append(KNewLine);
+ }
+ else if (readBuf.Length() < readBuf.MaxLength())
+ {
+ // Otherwise, just put in the raw code code in the read buffer like normal - the client might be reading into a TBuf<1> (fshell does this for example), in which case there will never be enough room for "\r\n".
+ TPtrC keyCodePtr((TUint16*)&consoleKey.iKeyCode, 1);
+ readBuf.Append(keyCodePtr);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ if (readBuf.Length() < readBuf.MaxLength())
+ {
+ TPtrC keyCodePtr((TUint16*)&consoleKey.iKeyCode, 1);
+ readBuf.Append(keyCodePtr);
+ }
+ else
+ {
+ break;
+ }
+ }
+ iKeyBuffer.Remove(0);
+ }
+ iBuf->Des().SetLength(iBuf->Length() + readBuf.Length());
+ }
+
+ switch (iReadMode)
+ {
+ case RIoReadHandle::EFull:
+ {
+ if (iBuf->Length() == iMaxReadLength)
+ {
+ CompleteRead(KErrNone, iMaxReadLength);
+ }
+ break;
+ }
+ case RIoReadHandle::ELine:
+ {
+ const TDesC* lineSeparator = iLineSeparator;
+ if (lineSeparator == NULL) lineSeparator = &KLf;
+
+ TInt pos = iBuf->Find(*lineSeparator);
+ if (pos >= 0)
+ {
+ CompleteRead(KErrNone, pos + lineSeparator->Length());
+ }
+ else if (iBuf->Length() == iMaxReadLength)
+ {
+ CompleteRead(KErrNone, iMaxReadLength);
+ }
+ else if ((iBuf->Length() > 0) && (iCompleteErr == KErrEof))
+ {
+ // the read end point has reached the end of the stream
+ // there is still some data remaining, but no new line
+ // to just send the last bit
+ CompleteRead(KErrNone, iBuf->Length());
+ }
+ break;
+ }
+ case RIoReadHandle::EOneOrMore:
+ {
+ if (iBuf->Length() > 0)
+ {
+ CompleteRead(KErrNone, iBuf->Length());
+ }
+ break;
+ }
+ }
+ }
+
+void CIoReadObject::CompleteRead(TInt aError, TInt aLength)
+ {
+ if (IorReadPending())
+ {
+ OBJ_NAME(*this);
+
+ if ((aError == KErrNone)||(aError == KErrEof))
+ {
+ LOG(CIoLog::Printf(_L("Read object \'%S\' writing %d characters"), &objName, aLength));
+ TPtrC ptr(iBuf->Des().Ptr(), aLength);
+ LOG(Dump(ptr));
+ TRAPD(err, MessageWriteL(iReadMessage, 0, ptr));
+ if (err == KErrNone)
+ {
+ iBuf->Des().Delete(0, aLength);
+ }
+ else
+ {
+ aError = err;
+ }
+ }
+
+ LOG(CIoLog::Printf(_L("Read object \'%S\' completing read message with %d"), &objName, aError));
+ Complete(iReadMessage, aError);
+ }
+ else if (aError)
+ {
+ iCompleteErr = aError;
+ }
+ }
+
+void CIoReadObject::CompleteReadKey(TInt aError, RIoConsoleReadHandle::TConsoleKey& aConsoleKey)
+ {
+ if (aError == KErrNone)
+ {
+ TPckgC<RIoConsoleReadHandle::TConsoleKey> consoleKeyPckg(aConsoleKey);
+ TRAP(aError, MessageWriteL(iReadKeyMessage, 0, consoleKeyPckg));
+ }
+ Complete(iReadKeyMessage, aError);
+ }
+
+MIoReadEndPoint* CIoReadObject::ReadEndPoint() const
+ {
+ return static_cast<MIoReadEndPoint*>(iEndPoint);
+ }
+
+CIoReadObject::TCapturedKey::TCapturedKey(TUint aKeyCode, TUint aModifierMask, TUint aModifiers)
+ : iKeyCode(aKeyCode), iModifierMask(aModifierMask), iModifiers(aModifiers)
+ {
+ }
+
+
+//
+// CIoWriteObject.
+//
+
+CIoWriteObject* CIoWriteObject::NewLC(TInt aId)
+ {
+ CIoWriteObject* self = new(ELeave) CIoWriteObject(aId);
+ LOG(CIoLog::Printf(_L("Write object 0x%08x created"), self));
+ CleanupClosePushL(*self);
+ return self;
+ }
+
+CIoWriteObject::~CIoWriteObject()
+ {
+ OBJ_NAME(*this);
+ LOG(CIoLog::Printf(_L("Write object \"%S\" (0x%08x) destroying"), &objName, this));
+ if (iEndPoint)
+ {
+ WriteEndPoint()->IowepDetach(*this);
+ }
+
+ CompleteIfPending(iWriteMessage, KErrSessionClosed);
+ CompleteIfPending(iGetCursorPosMsg, KErrSessionClosed);
+ CompleteIfPending(iSetCursorPosAbsMsg, KErrSessionClosed);
+ CompleteIfPending(iSetCursorPosRelMsg, KErrSessionClosed);
+ CompleteIfPending(iSetCursorHeightMsg, KErrSessionClosed);
+ CompleteIfPending(iSetTitleMsg, KErrSessionClosed);
+ CompleteIfPending(iClearScreenMsg, KErrSessionClosed);
+ CompleteIfPending(iClearToEndOfLineMsg, KErrSessionClosed);
+ CompleteIfPending(iGetScreenSizeMsg, KErrSessionClosed);
+ CompleteIfPending(iSetAttributesMsg, KErrSessionClosed);
+ }
+
+void CIoWriteObject::DuplicateL(const CIoWriteObject& aDuplicate)
+ {
+ DoDuplicateL(aDuplicate);
+ if (aDuplicate.iEndPoint)
+ {
+ AttachL(*aDuplicate.WriteEndPoint());
+ }
+ iIsStdErr = aDuplicate.iIsStdErr;
+ }
+
+void CIoWriteObject::AttachL(MIoWriteEndPoint& aEndPoint)
+ {
+ if (iEndPoint)
+ {
+ WriteEndPoint()->IowepDetach(*this);
+ }
+
+ aEndPoint.IowepAttachL(*this);
+ iEndPoint = &aEndPoint;
+ }
+
+void CIoWriteObject::WriteL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicWriteWhenNotAttached));
+ __ASSERT_RETURN(!MessagePending(iWriteMessage), PanicClient(aMessage, EPanicWriteAlreadyPending));
+ iWriteMessage = aMessage;
+ iOffset = 0;
+ iWriteLength = DesLengthL(iWriteMessage, 0);
+ WriteEndPoint()->IowepWriteL(*this);
+ }
+
+void CIoWriteObject::WriteCancel(const CIoSession& aSession)
+ {
+ if (MessagePending(iWriteMessage) && (iWriteMessage.Session() == &aSession))
+ {
+ if (iEndPoint)
+ {
+ WriteEndPoint()->IowepWriteCancel(*this);
+ }
+ Complete(iWriteMessage, KErrCancel);
+ }
+ }
+
+TInt CIoWriteObject::IowWriteLength() const
+ {
+ ASSERT(MessagePending(iWriteMessage));
+ return (iWriteLength - iOffset);
+ }
+
+TInt CIoWriteObject::IowWrite(TDes& aBuf)
+ {
+ ASSERT(MessagePending(iWriteMessage));
+ ASSERT(aBuf.Length() <= (iWriteLength - iOffset));
+ OBJ_NAME(*this);
+ TRAPD(err, MessageReadL(iWriteMessage, 0, aBuf, iOffset));
+ if (err == KErrNone)
+ {
+ LOG(CIoLog::Printf(_L("Write object \'%S\' read %d characters"), &objName, aBuf.Length()));
+ LOG(Dump(aBuf));
+ iOffset += aBuf.Length();
+ }
+ else
+ {
+ LOG(CIoLog::Printf(_L("Write object \'%S\' failed to read: %d"), &objName, err));
+ }
+ return err;
+ }
+
+RIoReadWriteHandle::TMode CIoWriteObject::IowWriteMode() const
+ {
+ return iMode;
+ }
+
+void CIoWriteObject::IowCursorPos(TInt aError, TPoint aPos)
+ {
+ TPckgC<TPoint> posPckg(aPos);
+ Complete(iGetCursorPosMsg, aError==KErrNone ? MessageWrite(iGetCursorPosMsg, 0, posPckg) : aError);
+ }
+
+void CIoWriteObject::IowSetCursorPosAbsComplete(TInt aError)
+ {
+ Complete(iSetCursorPosAbsMsg, aError);
+ }
+
+void CIoWriteObject::IowSetCursorPosRelComplete(TInt aError)
+ {
+ Complete(iSetCursorPosRelMsg, aError);
+ }
+
+void CIoWriteObject::IowSetCursorHeightComplete(TInt aError)
+ {
+ Complete(iSetCursorHeightMsg, aError);
+ }
+
+void CIoWriteObject::IowSetTitleComplete(TInt aError)
+ {
+ Complete(iSetTitleMsg, aError);
+ }
+
+void CIoWriteObject::IowClearScreenComplete(TInt aError)
+ {
+ Complete(iClearScreenMsg, aError);
+ }
+
+void CIoWriteObject::IowClearToEndOfLineComplete(TInt aError)
+ {
+ Complete(iClearToEndOfLineMsg, aError);
+ }
+
+void CIoWriteObject::IowScreenSize(TInt aError, TSize aSize)
+ {
+ if ((aSize == TSize(0, 0)) && Console() && !iTriedConsoleScreenSize)
+ {
+ iTriedConsoleScreenSize = ETrue;
+ TRAPD(err, Console()->IowepScreenSizeL(*this));
+ if (err!=KErrNone)
+ {
+ Complete(iGetScreenSizeMsg, err);
+ }
+ return;
+ }
+ TPckgC<TSize> sizePckg(aSize);
+ Complete(iGetScreenSizeMsg, aError == KErrNone ? MessageWrite(iGetScreenSizeMsg, 0, sizePckg) : aError);
+ }
+
+void CIoWriteObject::IowSetAttributesComplete(TInt aError)
+ {
+ Complete(iSetAttributesMsg, aError);
+ }
+
+HBufC* CIoWriteObject::IowTitleLC()
+ {
+ HBufC* titleBuf = HBufC::NewLC(DesLengthL(iSetTitleMsg, 0));
+ TPtr titlePtr(titleBuf->Des());
+ MessageReadL(iSetTitleMsg, 0, titlePtr);
+ return titleBuf;
+ }
+
+void CIoWriteObject::CursorPosL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicCursorPosWhenNotAttached));
+ __ASSERT_RETURN(iGetCursorPosMsg.IsNull(), PanicClient(aMessage, EPanicCursorPosAlreadyPending));
+ iGetCursorPosMsg = aMessage;
+ CleanupNullMessagePushL(iGetCursorPosMsg);
+ WriteEndPoint()->IowepCursorPosL(*this);
+ CleanupStack::Pop(&iGetCursorPosMsg);
+ }
+
+void CIoWriteObject::SetCursorPosAbsL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicSetCursorPosAbsWhenNotAttached));
+ __ASSERT_RETURN(iSetCursorPosAbsMsg.IsNull(), PanicClient(aMessage, EPanicSetCursorPosAlreadyPending));
+ TPoint pos;
+ TPckg<TPoint> posPckg(pos);
+ MessageReadL(aMessage, 0, posPckg);
+ iSetCursorPosAbsMsg = aMessage;
+ CleanupNullMessagePushL(iSetCursorPosAbsMsg);
+ WriteEndPoint()->IowepSetCursorPosAbsL(pos, *this);
+ CleanupStack::Pop(&iSetCursorPosAbsMsg);
+ }
+
+void CIoWriteObject::SetCursorPosRelL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicSetCursorPosRelWhenNotAttached));
+ __ASSERT_RETURN(iSetCursorPosRelMsg.IsNull(), PanicClient(aMessage, EPanicSetCursorPosAlreadyPending));
+ TPoint pos;
+ TPckg<TPoint> posPckg(pos);
+ MessageReadL(aMessage, 0, posPckg);
+ iSetCursorPosRelMsg = aMessage;
+ CleanupNullMessagePushL(iSetCursorPosRelMsg);
+ WriteEndPoint()->IowepSetCursorPosRelL(pos, *this);
+ CleanupStack::Pop(&iSetCursorPosRelMsg);
+ }
+
+void CIoWriteObject::SetCursorHeightL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicSetCursorHeightWhenNotAttached));
+ __ASSERT_RETURN(iSetCursorHeightMsg.IsNull(), PanicClient(aMessage, EPanicSetCursorHeightAlreadyPending));
+ iSetCursorHeightMsg = aMessage;
+ CleanupNullMessagePushL(iSetCursorHeightMsg);
+ WriteEndPoint()->IowepSetCursorHeightL(aMessage.Int0(), *this);
+ CleanupStack::Pop(&iSetCursorHeightMsg);
+ }
+
+void CIoWriteObject::SetTitleL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicSetTitleWhenNotAttached));
+ __ASSERT_RETURN(iSetTitleMsg.IsNull(), PanicClient(aMessage, EPanicSetTitleAlreadyPending));
+ iSetTitleMsg = aMessage;
+ // if we leave here, the message will be completed by the framework. But we do want to null the message
+ // as it will no longer be valid.
+ CleanupNullMessagePushL(iSetTitleMsg);
+ WriteEndPoint()->IowepSetTitleL(*this);
+ CleanupStack::Pop(&iSetTitleMsg);
+ }
+
+void CIoWriteObject::ClearScreen(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicClearScreenWhenNotAttached));
+ __ASSERT_RETURN(iClearScreenMsg.IsNull(), PanicClient(aMessage, EPanicClearScreenAlreadyPending));
+ iClearScreenMsg = aMessage;
+ CleanupNullMessagePushL(iClearScreenMsg);
+ WriteEndPoint()->IowepClearScreenL(*this);
+ CleanupStack::Pop(&iClearScreenMsg);
+ }
+
+void CIoWriteObject::ClearToEndOfLine(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicClearToEndOfLineWhenNotAttached));
+ __ASSERT_RETURN(iClearToEndOfLineMsg.IsNull(), PanicClient(aMessage, EPanicClearToEndOfLineAlreadyPending));
+ iClearToEndOfLineMsg = aMessage;
+ CleanupNullMessagePushL(iClearToEndOfLineMsg);
+ WriteEndPoint()->IowepClearToEndOfLineL(*this);
+ CleanupStack::Pop(&iClearToEndOfLineMsg);
+ }
+
+void CIoWriteObject::ScreenSizeL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicScreenSizeWhenNotAttached));
+ __ASSERT_RETURN(iGetScreenSizeMsg.IsNull(), PanicClient(aMessage, EPanicScreenSizeAlreadyPending));
+ iGetScreenSizeMsg = aMessage;
+ CleanupNullMessagePushL(iGetScreenSizeMsg);
+ iTriedConsoleScreenSize = EFalse;
+ WriteEndPoint()->IowepScreenSizeL(*this);
+ CleanupStack::Pop(&iGetScreenSizeMsg);
+ }
+
+void CIoWriteObject::SetAttributesL(const RMsg& aMessage)
+ {
+ __ASSERT_RETURN(iEndPoint, PanicClient(aMessage, EPanicSetAttributesWhenNotAttached));
+ __ASSERT_RETURN(iSetAttributesMsg.IsNull(), PanicClient(aMessage, EPanicSetAttributesAlreadyPending));
+ iSetAttributesMsg = aMessage;
+ CleanupNullMessagePushL(iSetAttributesMsg);
+ WriteEndPoint()->IowepSetAttributesL((TUint)aMessage.Int0(), (ConsoleAttributes::TColor)aMessage.Int1(), (ConsoleAttributes::TColor)aMessage.Int2(), *this);
+ CleanupStack::Pop(&iSetAttributesMsg);
+ }
+
+TBool CIoWriteObject::IsType(RIoHandle::TType aType) const
+ {
+ return ((aType == RIoHandle::EReadWriteObject) || (aType == RIoHandle::EWriteObject));
+ }
+
+void CIoWriteObject::SessionClosed(const CIoSession& aSession)
+ {
+ WriteCancel(aSession);
+ }
+
+RIoReadWriteHandle::TMode CIoWriteObject::IorwMode() const
+ {
+ return iMode;
+ }
+
+void CIoWriteObject::IowComplete(TInt aError)
+ {
+ ASSERT(MessagePending(iWriteMessage));
+ Complete(iWriteMessage, aError);
+ iOffset = 0;
+ iWriteLength = 0;
+ }
+
+TName CIoWriteObject::IowName()
+ {
+ return Name();
+ }
+
+CIoWriteObject::CIoWriteObject(TInt aId)
+ : CIoReadWriteObject(aId)
+ {
+ }
+
+MIoWriteEndPoint* CIoWriteObject::WriteEndPoint() const
+ {
+ return static_cast<MIoWriteEndPoint*>(iEndPoint);
+ }
+
+void CIoWriteObject::SetIsStdErr(TBool aFlag)
+ {
+ iIsStdErr = aFlag;
+ }
+
+TBool CIoWriteObject::IowIsStdErr() const
+ {
+ return iIsStdErr;
+ }