//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #if !OBJECTSTATEFORMATTER namespace System.Web.UI { using System.Text; using System.IO; using System.Collections; using System.Globalization; using System.Web.Configuration; internal class LosWriter : TextWriter{ private const int BUFFER_SIZE = 4096; private const int MAX_FREE_BUFFERS = 16; private static CharBufferAllocator _charBufferAllocator; private static CharBufferAllocator _charBufferAllocatorBase64; private static UbyteBufferAllocator _byteBufferAllocator; private char[] _charBuffer; private byte[] _byteBuffer; private int _size; private int _freePos; private bool _recyclable; static LosWriter() { _charBufferAllocator = new CharBufferAllocator(BUFFER_SIZE, MAX_FREE_BUFFERS); int byteBufferSize = Encoding.UTF8.GetMaxByteCount(BUFFER_SIZE); _byteBufferAllocator = new UbyteBufferAllocator(byteBufferSize, MAX_FREE_BUFFERS); // base64 increases data by up to 33%, so we err on the side of caution here _charBufferAllocatorBase64 = new CharBufferAllocator((int) (byteBufferSize * 1.35), MAX_FREE_BUFFERS); } internal LosWriter() { _charBuffer = (char[])_charBufferAllocator.GetBuffer(); _size = _charBuffer.Length; _freePos = 0; _recyclable = true; } internal void Dispose() { if (_recyclable) { if (_charBuffer != null) _charBufferAllocator.ReuseBuffer(_charBuffer); if (_byteBuffer != null) _byteBufferAllocator.ReuseBuffer(_byteBuffer); } _byteBuffer = null; _charBuffer = null; } public override Encoding Encoding { get { return null; } } private void Grow(int newSize) { if (newSize <= _size) return; if (newSize < _size*2) newSize = _size*2; char[] newBuffer = new char[newSize]; if (_freePos > 0) Array.Copy(_charBuffer, newBuffer, _freePos); _charBuffer = newBuffer; _size = newSize; _recyclable = false; } public override void Write(char ch) { if (_freePos >= _size) Grow(_freePos+1); _charBuffer[_freePos++] = ch; } public override void Write(String s) { int len = s.Length; int newFreePos = _freePos + len; if (newFreePos > _size) Grow(newFreePos); s.CopyTo(0, _charBuffer, _freePos, len); _freePos = newFreePos; } internal /*public*/ void CompleteTransforms(TextWriter output, bool enableMac, byte[] macKey) { int len = 0; // convert to bytes if (_recyclable) { // still using the original recyclable char buffer // -- can use recyclable byte buffer _byteBuffer = (byte[])_byteBufferAllocator.GetBuffer(); if (_freePos > 0) len = Encoding.UTF8.GetBytes(_charBuffer, 0, _freePos, _byteBuffer, 0); // do the mac encoding if requested if (enableMac) { // the size of the output array depends on the key length and encryption type // so we can't use the recyclable buffers after this byte[] data = MachineKeySection.GetEncodedData(_byteBuffer, macKey, 0, ref len); string serialized = Convert.ToBase64String(data, 0, len); output.Write(serialized); } else { char[] base64chars = (char[]) _charBufferAllocatorBase64.GetBuffer(); len = Convert.ToBase64CharArray(_byteBuffer, 0, len, base64chars, 0); output.Write(base64chars, 0, len); _charBufferAllocatorBase64.ReuseBuffer(base64chars); } } else { _byteBuffer = Encoding.UTF8.GetBytes(_charBuffer, 0, _freePos); len = _byteBuffer.Length; if (enableMac) _byteBuffer = MachineKeySection.GetEncodedData(_byteBuffer, macKey, 0, ref len); string serialized = Convert.ToBase64String(_byteBuffer); output.Write(serialized); } } } } #endif // !OBJECTSTATEFORMATTER