/// <summary> /// Begins line reading. /// </summary> /// <param name="op">Read line opeartion.</param> /// <param name="async">If true then this method can complete asynchronously. If false, this method completed always syncronously.</param> /// <returns>Returns true if read line completed synchronously, false if asynchronous operation pending.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception> public bool ReadLine(ReadLineAsyncOP op, bool async) { if (op == null) { throw new ArgumentNullException("op"); } if (!op.Start(async, this)) { /* REMOVE ME: if(!async){ // Wait while async operation completes. while(!op.IsCompleted){ Thread.Sleep(1); } return true; } else{ return false; }*/ return false; } // Completed synchronously. else { return true; } }
/// <summary> /// Reads all data from the source <b>stream</b> and writes it to stream. Period handling and period terminator is added as required. /// </summary> /// <param name="stream">Source stream which data to write to stream.</param> /// <returns>Returns number of bytes written to source stream.</returns> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null.</exception> /// <exception cref="LineSizeExceededException">Is raised when <b>stream</b> has too big line.</exception> public long WritePeriodTerminated(Stream stream) { if (m_IsDisposed) { throw new ObjectDisposedException(GetType().Name); } if (stream == null) { throw new ArgumentNullException("stream"); } // We need to read lines, do period handling and write them to stream. long totalWritten = 0; byte[] buffer = new byte[m_BufferSize]; ReadLineAsyncOP readLineOP = new ReadLineAsyncOP(buffer, SizeExceededAction.ThrowException); SmartStream reader = new SmartStream(stream, false); while (true) { reader.ReadLine(readLineOP, false); if (readLineOP.Error != null) { throw readLineOP.Error; } // We reached end of stream, no more data. if (readLineOP.BytesInBuffer == 0) { break; } // Period handling. If line starts with period(.), additional period is added. if (readLineOP.LineBytesInBuffer > 0 && buffer[0] == '.') { // Add additional period. Write(new[] {(byte) '.'}, 0, 1); totalWritten++; } // Write line to source stream. Write(buffer, 0, readLineOP.BytesInBuffer); totalWritten += readLineOP.BytesInBuffer; } // Write period terminator. WriteLine("."); Flush(); return totalWritten; }
/// <summary> /// Default constructor. /// </summary> /// <param name="stream">Stream wehre to sore readed data.</param> /// <param name="maxCount">Maximum number of bytes to read. Value 0 means not limited.</param> /// <param name="exceededAction">Specifies how period-terminated reader behaves when <b>maxCount</b> exceeded.</param> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception> public ReadPeriodTerminatedAsyncOP(Stream stream, long maxCount, SizeExceededAction exceededAction) { if (stream == null) { throw new ArgumentNullException("stream"); } m_pStream = stream; m_MaxCount = maxCount; m_ExceededAction = exceededAction; m_pReadLineOP = new ReadLineAsyncOP(new byte[Workaround.Definitions.MaxStreamLineLength], exceededAction); m_pReadLineOP.Completed += m_pReadLineOP_Completed; }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if (m_IsDisposed) { return; } m_IsDisposed = true; m_pOwner = null; m_pStream = null; m_pReadLineOP.Dispose(); m_pReadLineOP = null; m_pException = null; Completed = null; }
/// <summary> /// Default constructor. /// </summary> /// <param name="stream">Stream wehre to sore readed data.</param> /// <param name="maxCount">Maximum number of bytes to read. Value 0 means not limited.</param> /// <param name="exceededAction">Specifies how period-terminated reader behaves when <b>maxCount</b> exceeded.</param> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception> public ReadPeriodTerminatedAsyncOP(Stream stream,long maxCount,SizeExceededAction exceededAction) { if(stream == null){ throw new ArgumentNullException("stream"); } m_pStream = stream; m_MaxCount = maxCount; m_ExceededAction = exceededAction; m_pReadLineOP = new ReadLineAsyncOP(new byte[32000],exceededAction); m_pReadLineOP.Completed += new EventHandler<EventArgs<ReadLineAsyncOP>>(m_pReadLineOP_Completed); }
/// <summary> /// Is called when source stream read line reading has completed. /// </summary> /// <param name="op">Asynchronous operation.</param> private void ReadLineCompleted(ReadLineAsyncOP op) { try{ if(op.Error != null){ m_pException = op.Error; SetState(AsyncOP_State.Completed); } else{ // We have readed all source stream data, we are done. if(op.BytesInBuffer == 0){ // Line ends CRLF. if(m_EndsCRLF){ m_BytesWritten += 3; m_pOwner.BeginWrite(new byte[]{(byte)'.',(byte)'\r',(byte)'\n'},0,3,this.SendTerminatorCompleted,null); } // Line doesn't end CRLF, we need to add it. else{ m_BytesWritten += 5; m_pOwner.BeginWrite(new byte[]{(byte)'\r',(byte)'\n',(byte)'.',(byte)'\r',(byte)'\n'},0,5,this.SendTerminatorCompleted,null); } op.Dispose(); } // Write readed line. else{ m_BytesWritten += op.BytesInBuffer; // Check if line ends CRLF. if(op.BytesInBuffer >= 2 && op.Buffer[op.BytesInBuffer - 2] == '\r' && op.Buffer[op.BytesInBuffer - 1] == '\n'){ m_EndsCRLF = true; } else{ m_EndsCRLF = false; } // Period handling. If line starts with period(.), additional period is added. if(op.Buffer[0] == '.'){ byte[] buffer = new byte[op.BytesInBuffer + 1]; buffer[0] = (byte)'.'; Array.Copy(op.Buffer,0,buffer,1,op.BytesInBuffer); m_pOwner.BeginWrite(buffer,0,buffer.Length,this.SendLineCompleted,null); } // Normal line. else{ m_pOwner.BeginWrite(op.Buffer,0,op.BytesInBuffer,this.SendLineCompleted,null); } } } } catch(Exception x){ m_pException = x; SetState(AsyncOP_State.Completed); op.Dispose(); } }
/// <summary> /// Starts operation processing. /// </summary> /// <param name="owner">Owner SmartStream.</param> /// <returns>Returns true if asynchronous operation in progress or false if operation completed synchronously.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> internal bool Start(SmartStream owner) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pOwner = owner; SetState(AsyncOP_State.Active); try{ // Read line. m_pReadLineOP = new ReadLineAsyncOP(new byte[32000],SizeExceededAction.ThrowException); m_pReadLineOP.Completed += delegate(object s,EventArgs<ReadLineAsyncOP> e){ ReadLineCompleted(m_pReadLineOP); }; if(m_pStream.ReadLine(m_pReadLineOP,true)){ ReadLineCompleted(m_pReadLineOP); } } catch(Exception x){ m_pException = x; SetState(AsyncOP_State.Completed); m_pReadLineOP.Dispose(); } // Set flag rise CompletedAsync event flag. The event is raised when async op completes. // If already completed sync, that flag has no effect. lock(m_pLock){ m_RiseCompleted = true; return m_State == AsyncOP_State.Active; } }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if(m_State == AsyncOP_State.Disposed){ return; } SetState(AsyncOP_State.Disposed); m_pException = null; m_pStream = null; m_pOwner = null; m_pReadLineOP = null; this.CompletedAsync = null; }
/// <summary> /// Begins line reading. /// </summary> /// <param name="op">Read line opeartion.</param> /// <param name="async">If true then this method can complete asynchronously. If false, this method completed always syncronously.</param> /// <returns>Returns true if read line completed synchronously, false if asynchronous operation pending.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception> public bool ReadLine(ReadLineAsyncOP op,bool async) { if(op == null){ throw new ArgumentNullException("op"); } #region async if(async){ return op.Start(async,this); } #endregion #region sync else{ byte[] buffer = op.Buffer; int bytesInBuffer = 0; int lastByte = -1; bool CRLFLinesOnly = true; int lineBuffSize = buffer.Length; SizeExceededAction exceededAction = op.SizeExceededAction; Exception exception = null; try{ while(true){ // Read buffer empty, buff next data block. if(m_ReadBufferOffset >= m_ReadBufferCount){ this.BufferRead(false,null); // We reached end of stream, no more data. if(m_ReadBufferCount == 0){ break; } } byte b = m_pReadBuffer[m_ReadBufferOffset++]; // Line buffer full. if(bytesInBuffer >= lineBuffSize){ if(exception == null){ exception = new LineSizeExceededException(); } if(exceededAction == SizeExceededAction.ThrowException){ break; } } // Store byte. else{ buffer[bytesInBuffer++] = b; } // We have LF line. if(b == '\n'){ if(!CRLFLinesOnly || CRLFLinesOnly && lastByte == '\r'){ break; } } lastByte = b; } } catch(Exception x){ exception = x; } // Set read line operation result data. op.SetInfo(bytesInBuffer,exception); return true; } #endregion }