edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/IronRuby.Tests.csproj;C853491
File: IronRuby.Tests.csproj
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/IronRuby.Tests.csproj;C853491  (server)    5/6/2009 11:24 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/IronRuby.Tests.csproj;Files3
@@ -67,6 +67,7 @@
     <Compile Include="Runtime\DeclarationTests.cs" />
     <Compile Include="Runtime\DlrInteropTests.cs" />
     <Compile Include="Runtime\InterpreterTests.cs" />
+    <Compile Include="Runtime\IoTests.cs" />
     <Compile Include="Runtime\MethodTests.cs" />
     <Compile Include="Runtime\MiscTests.cs" />
     <Compile Include="Runtime\ModuleTests.cs" />
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C857486
File: RubyTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C857486  (server)    5/6/2009 11:23 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;Files3
@@ -88,6 +88,7 @@
                 Scenario_RubyMath1,
 
                 MutableString1,
+                File1,
                 StringsPlus,
                 Strings0,
                 Strings1,
@@ -565,7 +566,7 @@
                 Dlr_Comparable,
                 Dlr_RubyObjects,
                 Dlr_Methods,
-                Dlr_Languages
+                Dlr_Languages,
             };
         }
     }
===================================================================
add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/IoTests.cs
File: IoTests.cs
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/IoTests.cs;Files3
@@ -1,0 +1,85 @@
+?/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation. 
+ *
+ * This source code is subject to terms and conditions of the Microsoft Public License. A 
+ * copy of the license can be found in the License.html file at the root of this distribution. If 
+ * you cannot locate the  Microsoft Public License, please send an email to 
+ * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
+ * by the terms of the Microsoft Public License.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using IronRuby.Builtins;
+using System.Text;
+using System.Diagnostics;
+using System.Collections.Generic;
+using IronRuby.Runtime;
+using Microsoft.Scripting;
+using System.IO;
+using Microsoft.Scripting.Utils;
+
+namespace IronRuby.Tests {
+    public partial class Tests {
+        public void File1() {
+            Test_Read1();
+        }
+
+        private class TestStream : MemoryStream {
+            private readonly bool _canSeek;
+
+            public TestStream(bool canSeek, byte[] data) 
+                : base(data) {
+                _canSeek = canSeek;
+            }
+
+            public override bool CanSeek {
+                get { return false; }
+            }
+        }
+
+        private byte[] B(string str) {
+            return BinaryEncoding.Instance.GetBytes(str);
+        }
+
+        private void Test_Read1() {
+            string s;
+            string crlf = "\r\n";
+            var stream = new TestStream(false, B(
+                "ab\r\r\n" +
+                "e" + (s = "fgh" + crlf + "ijkl" + crlf + "mnop" + crlf + crlf + crlf + crlf + "qrst") +
+                crlf + "!"
+            ));
+            int s_crlf_count = 6;
+
+            var io = new RubyIO(Context, stream, "r");
+            Assert(io.PeekByte() == (byte)'a');
+
+            var buffer = MutableString.CreateBinary(B("foo:"));
+            Assert(io.AppendBytes(buffer, 4) == 4);
+            Assert(buffer.ToString() == "foo:ab\r\n");
+
+            buffer = MutableString.CreateBinary();
+            Assert(io.AppendBytes(buffer, 1) == 1);
+            Assert(buffer.ToString() == "e");
+
+            buffer = MutableString.CreateMutable("x:");
+            int c = s.Length - s_crlf_count - 2;
+            Assert(io.AppendBytes(buffer, c) == c);
+            Assert(buffer.ToString() == "x:" + s.Replace(crlf, "\n").Substring(0, c));
+
+            buffer = MutableString.CreateBinary();
+            Assert(io.AppendBytes(buffer, 10) == 4);
+            Assert(buffer.ToString() == "st\n!");
+
+            buffer = MutableString.CreateBinary();
+            Assert(io.AppendBytes(buffer, 10) == 0);
+            Assert(buffer.ToString() == "");
+
+        }
+    }
+}
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MethodTests.cs;C786764
File: MethodTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MethodTests.cs;C786764  (server)    5/6/2009 11:22 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MethodTests.cs;Files3
@@ -861,5 +861,80 @@
         public void MethodDefinitionInModuleEval1B() {
             AssertOutput(() => CompilerTest(MethodDefinitionInModuleEvalCode), "B");
         }
+
+        public void Scenario_ModuleOps_Methods() {
+            AssertOutput(delegate() {
+                CompilerTest(@"
+class C
+  def ifoo
+    puts 'ifoo'
+  end
+end
+
+class << C
+  $C1 = self
+  
+  def foo
+    puts 'foo'
+  end
+end
+
+class C
+  alias_method(:bar,:foo) rescue puts 'Error 1'
+  instance_method(:foo) rescue puts 'Error 2'
+  puts method_defined?(:foo)
+  foo
+  
+  alias_method(:ibar,:ifoo)
+  instance_method(:ifoo)
+  puts method_defined?(:ifoo)
+  ifoo rescue puts 'Error 3'
+  
+  remove_method(:ifoo)
+end
+
+C.new.ifoo rescue puts 'Error 4'
+C.new.ibar
+");
+            }, @"
+Error 1
+Error 2
+false
+foo
+true
+Error 3
+Error 4
+ifoo
+");
+        }
+
+        public void Methods1() {
+            AssertOutput(delegate() {
+                CompilerTest(@"
+class C
+  def foo a,b
+    puts a + b
+  end
+end
+
+class D < C
+end
+
+c = C.new
+p m = c.method(:foo)
+p u = m.unbind
+p n = u.bind(D.new)
+
+m[1,2]
+n[1,2]
+");
+            }, @"
+#<Method: C#foo>
+#<UnboundMethod: C#foo>
+#<Method: D(C)#foo>
+3
+3
+");
+        }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MiscTests.cs;C840659
File: MiscTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MiscTests.cs;C840659  (server)    5/6/2009 11:22 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MiscTests.cs;Files3
@@ -846,80 +846,5 @@
 ");
             }, @"System::Collections::ArrayList");
         }
-
-        public void Scenario_ModuleOps_Methods() {
-            AssertOutput(delegate() {
-                CompilerTest(@"
-class C
-  def ifoo
-    puts 'ifoo'
-  end
-end
-
-class << C
-  $C1 = self
-  
-  def foo
-    puts 'foo'
-  end
-end
-
-class C
-  alias_method(:bar,:foo) rescue puts 'Error 1'
-  instance_method(:foo) rescue puts 'Error 2'
-  puts method_defined?(:foo)
-  foo
-  
-  alias_method(:ibar,:ifoo)
-  instance_method(:ifoo)
-  puts method_defined?(:ifoo)
-  ifoo rescue puts 'Error 3'
-  
-  remove_method(:ifoo)
-end
-
-C.new.ifoo rescue puts 'Error 4'
-C.new.ibar
-");
-            }, @"
-Error 1
-Error 2
-false
-foo
-true
-Error 3
-Error 4
-ifoo
-");
-        }
-
-        public void Methods1() {
-            AssertOutput(delegate() {
-                CompilerTest(@"
-class C
-  def foo a,b
-    puts a + b
-  end
-end
-
-class D < C
-end
-
-c = C.new
-p m = c.method(:foo)
-p u = m.unbind
-p n = u.bind(D.new)
-
-m[1,2]
-n[1,2]
-");
-            }, @"
-#<Method: C#foo>
-#<UnboundMethod: C#foo>
-#<Method: D(C)#foo>
-3
-3
-");
-        }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs;C840739
File: IoOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs;C840739  (server)    5/5/2009 6:30 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs;Files3
@@ -738,33 +738,20 @@
         }
 
         [RubyMethod("read")]
-        public static MutableString/*!*/ Read(RubyIO/*!*/ self, [DefaultProtocol]int bytes, [DefaultProtocol, Optional]MutableString buffer) {
+        public static MutableString Read(RubyIO/*!*/ self, [DefaultProtocol]int bytes, [DefaultProtocol, Optional]MutableString buffer) {
             self.AssertOpenedForReading();
-            if (self.IsEndOfStream()) {
-                return null;
+            if (bytes < 0) {
+                throw RubyExceptions.CreateArgumentError("negative length -1 given");
             }
 
             if (buffer == null) {
                 buffer = MutableString.CreateBinary();
-            }
-
-            buffer.Clear();
-            if (!self.PreserveEndOfLines) {
-                for (int i = 0; i < bytes; ++i) {
-                    int c = self.ReadByteNormalizeEoln();
-                    if (c == -1) {
-                        return buffer;
-                    } else {
-                        buffer.Append((byte)c);
-                    }
-                }
             } else {
-                var fixedBuffer = new byte[bytes];
-                bytes = self.ReadBytes(fixedBuffer, 0, bytes);
-                buffer.Append(fixedBuffer, 0, bytes);
+                buffer.Clear();
             }
 
-            return buffer;
+            int bytesRead = self.AppendBytes(buffer, bytes);
+            return (bytesRead == 0 && bytes != 0) ? null : buffer;
         }
 
         [RubyMethod("read", RubyMethodAttributes.PublicSingleton)]
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.Content.cs;C785561
File: MutableString.Content.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.Content.cs;C785561  (server)    5/5/2009 6:56 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.Content.cs;Files3
@@ -19,6 +19,7 @@
 using System.Text;
 using IronRuby.Runtime;
 using System.Diagnostics;
+using System.IO;
 
 namespace IronRuby.Builtins {
     public partial class MutableString {
@@ -69,8 +70,11 @@
 
             public abstract string/*!*/ ConvertToString();
             public abstract byte[]/*!*/ ConvertToBytes();
+            public abstract void SwitchToBinaryContent();
+            public abstract void SwitchToStringContent();
 
             public abstract byte[]/*!*/ ToByteArray();
+            internal abstract byte[]/*!*/ GetByteArray();
             public abstract GenericRegex/*!*/ ToRegularExpression(RubyRegexOptions options);
 
             // returns self if there are no characters to be escaped:
@@ -79,11 +83,14 @@
             // read:
             public abstract bool IsBinary { get; }
             public abstract bool IsEmpty { get; }
-            public abstract int Length { get; }
+            public abstract int Count { get; }
             public abstract int GetBinaryHashCode();
             public abstract int GetHashCode(out int binarySum);
             public abstract int GetCharCount();
             public abstract int GetByteCount();
+            public abstract void TrimExcess();
+            public abstract int GetCapacity();
+            public abstract void SetCapacity(int capacity);
             public abstract Content/*!*/ Clone();
 
             public abstract char GetChar(int index);
@@ -116,6 +123,7 @@
             public abstract Content/*!*/ Append(string/*!*/ str, int start, int count);
             public abstract Content/*!*/ Append(char[]/*!*/ chars, int start, int count);
             public abstract Content/*!*/ Append(byte[]/*!*/ bytes, int start, int count);
+            public abstract Content/*!*/ Append(Stream/*!*/ stream, int count);
             public abstract Content/*!*/ AppendTo(Content/*!*/ str, int start, int count);
 
             public abstract Content/*!*/ AppendFormat(IFormatProvider provider, string/*!*/ format, object[]/*!*/ args);
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C786074
File: MutableString.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C786074  (server)    5/5/2009 6:56 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;Files3
@@ -22,6 +22,7 @@
 using IronRuby.Runtime;
 using Microsoft.Scripting.Runtime;
 using IronRuby.Compiler;
+using System.IO;
 
 namespace IronRuby.Builtins {
 
@@ -158,7 +159,7 @@
         }
 
         public static MutableString/*!*/ CreateBinary() {
-            return new MutableString(RubyEncoding.Binary);
+            return new MutableString(new byte[Utils.MinBufferSize], 0, RubyEncoding.Binary);
         }
 
         public static MutableString/*!*/ CreateBinary(int capacity) {
@@ -401,6 +402,14 @@
             return _content.ConvertToBytes();
         }
 
+        public void SwitchToBinary() {
+            _content.SwitchToBinaryContent();
+        }
+
+        public void SwitchToString() {
+            _content.SwitchToStringContent();
+        }
+
         // used by auto-conversions
         [Obsolete("Do not use in code")]
         public static implicit operator string(MutableString/*!*/ self) {
@@ -461,11 +470,11 @@
         // TODO: replace by CharCount, ByteCount
         //[Obsolete("Use GetCharCount(), GetByteCount()")]
         public int Length {
-            get { return _content.Length; }
+            get { return _content.Count; }
         }
         
         public int GetLength() {
-            return _content.Length;
+            return _content.Count;
         }
 
         public int GetCharCount() {
@@ -476,6 +485,25 @@
             return _content.GetByteCount();
         }
 
+        public MutableString/*!*/ TrimExcess() {
+            _content.TrimExcess();
+            return this;
+        }
+
+        public int Capacity { 
+            get {
+                return _content.GetCapacity();
+            } set {
+                _content.SetCapacity(value);
+            }
+        }
+
+        public void EnsureCapacity(int minCapacity) {
+            if (_content.GetCapacity() < minCapacity) {
+                _content.SetCapacity(minCapacity);
+            }
+        }
+
         #endregion
 
         #region StartsWith, EndsWith (read-only)
@@ -505,7 +533,7 @@
 
         // returns -1 if the string is empty
         public int GetLastChar() {
-            return (_content.IsEmpty) ? -1 : _content.GetChar(_content.Length - 1); 
+            return (_content.IsEmpty) ? -1 : _content.GetChar(_content.GetCharCount() - 1); 
         }
 
         // returns -1 if the string is empty
@@ -517,7 +545,7 @@
         /// Returns a new mutable string containing a substring of the current one.
         /// </summary>
         public MutableString/*!*/ GetSlice(int start) {
-            return GetSlice(start, _content.Length - start);
+            return GetSlice(start, _content.Count - start);
         }
 
         public MutableString/*!*/ GetSlice(int start, int count) {
@@ -618,7 +646,7 @@
         }
 
         public int IndexOf(MutableString/*!*/ value, int start) {
-            return IndexOf(value, start, _content.Length - start);
+            return IndexOf(value, start, _content.Count - start);
         }
 
         public int IndexOf(MutableString/*!*/ value, int start, int count) {
@@ -693,7 +721,7 @@
         }
 
         public int LastIndexOf(MutableString/*!*/ value) {
-            int length = _content.Length;
+            int length = _content.Count;
             return LastIndexOf(value, length - 1, length);
         }
 
@@ -778,10 +806,22 @@
             return this;
         }
 
+        /// <summary>
+        /// Reads "count" bytes from "source" stream and appends them to this string.
+        /// </summary>
+        public MutableString/*!*/ Append(Stream/*!*/ stream, int count) {
+            ContractUtils.RequiresNotNull(stream, "stream");
+            ContractUtils.Requires(count >= 0, "count");
+
+            Mutate();
+            _content.Append(stream, count);
+            return this;
+        }
+
         public MutableString/*!*/ Append(MutableString/*!*/ value) {
             if (value != null) {
                 Mutate();
-                value._content.AppendTo(_content, 0, value._content.Length);
+                value._content.AppendTo(_content, 0, value._content.Count);
             }
             return this;
         }
@@ -880,7 +920,7 @@
             //RequiresArrayInsertIndex(index);
             if (value != null) {
                 Mutate();
-                value._content.InsertTo(_content, index, 0, value._content.Length);
+                value._content.InsertTo(_content, index, 0, value._content.Count);
             }
             return this;
         }
@@ -904,7 +944,7 @@
 
             // TODO:
             if (IsBinary) {
-                int length = _content.Length;
+                int length = _content.Count;
                 for (int i = 0; i < length / 2; i++) {
                     byte a = GetByte(i);
                     byte b = GetByte(length - i - 1);
@@ -912,7 +952,7 @@
                     SetByte(length - i - 1, a);
                 }
             } else {
-                int length = _content.Length;
+                int length = _content.Count;
                 for (int i = 0; i < length / 2; i++) {
                     char a = GetChar(i);
                     char b = GetChar(length - i - 1);
@@ -936,6 +976,13 @@
             return Remove(start, count).Insert(start, value);
         }
 
+        public MutableString/*!*/ Remove(int start) {
+            //RequiresArrayRange(start, count);
+            Mutate();
+            _content.Remove(start, _content.Count - start);
+            return this;
+        }
+
         public MutableString/*!*/ Remove(int start, int count) {
             //RequiresArrayRange(start, count);
             Mutate();
@@ -955,7 +1002,6 @@
             return this;
         }
 
-
         #endregion
 
         #region Quoted Representation
@@ -1231,6 +1277,14 @@
 
         #endregion
 
+        #region Internal Helpers
+
+        internal byte[]/*!*/ GetByteArray() {
+            return _content.GetByteArray();
+        }
+
+        #endregion
+
 #if OBSOLETE
         #region Utils
 
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.StringBuilderContent.cs;C785561
File: MutableString.StringBuilderContent.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.StringBuilderContent.cs;C785561  (server)    5/5/2009 7:05 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.StringBuilderContent.cs;Files3
@@ -19,6 +19,7 @@
 using System.Text;
 using IronRuby.Runtime;
 using System.Diagnostics;
+using System.IO;
 
 namespace IronRuby.Builtins {
     public partial class MutableString {
@@ -91,7 +92,7 @@
                 get { return _count; }
             }
 
-            public override int Length {
+            public override int Count {
                 get { return _count; }
             }
 
@@ -107,10 +108,33 @@
                 return (IsBinaryEncoded) ? _count : (_count == 0) ? 0 : SwitchToBinary().GetByteCount();
             }
 
+            public override void SwitchToBinaryContent() {
+                SwitchToBinary();
+            }
+
+            public override void SwitchToStringContent() {
+                // nop
+            }
+
             public override Content/*!*/ Clone() {
                 return new CharArrayContent(Utils.GetSlice(_data, 0, _count), _owner);
             }
 
+            public override void TrimExcess() {
+                Utils.TrimExcess(ref _data, _count);
+            }
+
+            public override int GetCapacity() {
+                return _count;
+            }
+
+            public override void SetCapacity(int capacity) {
+                if (capacity < _count) {
+                    throw new InvalidOperationException();
+                }
+                Array.Resize(ref _data, capacity);
+            }
+
             #endregion
 
             #region Conversions (read-only)
@@ -132,6 +156,10 @@
                 return DataToBytes(0);
             }
 
+            internal override byte[]/*!*/ GetByteArray() {
+                return SwitchToBinary().GetByteArray();
+            }
+
             public override GenericRegex/*!*/ ToRegularExpression(RubyRegexOptions options) {
                 return new StringRegex(ToString(), options);
             }
@@ -269,6 +297,11 @@
                 return SwitchToBinary(count).Append(bytes, start, count);
             }
 
+            public override Content/*!*/ Append(Stream/*!*/ stream, int count) {
+                SwitchToBinary(count).Append(stream, count);
+                return this;
+            }
+
             public override Content/*!*/ AppendFormat(IFormatProvider provider, string/*!*/ format, object[]/*!*/ args) {
                 var formatted = String.Format(provider, format, args);
                 Append(formatted, 0, formatted.Length);
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.StringContent.cs;C785561
File: MutableString.StringContent.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.StringContent.cs;C785561  (server)    5/5/2009 7:06 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.StringContent.cs;Files3
@@ -18,6 +18,7 @@
 using System.Text;
 using Microsoft.Scripting.Utils;
 using IronRuby.Runtime;
+using System.IO;
 
 namespace IronRuby.Builtins {
     public partial class MutableString {
@@ -31,15 +32,25 @@
                 _data = data;
             }
 
-            protected virtual BinaryContent/*!*/ SwitchToBinary() {
+            internal BinaryContent/*!*/ SwitchToBinary() {
                 var bytes = DataToBytes();
                 return WrapContent(bytes, bytes.Length);
             }
 
+            internal BinaryContent/*!*/ SwitchToBinary(int additionalCapacity) {
+                // TODO:
+                return SwitchToBinary();
+            }
+
             private CharArrayContent/*!*/ SwitchToMutable() {
                 return WrapContent(_data.ToCharArray(), _data.Length);
             }
 
+            private CharArrayContent/*!*/ SwitchToMutable(int additionalCapacity) {
+                // TODO:
+                return SwitchToMutable();
+            }
+
             protected byte[]/*!*/ DataToBytes() {
                 return _data.Length > 0 ? _owner._encoding.StrictEncoding.GetBytes(_data) : Utils.EmptyBytes;
             }
@@ -58,7 +69,7 @@
                 get { return false; }
             }
 
-            public override int Length {
+            public override int Count {
                 get { return _data.Length; }
             }
 
@@ -78,6 +89,21 @@
                 return new StringContent(_data, _owner);
             }
 
+            public override void TrimExcess() {
+                // nop
+            }
+
+            public override int GetCapacity() {
+                return _data.Length;
+            }
+
+            public override void SetCapacity(int capacity) {
+                if (capacity < _data.Length) {
+                    throw new InvalidOperationException();
+                }
+                SwitchToMutable(capacity - _data.Length);
+            }
+
             #endregion
 
             #region Conversions (read-only)
@@ -100,6 +126,18 @@
                 return DataToBytes();
             }
 
+            internal override byte[]/*!*/ GetByteArray() {
+                return SwitchToBinary().GetByteArray();
+            }
+
+            public override void SwitchToBinaryContent() {
+                SwitchToBinary();
+            }
+
+            public override void SwitchToStringContent() {
+                // nop
+            }
+
             public override GenericRegex/*!*/ ToRegularExpression(RubyRegexOptions options) {
                 return new StringRegex(_data, options);
             }
@@ -203,25 +241,30 @@
             #region Append
 
             public override Content/*!*/ Append(char c, int repeatCount) {
-                return SwitchToMutable().Append(c, repeatCount);
+                return SwitchToMutable(repeatCount).Append(c, repeatCount);
             }
 
             public override Content/*!*/ Append(byte b, int repeatCount) {
-                return SwitchToBinary().Append(b, repeatCount);
+                return SwitchToBinary(repeatCount).Append(b, repeatCount);
             }
 
             public override Content/*!*/ Append(string/*!*/ str, int start, int count) {
-                return SwitchToMutable().Append(str, start, count);
+                return SwitchToMutable(count).Append(str, start, count);
             }
 
             public override Content/*!*/ Append(char[]/*!*/ chars, int start, int count) {
-                return SwitchToMutable().Append(chars, start, count);
+                return SwitchToMutable(count).Append(chars, start, count);
             }
 
             public override Content/*!*/ Append(byte[]/*!*/ bytes, int start, int count) {
-                return SwitchToBinary().Append(bytes, start, count);
+                return SwitchToBinary(count).Append(bytes, start, count);
             }
 
+            public override Content/*!*/ Append(Stream/*!*/ stream, int count) {
+                SwitchToBinary(count).Append(stream, count);
+                return this;
+            }
+
             public override Content/*!*/ AppendFormat(IFormatProvider provider, string/*!*/ format, object[]/*!*/ args) {
                 return SwitchToMutable().AppendFormat(provider, format, args);
             }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyIO.cs;C840659
File: RubyIO.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyIO.cs;C840659  (server)    5/5/2009 6:33 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyIO.cs;Files3
@@ -20,6 +20,7 @@
 using Microsoft.Scripting.Utils;
 using IronRuby.Runtime;
 using System.Text;
+using System.Diagnostics;
 
 namespace IronRuby.Builtins {
     public enum IOMode {
@@ -54,6 +55,9 @@
         public const int SEEK_CUR = 1;
         public const int SEEK_END = 2;
 
+        private const byte CR = (byte)'\r';
+        private const byte LF = (byte)'\n';
+
         #region Construction
 
         public RubyIO(RubyContext/*!*/ context) {
@@ -392,15 +396,15 @@
                 int i = index;
                 while (i < count) {
                     int j = i;
-                    while (j < buffer.Length && buffer[j] != (byte)'\n') {
+                    while (j < buffer.Length && buffer[j] != LF) {
                         j++;
                     }
                     _stream.Write(buffer, i, j - i);
                     bytesWritten += j - i;
 
                     if (j < buffer.Length) {
-                        _stream.WriteByte((byte)'\r');
-                        _stream.WriteByte((byte)'\n');
+                        _stream.WriteByte(CR);
+                        _stream.WriteByte(LF);
                         bytesWritten += 2;
                     }
 
@@ -435,19 +439,90 @@
             return _stream.ReadByte();
         }
 
-        public int ReadBytes(byte[] buffer, int offset, int count) {
+        public int ReadBytes(byte[]/*!*/ buffer, int offset, int count) {
             return _stream.Read(buffer, offset, count);
         }
 
+        public int AppendBytes(MutableString/*!*/ buffer, int count) {
+            ContractUtils.RequiresNotNull(buffer, "buffer");
+            ContractUtils.Requires(count >= 0, "count");
+
+            if (count == 0) {
+                return 0;
+            }
+
+            buffer.SwitchToBinary();
+            int initialBufferSize = buffer.GetByteCount();
+            if (_preserveEndOfLines) {
+                AppendRawBytes(buffer, count);
+            } else {
+                // allocate 3 more bytes at the end for a backstop and possible LF:
+                buffer.EnsureCapacity(initialBufferSize + count + 3);
+                byte[] bytes = buffer.GetByteArray();
+
+                int done = initialBufferSize;
+                bool eof;
+                do {
+                    AppendRawBytes(buffer, count);
+                    int end = buffer.GetByteCount();
+                    int bytesRead = end - done;
+                    if (bytesRead == 0) {
+                        break;
+                    }
+                    eof = bytesRead < count;
+
+                    if (bytes[end - 1] == CR && PeekByte() == LF) {
+                        ReadByte();
+                        bytes[end++] = LF;
+                    }
+
+                    // insert backstop:
+                    bytes[end] = CR;
+                    bytes[end + 1] = LF;
+
+                    int last = IndexOfCrLf(bytes, done);
+                    count -= last - done;
+                    done = last;
+                    while (last < end) {
+                        int next = IndexOfCrLf(bytes, last + 2);
+                        int chunk = next - last - 1;
+                        Buffer.BlockCopy(bytes, last + 1, bytes, done, chunk);
+                        done += chunk;
+                        count -= chunk;
+                        last = next;
+                    }
+                    buffer.Remove(done);
+                } while (count > 0 && !eof);
+            }
+
+            return buffer.GetByteCount() - initialBufferSize;
+        }
+
+        private void AppendRawBytes(MutableString/*!*/ buffer, int count) {
+            Debug.Assert(count > 0);
+
+            if (_peekAhead != -1) {
+                buffer.Append((byte)_peekAhead);
+                _peekAhead = -1;
+                count--;
+            }
+            buffer.Append(_stream, count);
+        }
+
+        private static int IndexOfCrLf(byte[]/*!*/ array, int i) {
+            while (true) {
+                if (array[i++] == CR && array[i] == LF) {
+                    return i - 1;
+                }
+            }
+        }
+
         public int ReadByteNormalizeEoln() {
             // TODO: encoding
-            if (IsEndOfStream()) {
-                return -1;
-            }
             int first = ReadByte();
             if (first == '\r' && !_preserveEndOfLines) {
                 int second = PeekByte();
-                if (second != -1 && second == '\n') {
+                if (second == '\n') {
                     return ReadByte();
                 }
             }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs;C840659
File: Utils.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs;C840659  (server)    5/5/2009 7:05 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs;Files3
@@ -106,6 +106,12 @@
             }
         }
 
+        internal static void TrimExcess<T>(ref T[] data, int count) {
+            if ((long)count * 10 < (long)data.Length * 9) {
+                Array.Resize(ref data, count);
+            }
+        }
+
         internal static void ResizeForInsertion<T>(ref T[]/*!*/ array, int itemCount, int index, int count) {
             int minLength = itemCount + count;
             T[] a;
===================================================================
