edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C445606
File: Initializers.Generated.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C445606  (server)    5/20/2008 10:45 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;RubyArrayPack
@@ -51,7 +51,7 @@
             ExtendModule(typeof(System.Collections.Generic.IDictionary<System.Object, System.Object>), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Collections__Generic__IDictionary_Instance), null, new Ruby.Builtins.RubyModule[] {def16, });
             ExtendModule(typeof(System.Collections.IEnumerable), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Collections__IEnumerable_Instance), null, new Ruby.Builtins.RubyModule[] {def16, });
             ExtendModule(typeof(System.Collections.IList), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Collections__IList_Instance), null, new Ruby.Builtins.RubyModule[] {def16, });
-            ExtendModule(typeof(System.IComparable), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__IComparable_Instance), null, new Ruby.Builtins.RubyModule[] {def25, });
+            Ruby.Builtins.RubyModule def29 = ExtendModule(typeof(System.IComparable), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__IComparable_Instance), null, new Ruby.Builtins.RubyModule[] {def25, });
             DefineGlobalClass("Time", typeof(System.DateTime), classRef0, new System.Action<Ruby.Builtins.RubyModule>(LoadTime_Instance), new System.Action<Ruby.Builtins.RubyModule>(LoadTime_Class), new Ruby.Builtins.RubyModule[] {def25, }, new System.Delegate[] {
                 new Microsoft.Scripting.Utils.Function<System.DateTime>(Ruby.Builtins.TimeOps.Create),
             });
@@ -65,7 +65,7 @@
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Runtime.BlockParam, System.Object, System.Object>(Ruby.Builtins.ArrayOps.CreateArray),
             });
             DefineGlobalClass("Binding", typeof(Ruby.Builtins.Binding), Context.ObjectClass, null, null, Ruby.Builtins.RubyModule.EmptyArray, null);
-            DefineGlobalClass("ClrString", typeof(System.String), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadClrString_Instance), null, Ruby.Builtins.RubyModule.EmptyArray, null);
+            DefineGlobalClass("ClrString", typeof(System.String), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadClrString_Instance), null, new Ruby.Builtins.RubyModule[] {def29, }, null);
             DefineGlobalClass("Dir", typeof(Ruby.Builtins.RubyDir), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadDir_Instance), new System.Action<Ruby.Builtins.RubyModule>(LoadDir_Class), new Ruby.Builtins.RubyModule[] {def16, }, null);
             Ruby.Builtins.RubyClass def26 = Context.ExceptionClass = DefineGlobalClass("Exception", typeof(System.Exception), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadException_Instance), new System.Action<Ruby.Builtins.RubyModule>(LoadException_Class), Ruby.Builtins.RubyModule.EmptyArray, new System.Delegate[] {
                 new Microsoft.Scripting.Utils.Function<Ruby.Builtins.MutableString, System.Exception>(Ruby.Builtins.ExceptionOps.Factory),
@@ -329,6 +329,11 @@
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyArray, Ruby.Runtime.BlockParam, System.Object, System.Object>(Ruby.Builtins.ArrayOps.Initialize),
             });
             
+            module.DefineLibraryMethod("pack", 0x29, new System.Delegate[] {
+                new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyArray, Ruby.Builtins.MutableString, Ruby.Builtins.MutableString>(Ruby.Builtins.ArrayOps.Pack),
+                new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyArray, System.Object, Ruby.Builtins.MutableString>(Ruby.Builtins.ArrayOps.Pack),
+            });
+            
             module.DefineLibraryMethod("reverse!", 0x29, new System.Delegate[] {
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyArray, Ruby.Builtins.RubyArray>(Ruby.Builtins.ArrayOps.InPlaceReverse),
             });
@@ -3906,6 +3911,11 @@
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, System.Object, System.Object, Ruby.Builtins.MutableString>(Ruby.Builtins.MutableStringOps.TrInPlace),
             });
             
+            module.DefineLibraryMethod("unpack", 0x29, new System.Delegate[] {
+                new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, Ruby.Builtins.MutableString, Ruby.Builtins.RubyArray>(Ruby.Builtins.MutableStringOps.Unpack),
+                new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, System.Object, Ruby.Builtins.RubyArray>(Ruby.Builtins.MutableStringOps.Unpack),
+            });
+            
             module.DefineLibraryMethod("upcase", 0x29, new System.Delegate[] {
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, Ruby.Builtins.MutableString>(Ruby.Builtins.MutableStringOps.UpCase),
             });
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs;C443395
File: ArrayOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs;C443395  (server)    5/21/2008 9:50 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs;RubyArrayPack
@@ -17,6 +17,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Text;
@@ -189,6 +190,185 @@
             return self;
         }
 
+        #region class FormatDirective is used by Array.pack and String.unpack
+
+        internal struct FormatDirective {
+            internal readonly char Directive;
+            internal readonly int? Count;
+            private static readonly Dictionary<char, char> _native;
+
+            static FormatDirective() {
+                bool is64bit = (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8);
+                _native = new Dictionary<char, char>(6);
+                _native['s'] = 's';
+                _native['S'] = 'S';
+                _native['i'] = 'i';
+                _native['I'] = 'I';
+                _native['l'] = is64bit ? 'i' : 'q';
+                _native['L'] = is64bit ? 'I' : 'Q';
+            }
+
+            internal FormatDirective(char directive, int? count) {
+                Directive = directive;
+                Count = count;
+            }
+            internal static IEnumerable<FormatDirective>/*!*/ Enumerate(string format) {
+                for (int i = 0; i < format.Length; i++) {
+                    char c = format[i];
+                    if (!Char.IsLetter(c) && c != '@') {
+                        continue;
+                    }
+                    i++;
+                    int? count = 1;
+                    char c2 = (i < format.Length) ? format[i] : (char)0;
+                    if (c2 == '_') {
+                        char tmp;
+                        if (!_native.TryGetValue(c, out tmp)) {
+                            throw RubyExceptions.CreateArgumentError("'_' allowed only after types sSiIlL");
+                        }
+                        c = tmp;
+                        i++;
+                        c2 = (i < format.Length) ? format[i] : (char)0;
+                    }
+                    if (Char.IsDigit(c2)) {
+                        int pos1 = i;
+                        i++;
+                        while (i < format.Length && Char.IsDigit(format[i])) {
+                            i++;
+                        }
+                        count = Int32.Parse(format.Substring(pos1, (i - pos1)));
+                        i--;
+                    } else if (c2 == '*') {
+                        count = null;
+                    } else {
+                        i--;
+                    }
+                    
+                    yield return new FormatDirective(c, count);
+                }
+            }
+        }
+
+        #endregion
+
+        [RubyMethod("pack")]
+        public static MutableString/*!*/ Pack(CodeContext/*!*/ context, RubyArray/*!*/ self, [NotNull]MutableString/*!*/ format) {
+            using (MutableStringStream stream = new MutableStringStream()) {
+                BinaryWriter writer = new BinaryWriter(stream);
+                int i = 0;
+                foreach (FormatDirective directive in FormatDirective.Enumerate(format.ToString())) {
+                    int remaining = (self.Count - i);
+                    int count = directive.Count.HasValue ? directive.Count.Value : remaining;
+                    if (count > remaining) {
+                        count = remaining;
+                    }
+                    switch (directive.Directive) {
+                        case '@':
+                            count = 0;
+                            stream.Position = directive.Count.HasValue ? directive.Count.Value : 1;
+                            break;
+                        case 'A':
+                        case 'a':
+                        case 'Z':
+                            count = 1;
+                            char[] cstr = Protocols.CastToString(context, self[i]).ToString().ToCharArray();
+                            int len1 = directive.Count.HasValue ? directive.Count.Value : cstr.Length;
+                            int len2 = (len1 > cstr.Length) ? cstr.Length : len1;
+                            writer.Write(cstr, 0, len2);
+                            if (len1 > len2) {
+                                byte fill = (directive.Directive == 'A') ? (byte)' ' : (byte)0;
+                                for (int j = 0; j < (len1 - len2); j++) {
+                                    writer.Write(fill);
+                                }
+                            }
+                            if (directive.Directive == 'Z' && !directive.Count.HasValue) {
+                                writer.Write((byte)0);
+                            }
+                            break;
+                        case 'c':
+                            for (int j = 0; j < count; j++) {
+                                writer.Write((sbyte)Protocols.CastToFixnum(context, self[i + j]));
+                            }
+                            break;
+                        case 'C':
+                            for (int j = 0; j < count; j++) {
+                                writer.Write((byte)Protocols.CastToFixnum(context, self[i + j]));
+                            }
+                            break;
+                        case 'i':
+                            for (int j = 0; j < count; j++) {
+                                writer.Write((int)Protocols.CastToFixnum(context, self[i + j]));
+                            }
+                            break;
+                        case 'I':
+                            for (int j = 0; j < count; j++) {
+                                writer.Write((uint)Protocols.CastToFixnum(context, self[i + j]));
+                            }
+                            break;
+                        case 'm':
+                            count = 1;
+                            MutableString str = Protocols.CastToString(context, self[i]);
+                            char[] base64 = Convert.ToBase64String(str.ToByteArray()).ToCharArray();
+                            for (int j = 0; j < base64.Length; j += 60) {
+                                int len = base64.Length - j;
+                                if (len > 60) {
+                                    len = 60;
+                                }
+                                writer.Write(base64, j, len);
+                                writer.Write('\n');
+                            }
+                            break;
+                        case 's':
+                            for (int j = 0; j < count; j++) {
+                                writer.Write((short)Protocols.CastToFixnum(context, self[i + j]));
+                            }
+                            break;
+                        case 'S':
+                            for (int j = 0; j < count; j++) {
+                                writer.Write((ushort)Protocols.CastToFixnum(context, self[i + j]));
+                            }
+                            break;
+                        case 'U':
+                            char[] buffer = new char[count];
+                            for (int j = 0; j < count; j++) {
+                                buffer[j] = (char)Protocols.CastToFixnum(context, self[i + j]);
+                            }
+                            writer.Write(Encoding.UTF8.GetBytes(buffer));
+                            break;
+                        case 'X':
+                            count = 0;
+                            int len3 = directive.Count.HasValue ? directive.Count.Value : 0;
+                            if (len3 > stream.Position) {
+                                throw RubyExceptions.CreateArgumentError("X outside of string");
+                            }
+                            stream.Position -= len3;
+                            break;
+                        case 'x':
+                            count = 0;
+                            int len4 = directive.Count.HasValue ? directive.Count.Value : 0;
+                            for (int j = 0; j < len4; j++) {
+                                writer.Write((byte)0);
+                            }
+                            break;
+                        default:
+                            throw RubyExceptions.CreateArgumentError(
+                                String.Format("Unknown format directive '{0}'", directive.Directive));
+                    }
+                    i += count;
+                    if (i >= self.Count) {
+                        break;
+                    }
+                }
+                stream.SetLength(stream.Position);
+                return stream.String;
+            }
+        }
+
+        [RubyMethod("pack")]
+        public static MutableString/*!*/ Pack(CodeContext/*!*/ context, RubyArray/*!*/ self, object format) {
+            return Pack(context, self, Protocols.CastToString(context, format));
+        }
+
         //----------------------------------------------------- Array#reverse_each
         //     array.reverse_each {|item| block }
         //------------------------------------------------------------------------
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C444052
File: MutableStringOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C444052  (server)    5/21/2008 9:52 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;RubyArrayPack
@@ -3116,5 +3116,169 @@
             Kernel.RequiresNotFrozen(context, self);
             return self.Reverse();            
         }
+
+        private static bool HasCapacity(Stream/*!*/ s, int? n) {
+            if (s.Length < (s.Position + n)) {
+                s.Position = s.Length;
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        private static int CalculateCounts(Stream/*!*/ s, int? count, int size, out int leftover) {
+            int remaining = (int)(s.Length - s.Position);
+            int maxCount = remaining / size;
+            if (!count.HasValue) {
+                leftover = 0;
+                return maxCount;
+            } else if (count.Value <= maxCount) {
+                leftover = 0;
+                return count.Value;
+            } else {
+                leftover = count.Value - maxCount;
+                return maxCount;
+            }
+        }
+
+        [RubyMethod("unpack")]
+        public static RubyArray/*!*/ Unpack(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]MutableString/*!*/ format) {
+            RubyArray result = new RubyArray(1 + self.Length / 2);
+            using (MutableStringStream stream = new MutableStringStream(self)) {
+                BinaryReader reader = new BinaryReader(stream);
+                foreach (ArrayOps.FormatDirective directive in ArrayOps.FormatDirective.Enumerate(format.ToString())) {
+                    int count, maxCount;
+                    byte[] buffer;
+                    MutableString str;
+                    int nilCount = 0;
+                    switch (directive.Directive) {
+                        case '@':
+                            stream.Position = directive.Count.HasValue ? directive.Count.Value : stream.Position;
+                            break;
+                        case 'A':
+                        case 'a':
+                            maxCount = (int)(stream.Length - stream.Position);
+                            count = directive.Count.HasValue ? directive.Count.Value : maxCount;
+                            if (count > maxCount) {
+                                count = maxCount;
+                            }
+                            buffer = reader.ReadBytes(count);
+                            str = MutableString.CreateBinary(buffer);
+                            if (directive.Directive == 'A') {
+                                // TODO: efficiency?
+                                for (int pos = count - 1; pos >= 0; pos--) {
+                                    if (buffer[pos] != 0 && buffer[pos] != 0x20) {
+                                        break;
+                                    }
+                                    str.Remove(pos, 1);
+                                }
+                            }
+                            result.Add(str);
+                            break;
+                        case 'Z':
+                            maxCount = (int)(stream.Length - stream.Position);
+                            count = directive.Count.HasValue ? directive.Count.Value : maxCount;
+                            if (count > maxCount) {
+                                count = maxCount;
+                            }
+                            buffer = reader.ReadBytes(count);
+                            str = MutableString.CreateBinary(buffer);
+                            for (int pos = 0; pos < count; pos++) {
+                                if (buffer[pos] == 0) {
+                                    str.Remove(pos, count - pos);
+                                    break;
+                                }
+                            }
+                            result.Add(str);
+                            break;
+                        case 'c':
+                            count = CalculateCounts(stream, directive.Count, sizeof(sbyte), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)reader.ReadSByte());
+                            }
+                            break;
+                        case 'C':
+                            count = CalculateCounts(stream, directive.Count, sizeof(byte), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)reader.ReadByte());
+                            }
+                            break;
+                        case 'i':
+                            count = CalculateCounts(stream, directive.Count, sizeof(int), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)reader.ReadInt32());
+                            }
+                            break;
+                        case 'I':
+                            count = CalculateCounts(stream, directive.Count, sizeof(uint), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)reader.ReadUInt32());
+                            }
+                            break;
+                        case 'm':
+                            // TODO: Recognize "==" as end of base 64 encoding
+                            int len = (int)(stream.Length - stream.Position);
+                            char[] base64 = reader.ReadChars(len);
+                            byte[] data = Convert.FromBase64CharArray(base64, 0, len);
+                            result.Add(MutableString.CreateBinary(data));
+                            break;
+                        case 's':
+                            count = CalculateCounts(stream, directive.Count, sizeof(short), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)reader.ReadInt16());
+                            }
+                            break;
+                        case 'S':
+                            count = CalculateCounts(stream, directive.Count, sizeof(ushort), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)reader.ReadUInt16());
+                            }
+                            break;
+                        case 'U':
+                            maxCount = (int)(stream.Length - stream.Position);
+                            count = directive.Count.HasValue ? directive.Count.Value : maxCount;
+                            int readCount = directive.Count.HasValue ? Encoding.UTF8.GetMaxByteCount(count) : count;
+                            if (readCount > maxCount) {
+                                readCount = maxCount;
+                            }
+                            long startPosition = stream.Position;
+                            char[] charData = Encoding.UTF8.GetChars(reader.ReadBytes(readCount));
+                            if (charData.Length > count) {
+                                int actualCount = Encoding.UTF8.GetByteCount(charData, 0, count);
+                                stream.Position = startPosition + actualCount;
+                            } else if (charData.Length < count) {
+                                count = charData.Length;
+                            }
+                            for (int j = 0; j < count; j++) {
+                                result.Add((int)charData[j]);
+                            }
+                            break;
+                        case 'X':
+                            int len3 = directive.Count.HasValue ? directive.Count.Value : 0;
+                            if (len3 > stream.Position) {
+                                throw RubyExceptions.CreateArgumentError("X outside of string");
+                            }
+                            stream.Position -= len3;
+                            break;
+                        case 'x':
+                            int len4 = directive.Count.HasValue ? directive.Count.Value : 0;
+                            stream.Position += len4;
+                            break;
+                        default:
+                            throw RubyExceptions.CreateArgumentError(
+                                String.Format("Unknown format directive '{0}'", directive.Directive));
+                    }
+                    for (int i = 0; i < nilCount; i++) {
+                        result.Add(null);
+                    }
+                }
+            }
+            return result;
+        }
+
+        [RubyMethod("unpack")]
+        public static RubyArray/*!*/ Unpack(CodeContext/*!*/ context, MutableString/*!*/ self, object format) {
+            return Unpack(context, self, Protocols.CastToString(context, format));
+        }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/StringIO/StringIO.cs;C444795
File: StringIO.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/StringIO/StringIO.cs;C444795  (server)    5/21/2008 10:03 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/StringIO/StringIO.cs;RubyArrayPack
@@ -27,124 +27,6 @@
     [RubyClass("StringIO")]
     public class StringIO : RubyIO {
 
-        #region MutableStringStream
-
-        protected class MutableStringStream : Stream {
-            private MutableString/*!*/ _string;
-            private int _position;
-
-            internal MutableStringStream(MutableString/*!*/ basis) {
-                _string = basis;
-                _position = 0;
-            }
-
-            internal MutableString String {
-                get { return _string; }
-                set {
-                    _string = value;
-                    _position = 0;
-                }
-            }
-
-            public override bool CanRead {
-                get { return true; }
-            }
-
-            public override bool CanSeek {
-                get { return true; }
-            }
-
-            public override bool CanWrite {
-                get { return true; }
-            }
-
-            public override void Flush() {
-            }
-
-            public override long Length {
-                get { return _string.ConvertToBytes().Length; }
-            }
-
-            public override long Position {
-                get {
-                    return _position;
-                }
-                set {
-                    if (value < 0) {
-                        throw RubyExceptions.CreateIOError("Invalid argument");
-                    }
-                    _position = (int)value;
-                }
-            }
-
-            public override int Read(byte[] buffer, int offset, int count) {
-                _string.ConvertToBytes();
-                int maxReadLen = _string.Length - _position;
-                if (count > maxReadLen) {
-                    count = maxReadLen;
-                }
-                for (int i = 0; i < count; i++) {
-                    buffer[offset + i] = _string.GetByte(_position++);
-                }
-                return count;
-            }
-
-            public override int ReadByte() {
-                if (_position >= _string.Length) {
-                    return -1;
-                }
-                return _string.GetByte(_position++);
-            }
-
-            public override long Seek(long offset, SeekOrigin origin) {
-                _string.ConvertToBytes();
-
-                int position = _position;
-                switch (origin) {
-                    case SeekOrigin.Begin:
-                        position = (int)offset;
-                        break;
-                    case SeekOrigin.End:
-                        position = _string.Length + (int)offset;
-                        break;
-                    case SeekOrigin.Current:
-                        position += (int)offset;
-                        break;
-                }
-                Position = position;
-                return Position;
-            }
-
-            public override void SetLength(long value) {
-                _string.ConvertToBytes();
-                if (_string.Length < value) {
-                    _string.Append(new byte[(value - _string.Length)]);
-                } else if (_string.Length > value) {
-                    _string.Remove((int)value, _string.Length - (int)value);
-                }
-            }
-
-            public override void Write(byte[] buffer, int offset, int count) {
-                _string.ConvertToBytes();
-                if ((_position + count) > _string.Length) {
-                    SetLength(_position + count);
-                }
-                for (int i = offset; i < offset + count; i++) {
-                    _string.SetByte(_position++, buffer[i]);
-                }
-            }
-
-            public override void WriteByte(byte value) {
-                _string.ConvertToBytes();
-                if ((_position + 1) > _string.Length) {
-                    SetLength(_position + 1);
-                }
-                _string.SetByte(_position++, value);
-            }
-        }
-
-        #endregion
-
         private static DynamicSite<BlockParam, object, object> _OpenSite =
             CallSiteFactory.CreateSimpleCallSite<BlockParam, object, object>(RubyContext.RubyBinder);
 
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C444052
File: Ruby.csproj
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C444052  (server)    5/21/2008 10:02 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;RubyArrayPack
@@ -94,6 +94,7 @@
     <Compile Include="Builtins\IO.cs" />
     <Compile Include="Builtins\MatchData.cs" />
     <Compile Include="Builtins\MutableString.Content.cs" />
+    <Compile Include="Builtins\MutableStringStream.cs" />
     <Compile Include="Builtins\RubyMethod.cs" />
     <Compile Include="Builtins\RubyRegexOptions.cs" />
     <Compile Include="Compiler\Ast\Expressions\ConditionalJumpExpression.cs" />
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj.vspscc;C390406
add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableStringStream.cs
File: MutableStringStream.cs
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableStringStream.cs;RubyArrayPack
@@ -1,0 +1,137 @@
+?/* ****************************************************************************
+ *
+ * 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.IO;
+
+using Ruby.Runtime;
+
+namespace Ruby.Builtins {
+    public class MutableStringStream : Stream {
+        private MutableString/*!*/ _string;
+        private int _position;
+
+        public MutableStringStream() : this(MutableString.CreateEmpty()) {
+        }
+
+        public MutableStringStream(MutableString/*!*/ basis) {
+            _string = basis;
+            _position = 0;
+        }
+
+        public MutableString String {
+            get { return _string; }
+            set {
+                _string = value;
+                _position = 0;
+            }
+        }
+
+        public override bool CanRead {
+            get { return true; }
+        }
+
+        public override bool CanSeek {
+            get { return true; }
+        }
+
+        public override bool CanWrite {
+            get { return true; }
+        }
+
+        public override void Flush() {
+        }
+
+        public override long Length {
+            get { return _string.ConvertToBytes().Length; }
+        }
+
+        public override long Position {
+            get {
+                return _position;
+            }
+            set {
+                if (value < 0) {
+                    throw RubyExceptions.CreateIOError("Invalid argument");
+                }
+                _position = (int)value;
+            }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count) {
+            _string.ConvertToBytes();
+            int maxReadLen = _string.Length - _position;
+            if (count > maxReadLen) {
+                count = maxReadLen;
+            }
+            for (int i = 0; i < count; i++) {
+                buffer[offset + i] = _string.GetByte(_position++);
+            }
+            return count;
+        }
+
+        public override int ReadByte() {
+            if (_position >= _string.Length) {
+                return -1;
+            }
+            return _string.GetByte(_position++);
+        }
+
+        public override long Seek(long offset, SeekOrigin origin) {
+            _string.ConvertToBytes();
+
+            int position = _position;
+            switch (origin) {
+                case SeekOrigin.Begin:
+                    position = (int)offset;
+                    break;
+                case SeekOrigin.End:
+                    position = _string.Length + (int)offset;
+                    break;
+                case SeekOrigin.Current:
+                    position += (int)offset;
+                    break;
+            }
+            Position = position;
+            return Position;
+        }
+
+        public override void SetLength(long value) {
+            _string.ConvertToBytes();
+            if (_string.Length < value) {
+                _string.Append(new byte[(value - _string.Length)]);
+            } else if (_string.Length > value) {
+                _string.Remove((int)value, _string.Length - (int)value);
+            }
+        }
+
+        public override void Write(byte[] buffer, int offset, int count) {
+            _string.ConvertToBytes();
+            if ((_position + count) > _string.Length) {
+                SetLength(_position + count);
+            }
+            for (int i = offset; i < offset + count; i++) {
+                _string.SetByte(_position++, buffer[i]);
+            }
+        }
+
+        public override void WriteByte(byte value) {
+            _string.ConvertToBytes();
+            if ((_position + 1) > _string.Length) {
+                SetLength(_position + 1);
+            }
+            _string.SetByte(_position++, value);
+        }
+    }
+}
===================================================================
