New Snippet New Snippet Recent Snippets Recent Snippets My Snippets My Snippets Web Code Search Snippets Search
Sign inor Register
Language: C#

TranscodingStream

390 Views
Copy Code Show/Hide Line Numbers
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
 
namespace EAI.BE.BizTalk.PipelineComponents
{
    /// <summary>
    /// TranscodingStream class is a binary tranformation stream decorator. While reading the underlying bytestream is transcoded from a source to a target encoding, on the fly. There is no support for seeking nor writing.
    /// </summary>
    public class TranscodingStream : Stream
    {
        private Stream _stream;
        private StreamReader _reader;
        private Encoder _encoder;
        private long _position = 0;
 
        private Queue<byte> _buffer = new Queue<byte>(3);
        private bool _bufferFilled = false;
 
        private TranscodingStream(Stream stream, Encoding outEncoding) 
        {
            if (stream == null)
                throw new ArgumentNullException("inner");
 
            if (outEncoding == null)
                throw new ArgumentNullException("target");
 
            this._stream = stream;
            this._encoder = outEncoding.GetEncoder();
        }
 
        public TranscodingStream(Stream stream, Encoding outEncoding, Encoding inEncoding) : this(stream, outEncoding)
        {
            if (inEncoding == null)
                throw new ArgumentNullException("source");
         
            this._reader = new StreamReader(_stream, inEncoding);
        }
 
        public TranscodingStream(Stream stream, Encoding outEncoding, bool detectEncodingFromByteOrderMarks) : this(stream,outEncoding)
        {
            if (detectEncodingFromByteOrderMarks == false)
            {
                this._reader = new StreamReader(_stream, Encoding.UTF8);
            }
            else
            {
                this._reader = new StreamReader(_stream, true);
            }
 
        }
 
        public override bool CanRead
        {
            get { return true; }
        }
 
        public override bool CanSeek
        {
            get { return false; }
        }
 
        public override bool CanWrite
        {
            get { return false; }
        }
 
        public override void Flush()
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public override long Length
        {
            get 
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }
 
        public override long Position
        {
            get
            {
                return _position;
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }
 
        public override int Read(byte[] buffer, int offset, int count)
        {
            //if (_position < 0)
            //    throw new InvalidOperationException();
 
            int written = 0;
            int open = offset + count > buffer.Length ? buffer.Length - offset : count;
            int position = 0;
            int read = 0;
            int write = 0;
            char[] readBuffer;
 
            while (open > 0)
            {
                int maxSafeWrite = open / 4;
                
                if(maxSafeWrite>0)
                {
                    readBuffer = new char[maxSafeWrite];
                    
                    read = _reader.Read(readBuffer, 0, maxSafeWrite);
                    
                    if (read == 0)
                        return written;
 
                    write = _encoder.GetBytes(readBuffer, 0, read, buffer, offset + position, true);
                    position += write;
                    _position += write;
                    written += write;
                    
                    if (read < maxSafeWrite)
                        return written;
                }
                else
                {
                    readBuffer = new char[1];
 
                    if (_bufferFilled == false)
                    {
                        read = _reader.Read(readBuffer, 0, 1);
 
                        if (read == 0)
                            return written;
 
                        byte[] writeBuffer = new byte[_encoder.GetByteCount(readBuffer, 0, 1, false)];
 
                        _encoder.GetBytes(readBuffer, 0, 1, writeBuffer, 0, true);
 
                        if (writeBuffer.Length > open)
                        {
                            //more bytes are read from source than available in the output buffer 
                            write = open;
                            for (int i = 0; i < writeBuffer.Length - open; i++)
                            {
                                _buffer.Enqueue(writeBuffer[i + open]);
                            }
                            _bufferFilled = true;
                        }
                        else
                        {
                            write = writeBuffer.Length;
                        }
 
                        for (int i = 0; i < write; i++)
                        {
                            if (offset + position > buffer.GetUpperBound(0))
                                return written;
 
                            buffer[offset + position] = writeBuffer[i];
                            position += 1;
                            _position += 1;
                            written += 1;
 
                        }
 
                    }
                    else
                    {
                        
                        if (_bufferFilled)
                        {
                            buffer[offset + position] = _buffer.Dequeue();
                            _bufferFilled = _buffer.Count > 0;
                            
                            position += 1;
                            _position += 1;
                            written += 1;
                            write = 1;
                        }
                        
                    }
                    
                }
 
                open = open - write;
            }
 
            return written;
        }
 
        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public override void SetLength(long value)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        // base close will call dispose below, so inner stream will effectively be close (streamreader closes stream inside dispose)
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    _reader.Dispose();
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }
    }
} 
by Grgeory Van de Wiele
  August 06, 2009 @ 1:03am
Tags:
Comment:
This TranscodingStream class is a binary tranformation stream decorator: while reading, the underlying bytes are transcoded on the fly from a source to a target encoding. Both source and target encodings are configurable.

Add a comment


Report Abuse
brought to you by:
West Wind Techologies


If you find this site useful and use it frequently please consider making a donation to support this free service.
Donate