using System; using System.Collections; /* * Copyright 2012 Mario Vernari (http://cetdevelop.codeplex.com/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * 09/Apr/2012: * Added the ToArray method. **/ namespace ModbusLib { /// /// Wrapper around an ordinary byte array, /// which realizes a forward-only writer /// public class ByteArrayWriter : IEnumerable, IByteArray { private const int CHUNK_SIZE = 0x100; /// /// Crea an empty instance /// public ByteArrayWriter() { _buffer = new byte[CHUNK_SIZE]; _proxy = new byte[8]; } /// /// Create an instance using the specified content, /// and sealing it as immutable /// /// public ByteArrayWriter(byte[] initial) { _length = initial.Length; _buffer = new byte[_length]; Array.Copy( initial, _buffer, _length); } private byte[] _buffer; private int _length; private readonly byte[] _proxy; /// /// Indicate the current length of the written data /// public int Length { get { return _length; } } /// /// Provide a way to reset the writer /// /// /// This functionaly is not allowed when the writer has been sealed /// public void Reset() { CheckImmutable(); _length = 0; } /// /// Create a using the current writer as source /// /// public ByteArrayReader ToReader() { return new ByteArrayReader(((IByteArray)this).Data); } /// /// Create a byte-array using the current writer as source /// /// public byte[] ToArray() { return ((IByteArray)this).Data; } /// /// Add a byte to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteByte(byte value) { Allocate(1); _buffer[_length++] = value; } /// /// Add a series of bytes to the writer, from a byte array /// by specifying the starting index and the number involved /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteBytes( byte[] values, int offset, int count) { Allocate(count); Array.Copy( values, offset, _buffer, _length, count); _length += count; } /// /// Add a series of bytes to the writer /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteBytes(byte[] values) { WriteBytes( values, 0, values.Length); } /// /// Add the content of the given reader to the writer /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteBytes(ByteArrayReader reader) { WriteBytes(((IByteArray)reader).Data); } /// /// Add the content of another writer to the writer /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteBytes(ByteArrayWriter writer) { WriteBytes(((IByteArray)writer).Data); } /// /// Add an (Little-endian) to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteInt16LE(Int16 value) { CheckImmutable(); ByteArrayHelpers.WriteInt16LE( _proxy, 0, value); WriteBytes( _proxy, 0, 2); } /// /// Add an (Big-endian) to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteInt16BE(Int16 value) { CheckImmutable(); ByteArrayHelpers.WriteInt16BE( _proxy, 0, value); WriteBytes( _proxy, 0, 2); } #region NON CLS-Compliant members #pragma warning disable 3001, 3002, 0618 /// /// Add an (Little-endian) to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteUInt16LE(UInt16 value) { CheckImmutable(); ByteArrayHelpers.WriteUInt16LE( _proxy, 0, value); WriteBytes( _proxy, 0, 2); } /// /// Add an (Big-endian) to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteUInt16BE(UInt16 value) { CheckImmutable(); ByteArrayHelpers.WriteUInt16BE( _proxy, 0, value); WriteBytes( _proxy, 0, 2); } #pragma warning restore 3001, 3002, 0618 #endregion /// /// Add an (Little-endian) to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteInt32LE(Int32 value) { CheckImmutable(); ByteArrayHelpers.WriteInt32LE( _proxy, 0, value); WriteBytes( _proxy, 0, 4); } /// /// Add an (Big-endian) to the writer /// /// /// /// This functionality is not allowed when the writer has been sealed /// public void WriteInt32BE(Int32 value) { CheckImmutable(); ByteArrayHelpers.WriteInt32BE( _proxy, 0, value); WriteBytes( _proxy, 0, 4); } /// /// Allocate the specified number of bytes in the underlying /// buffer. Get the buffer longer when needed /// /// private void Allocate(int count) { CheckImmutable(); var size = _buffer.Length; var newLen = _length + count; if (newLen < size) return; do { size += CHUNK_SIZE; } while (size < newLen); var temp = new byte[size]; Array.Copy( _buffer, temp, _buffer.Length); _buffer = temp; } private void CheckImmutable() { //if the instance has been created as immutable, //can't allow any modification if (_proxy == null) throw new Exception(); } #region IEnumerable members IEnumerator IEnumerable.GetEnumerator() { for (int i = 0; i < _length; i++) yield return _buffer[i]; } #endregion /// /// Facility for data exchange /// /// /// Avoid to use this member unless strictly necessary /// byte[] IByteArray.Data { get { var temp = new byte[_length]; Array.Copy( _buffer, temp, _length); return temp; } } } }