[corlib] Fix localized resource loading bug (#14987)
[mono.git] / mcs / class / corlib / System.Resources / ResourceWriter.cs
index 50afc5a626c809b2b27f48f532a28e3cce4856ef..024cab9d5b5a4cb7abf8848d50a294d2e0ffdcbf 100644 (file)
@@ -4,6 +4,7 @@
 // Authors:
 //     Duncan Mak <duncan@ximian.com>
 //     Dick Porter <dick@ximian.com>
+//     Gert Driesen <drieseng@users.sourceforge.net>
 //
 // (C) 2001, 2002 Ximian, Inc.         http://www.ximian.com
 //
@@ -39,9 +40,7 @@ using System.Runtime.Serialization.Formatters.Binary;
 
 namespace System.Resources
 {
-#if NET_2_0
        [System.Runtime.InteropServices.ComVisible (true)]
-#endif
        public sealed class ResourceWriter : IResourceWriter, IDisposable
        {
                class TypeByNameObject
@@ -56,108 +55,153 @@ namespace System.Resources
                        }
                }
 
-#if NET_2_0
-               SortedList resources = new SortedList (StringComparer.Ordinal);
-#else
-               Hashtable resources = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
+#if NET_4_0
+               class StreamWrapper
+               {
+                       public readonly bool CloseAfterWrite;
+                       public readonly Stream Stream;
+
+                       public StreamWrapper (Stream stream, bool closeAfterWrite)
+                       {
+                               Stream = stream;
+                               CloseAfterWrite = closeAfterWrite;
+                       }
+               }
 #endif
+
+               SortedList resources = new SortedList (StringComparer.OrdinalIgnoreCase);
                Stream stream;
                
                public ResourceWriter (Stream stream)
                {
                        if (stream == null)
-                               throw new ArgumentNullException ("stream is null");
-                       if (stream.CanWrite == false)
-                               throw new ArgumentException ("stream is not writable.");
+                               throw new ArgumentNullException ("stream");
+                       if (!stream.CanWrite)
+                               throw new ArgumentException ("Stream was not writable.");
 
-                       this.stream=stream;
+                       this.stream = stream;
                }
                
                public ResourceWriter (String fileName)
                {
                        if (fileName == null)
-                               throw new ArgumentNullException ("fileName is null.");
+                               throw new ArgumentNullException ("fileName");
+
+                       stream = new FileStream(fileName, FileMode.Create,
+                               FileAccess.Write);
+               }
+
+#if NET_4_0
+               Func <Type, string> type_name_converter;
 
-                       stream=new FileStream(fileName, FileMode.Create, FileAccess.Write);
+               public Func<Type, string> TypeNameConverter {
+                       get {
+                               return type_name_converter;
+                       }
+                       set {
+                               type_name_converter = value;
+                       }
                }
+#endif
                
                public void AddResource (string name, byte[] value)
                {
-                       if (name == null) {
-                               throw new ArgumentNullException ("name is null");
-                       }
-                       if (value == null) {
-                               throw new ArgumentNullException ("value is null");
-                       }
-                       if(resources==null) {
-                               throw new InvalidOperationException ("ResourceWriter has been closed");
-                       }
-                       if(resources[name]!=null) {
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+                       if (resources == null)
+                               throw new InvalidOperationException ("The resource writer has already been closed and cannot be edited");
+                       if (resources [name] != null)
                                throw new ArgumentException ("Resource already present: " + name);
-                       }
 
                        resources.Add(name, value);
                }
                
                public void AddResource (string name, object value)
-               {                        
-                       if (name == null) {
-                               throw new ArgumentNullException ("name is null");
-                       }
-                       if(resources==null) {
-                               throw new InvalidOperationException ("ResourceWriter has been closed");
-                       }
-                       if(resources[name]!=null) {
+               {
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+                       if (resources == null)
+                               throw new InvalidOperationException ("The resource writer has already been closed and cannot be edited");
+                       if (resources[name] != null)
                                throw new ArgumentException ("Resource already present: " + name);
+#if NET_4_0
+                       if (value is Stream) {
+                               Stream stream = value as Stream;
+                               if (!stream.CanSeek)
+                                       throw new ArgumentException ("Stream does not support seeking.");
+
+                               if (!(value is MemoryStream)) // We already support MemoryStream
+                                       value = new StreamWrapper (stream, false);
                        }
+#endif
 
                        resources.Add(name, value);
                }
                
                public void AddResource (string name, string value)
                {
-                       if (name == null) {
-                               throw new ArgumentNullException ("name is null");
-                       }
-                       if (value == null) {
-                               throw new ArgumentNullException ("value is null");
-                       }
-                       if(resources==null) {
-                               throw new InvalidOperationException ("ResourceWriter has been closed");
-                       }
-                       if(resources[name]!=null) {
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+                       if (resources == null)
+                               throw new InvalidOperationException ("The resource writer has already been closed and cannot be edited");
+                       if (resources [name] != null)
                                throw new ArgumentException ("Resource already present: " + name);
-                       }
 
                        resources.Add(name, value);
                }
 
-               public void Close () {
-                       Dispose(true);
+#if NET_4_0
+               public void AddResource (string name, Stream value)
+               {
+                       // It seems .Net adds this overload just to make the api complete,
+                       // but AddResource (string name, object value) is already checking for Stream.
+                       AddResource (name, (object)value);
+               }
+
+               public void AddResource (string name, Stream value, bool closeAfterWrite)
+               {
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+                       if (resources == null)
+                               throw new InvalidOperationException ("The resource writer has already been closed and cannot be edited");
+                       if (resources [name] != null)
+                               throw new ArgumentException ("Resource already present: " + name);
+
+                       if (stream == null) {
+                               resources.Add (name, null); // Odd.
+                               return;
+                       }
+                               
+                       if (!stream.CanSeek)
+                               throw new ArgumentException ("Stream does not support seeking.");
+
+                       resources.Add (name, new StreamWrapper (value, true));
+               }
+#endif
+
+               public void Close ()
+               {
+                       Dispose (true);
                }
                
                public void Dispose ()
                {
-                       Dispose(true);
+                       Dispose (true);
                }
 
                private void Dispose (bool disposing)
                {
-                       if(disposing) {
-                               if(resources.Count>0 && generated==false) {
+                       if (disposing) {
+                               if (resources != null)
                                        Generate();
-                               }
-                               if(stream!=null) {
+                               if (stream != null)
                                        stream.Close();
-                               }
-                               // If we are explicitly disposed, we can avoid finalization.
                                GC.SuppressFinalize (this);
                        }
-                       resources=null;
-                       stream=null;
+                       resources = null;
+                       stream = null;
                }
 
-#if NET_2_0
                public void AddResourceData (string name, string typeName, byte [] serializedData)
                {
                        if (name == null)
@@ -170,61 +214,59 @@ namespace System.Resources
                        // shortcut
                        AddResource (name, new TypeByNameObject (typeName, serializedData));
                }
-#endif
 
-               private bool generated=false;
-               
-               public void Generate () {
+               public void Generate ()
+               {
                        BinaryWriter writer;
                        IFormatter formatter;
 
-                       if(resources==null) {
-                               throw new InvalidOperationException ("ResourceWriter has been closed");
-                       }
+                       if (resources == null)
+                               throw new InvalidOperationException ("The resource writer has already been closed and cannot be edited");
 
-                       if(generated) {
-                               throw new InvalidOperationException ("ResourceWriter can only Generate() once");
-                       }
-                       generated=true;
-                       
-                       writer=new BinaryWriter(stream, Encoding.UTF8);
-                       formatter=new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File|StreamingContextStates.Persistence));
+                       writer = new BinaryWriter (stream, Encoding.UTF8);
+                       formatter = new BinaryFormatter (null, new StreamingContext (StreamingContextStates.File | StreamingContextStates.Persistence));
 
                        /* The ResourceManager header */
                        
-                       writer.Write(ResourceManager.MagicNumber);
-                       writer.Write(ResourceManager.HeaderVersionNumber);
+                       writer.Write (ResourceManager.MagicNumber);
+                       writer.Write (ResourceManager.HeaderVersionNumber);
                        
                        /* Build the rest of the ResourceManager
                         * header in memory, because we need to know
                         * how long it is in advance
                         */
-                       MemoryStream resman_stream=new MemoryStream();
-                       BinaryWriter resman=new BinaryWriter(resman_stream,
+                       MemoryStream resman_stream = new MemoryStream ();
+                       BinaryWriter resman = new BinaryWriter (resman_stream,
                                                             Encoding.UTF8);
 
-                       resman.Write(typeof(ResourceReader).AssemblyQualifiedName);
-#if NET_2_0
-                       resman.Write(typeof(ResourceSet).FullName);
+#if NET_4_0
+                       string type_name = null;
+                       if (type_name_converter != null)
+                               type_name = type_name_converter (typeof (ResourceReader));
+                       if (type_name == null)
+                               type_name = typeof (ResourceReader).AssemblyQualifiedName;
+
+                       resman.Write (type_name);
 #else
-                       resman.Write(typeof(ResourceSet).AssemblyQualifiedName);
+                       resman.Write (typeof (ResourceReader).AssemblyQualifiedName);
 #endif
+                       resman.Write (typeof (RuntimeResourceSet).FullName);
 
                        /* Only space for 32 bits of header len in the
                         * resource file format
                         */
-                       int resman_len=(int)resman_stream.Length;
-                       writer.Write(resman_len);
-                       writer.Write(resman_stream.GetBuffer(), 0, resman_len);
+                       int resman_len = (int) resman_stream.Length;
+                       writer.Write (resman_len);
+                       writer.Write (resman_stream.GetBuffer (), 0, resman_len);
 
                        /* We need to build the ResourceReader name
                         * and data sections simultaneously
                         */
-                       MemoryStream res_name_stream=new MemoryStream();
-                       BinaryWriter res_name=new BinaryWriter(res_name_stream, Encoding.Unicode);
+                       MemoryStream res_name_stream = new MemoryStream ();
+                       BinaryWriter res_name = new BinaryWriter (res_name_stream, Encoding.Unicode);
 
-                       MemoryStream res_data_stream=new MemoryStream();
-                       BinaryWriter res_data=new BinaryWriter(res_data_stream,
+                       MemoryStream res_data_stream = new MemoryStream ();
+                       BinaryWriter res_data = new BinaryWriter (res_data_stream,
                                                               Encoding.UTF8);
 
                        /* Not sure if this is the best collection to
@@ -234,22 +276,22 @@ namespace System.Resources
                         * key==value would work, but I need to find
                         * the index of each item later)
                         */
-                       ArrayList types=new ArrayList();
-                       int[] hashes=new int[resources.Count];
-                       int[] name_offsets=new int[resources.Count];
-                       int count=0;
+                       ArrayList types = new ArrayList ();
+                       int [] hashes = new int [resources.Count];
+                       int [] name_offsets = new int [resources.Count];
+                       int count = 0;
                        
-                       IDictionaryEnumerator res_enum=resources.GetEnumerator();
-                       while(res_enum.MoveNext()) {
+                       IDictionaryEnumerator res_enum = resources.GetEnumerator ();
+                       while (res_enum.MoveNext()) {
                                /* Hash the name */
-                               hashes[count]=GetHash((string)res_enum.Key);
+                               hashes [count] = GetHash ((string) res_enum.Key);
 
                                /* Record the offsets */
-                               name_offsets[count]=(int)res_name.BaseStream.Position;
+                               name_offsets [count] = (int) res_name.BaseStream.Position;
 
                                /* Write the name section */
-                               res_name.Write((string)res_enum.Key);
-                               res_name.Write((int)res_data.BaseStream.Position);
+                               res_name.Write ((string) res_enum.Key);
+                               res_name.Write ((int) res_data.BaseStream.Position);
 
                                if (res_enum.Value == null) {
                                        Write7BitEncodedInt (res_data, -1);
@@ -263,9 +305,8 @@ namespace System.Resources
                                object typeObj = tbn != null ? (object) tbn.TypeName : type;
 
                                /* Keep a list of unique types */
-#if NET_2_0
                                // do not output predefined ones.
-                               switch (type != null ? Type.GetTypeCode (type) : TypeCode.Empty) {
+                               switch ((type != null && !type.IsEnum) ? Type.GetTypeCode (type) : TypeCode.Empty) {
                                case TypeCode.Decimal:
                                case TypeCode.Single:
                                case TypeCode.Double:
@@ -285,6 +326,10 @@ namespace System.Resources
                                                break;
                                        if (type == typeof (MemoryStream))
                                                break;
+#if NET_4_0
+                                       if (type == typeof (StreamWrapper))
+                                               break;
+#endif
                                        if (type==typeof(byte[]))
                                                break;
 
@@ -294,134 +339,99 @@ namespace System.Resources
                                        Write7BitEncodedInt(res_data, (int) PredefinedResourceType.FistCustom + types.IndexOf(typeObj));
                                        break;
                                }
-#else
-                               if (!types.Contains (typeObj))
-                                       types.Add (typeObj);
-                               /* Write the data section */
-                               Write7BitEncodedInt(res_data, types.IndexOf(type));
-#endif
 
                                /* Strangely, Char is serialized
                                 * rather than just written out
                                 */
-#if NET_2_0
                                if (tbn != null)
                                        res_data.Write((byte []) tbn.Value);
-                               else if (type==typeof(Byte)) {
-                                       res_data.Write((byte) PredefinedResourceType.Byte);
-                                       res_data.Write((Byte)res_enum.Value);
-                               } else if (type==typeof(Decimal)) {
-                                       res_data.Write((byte) PredefinedResourceType.Decimal);
-                                       res_data.Write((Decimal)res_enum.Value);
-                               } else if (type==typeof(DateTime)) {
-                                       res_data.Write((byte) PredefinedResourceType.DateTime);
-                                       res_data.Write(((DateTime)res_enum.Value).Ticks);
-                               } else if (type==typeof(Double)) {
-                                       res_data.Write((byte) PredefinedResourceType.Double);
-                                       res_data.Write((Double)res_enum.Value);
-                               } else if (type==typeof(Int16)) {
-                                       res_data.Write((byte) PredefinedResourceType.Int16);
-                                       res_data.Write((Int16)res_enum.Value);
-                               } else if (type==typeof(Int32)) {
-                                       res_data.Write((byte) PredefinedResourceType.Int32);
-                                       res_data.Write((Int32)res_enum.Value);
-                               } else if (type==typeof(Int64)) {
-                                       res_data.Write((byte) PredefinedResourceType.Int64);
-                                       res_data.Write((Int64)res_enum.Value);
-                               } else if (type==typeof(SByte)) {
-                                       res_data.Write((byte) PredefinedResourceType.SByte);
-                                       res_data.Write((SByte)res_enum.Value);
-                               } else if (type==typeof(Single)) {
-                                       res_data.Write((byte) PredefinedResourceType.Single);
-                                       res_data.Write((Single)res_enum.Value);
-                               } else if (type==typeof(String)) {
-                                       res_data.Write((byte) PredefinedResourceType.String);
-                                       res_data.Write((String)res_enum.Value);
-                               } else if (type==typeof(TimeSpan)) {
-                                       res_data.Write((byte) PredefinedResourceType.TimeSpan);
-                                       res_data.Write(((TimeSpan)res_enum.Value).Ticks);
-                               } else if (type==typeof(UInt16)) {
-                                       res_data.Write((byte) PredefinedResourceType.UInt16);
-                                       res_data.Write((UInt16)res_enum.Value);
-                               } else if (type==typeof(UInt32)) {
-                                       res_data.Write((byte) PredefinedResourceType.UInt32);
-                                       res_data.Write((UInt32)res_enum.Value);
-                               } else if (type==typeof(UInt64)) {
-                                       res_data.Write((byte) PredefinedResourceType.UInt64);
-                                       res_data.Write((UInt64)res_enum.Value);
-                               } else if (type==typeof(byte[])) {
-                                       res_data.Write((byte) PredefinedResourceType.ByteArray);
-                                       byte [] data = (byte[])res_enum.Value;
-                                       res_data.Write((uint) data.Length);
-                                       res_data.Write(data, 0, data.Length);
-                               } else if (type==typeof(MemoryStream)) {
-                                       res_data.Write((byte) PredefinedResourceType.Stream);
-                                       byte [] data = ((MemoryStream)res_enum.Value).ToArray ();
-                                       res_data.Write((uint) data.Length);
-                                       res_data.Write(data, 0, data.Length);
-                               } else {
-                                       /* non-intrinsic types are
-                                        * serialized
-                                        */
-                                       formatter.Serialize(res_data.BaseStream, res_enum.Value);
-                               }
-#else
-                               if(type==typeof(Byte)) {
-                                       res_data.Write((Byte)res_enum.Value);
-                               } else if (type==typeof(Decimal)) {
-                                       res_data.Write((Decimal)res_enum.Value);
-                               } else if (type==typeof(DateTime)) {
-                                       res_data.Write(((DateTime)res_enum.Value).Ticks);
-                               } else if (type==typeof(Double)) {
-                                       res_data.Write((Double)res_enum.Value);
-                               } else if (type==typeof(Int16)) {
-                                       res_data.Write((Int16)res_enum.Value);
-                               } else if (type==typeof(Int32)) {
-                                       res_data.Write((Int32)res_enum.Value);
-                               } else if (type==typeof(Int64)) {
-                                       res_data.Write((Int64)res_enum.Value);
-                               } else if (type==typeof(SByte)) {
-                                       res_data.Write((SByte)res_enum.Value);
-                               } else if (type==typeof(Single)) {
-                                       res_data.Write((Single)res_enum.Value);
-                               } else if (type==typeof(String)) {
-                                       res_data.Write((String)res_enum.Value);
-                               } else if (type==typeof(TimeSpan)) {
-                                       res_data.Write(((TimeSpan)res_enum.Value).Ticks);
-                               } else if (type==typeof(UInt16)) {
-                                       res_data.Write((UInt16)res_enum.Value);
-                               } else if (type==typeof(UInt32)) {
-                                       res_data.Write((UInt32)res_enum.Value);
-                               } else if (type==typeof(UInt64)) {
-                                       res_data.Write((UInt64)res_enum.Value);
+                               else if (type == typeof (Byte)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Byte);
+                                       res_data.Write ((Byte) res_enum.Value);
+                               } else if (type == typeof (Decimal)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Decimal);
+                                       res_data.Write ((Decimal) res_enum.Value);
+                               } else if (type == typeof (DateTime)) {
+                                       res_data.Write ((byte) PredefinedResourceType.DateTime);
+                                       res_data.Write (((DateTime) res_enum.Value).Ticks);
+                               } else if (type == typeof (Double)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Double);
+                                       res_data.Write ((Double) res_enum.Value);
+                               } else if (type == typeof (Int16)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Int16);
+                                       res_data.Write ((Int16) res_enum.Value);
+                               } else if (type == typeof (Int32)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Int32);
+                                       res_data.Write ((Int32) res_enum.Value);
+                               } else if (type == typeof (Int64)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Int64);
+                                       res_data.Write ((Int64) res_enum.Value);
+                               } else if (type == typeof (SByte)) {
+                                       res_data.Write ((byte) PredefinedResourceType.SByte);
+                                       res_data.Write ((SByte) res_enum.Value);
+                               } else if (type == typeof (Single)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Single);
+                                       res_data.Write ((Single) res_enum.Value);
+                               } else if (type == typeof (String)) {
+                                       res_data.Write ((byte) PredefinedResourceType.String);
+                                       res_data.Write ((String) res_enum.Value);
+                               } else if (type == typeof (TimeSpan)) {
+                                       res_data.Write ((byte) PredefinedResourceType.TimeSpan);
+                                       res_data.Write (((TimeSpan) res_enum.Value).Ticks);
+                               } else if (type == typeof (UInt16)) {
+                                       res_data.Write ((byte) PredefinedResourceType.UInt16);
+                                       res_data.Write ((UInt16) res_enum.Value);
+                               } else if (type == typeof (UInt32)) {
+                                       res_data.Write ((byte) PredefinedResourceType.UInt32);
+                                       res_data.Write ((UInt32) res_enum.Value);
+                               } else if (type == typeof (UInt64)) {
+                                       res_data.Write ((byte) PredefinedResourceType.UInt64);
+                                       res_data.Write ((UInt64) res_enum.Value);
+                               } else if (type == typeof (byte[])) {
+                                       res_data.Write ((byte) PredefinedResourceType.ByteArray);
+                                       byte [] data = (byte[]) res_enum.Value;
+                                       res_data.Write ((uint) data.Length);
+                                       res_data.Write (data, 0, data.Length);
+                               } else if (type == typeof (MemoryStream)) {
+                                       res_data.Write ((byte) PredefinedResourceType.Stream);
+                                       byte [] data = ((MemoryStream) res_enum.Value).ToArray ();
+                                       res_data.Write ((uint) data.Length);
+                                       res_data.Write (data, 0, data.Length);
+#if NET_4_0
+                               } else if (type == typeof (StreamWrapper)) {
+                                       StreamWrapper sw = (StreamWrapper) res_enum.Value;
+                                       sw.Stream.Position = 0;
+
+                                       res_data.Write ((byte) PredefinedResourceType.Stream);
+                                       byte [] data = ReadStream (sw.Stream);
+                                       res_data.Write ((uint) data.Length);
+                                       res_data.Write (data, 0, data.Length);
+
+                                       if (sw.CloseAfterWrite)
+                                               sw.Stream.Close ();
+#endif
                                } else {
                                        /* non-intrinsic types are
                                         * serialized
                                         */
-                                       formatter.Serialize(res_data.BaseStream, res_enum.Value);
+                                       formatter.Serialize (res_data.BaseStream, res_enum.Value);
                                }
-#endif
-
                                count++;
                        }
 
                        /* Sort the hashes, keep the name offsets
                         * matching up
                         */
-                       Array.Sort(hashes, name_offsets);
+                       Array.Sort (hashes, name_offsets);
                        
                        /* now do the ResourceReader header */
 
-#if NET_2_0
-                       writer.Write(2);
-#else
-                       writer.Write(1);
-#endif
-                       writer.Write(resources.Count);
-                       writer.Write(types.Count);
+                       writer.Write (2);
+                       writer.Write (resources.Count);
+                       writer.Write (types.Count);
 
                        /* Write all of the unique types */
-                       foreach(object type in types) {
+                       foreach (object type in types) {
                                if (type is Type)
                                        writer.Write(((Type) type).AssemblyQualifiedName);
                                else
@@ -431,75 +441,92 @@ namespace System.Resources
                        /* Pad the next fields (hash values) on an 8
                         * byte boundary, using the letters "PAD"
                         */
-                       int pad_align=(int)(writer.BaseStream.Position & 7);
-                       int pad_chars=0;
+                       int pad_align = (int) (writer.BaseStream.Position & 7);
+                       int pad_chars = 0;
 
-                       if(pad_align!=0) {
-                               pad_chars=8-pad_align;
-                       }
+                       if (pad_align != 0)
+                               pad_chars = 8 - pad_align;
 
-                       for(int i=0; i<pad_chars; i++) {
-                               writer.Write((byte)"PAD"[i%3]);
-                       }
+                       for (int i = 0; i < pad_chars; i++)
+                               writer.Write ((byte) "PAD" [i % 3]);
 
                        /* Write the hashes */
-                       for(int i=0; i<resources.Count; i++) {
-                               writer.Write(hashes[i]);
-                       }
+                       for (int i = 0; i < resources.Count; i++)
+                               writer.Write (hashes[i]);
 
                        /* and the name offsets */
-                       for(int i=0; i<resources.Count; i++) {
-                               writer.Write(name_offsets[i]);
-                       }
+                       for (int i = 0; i < resources.Count; i++)
+                               writer.Write (name_offsets [i]);
 
                        /* Write the data section offset */
-                       int data_offset=(int)writer.BaseStream.Position +
-                               (int)res_name_stream.Length + 4;
-                       writer.Write(data_offset);
+                       int data_offset= (int) writer.BaseStream.Position +
+                               (int) res_name_stream.Length + 4;
+                       writer.Write (data_offset);
 
                        /* The name section goes next */
-                       writer.Write(res_name_stream.GetBuffer(), 0,
-                                    (int)res_name_stream.Length);
+                       writer.Write (res_name_stream.GetBuffer(), 0,
+                                    (int) res_name_stream.Length);
                        /* The data section is last */
-                       writer.Write(res_data_stream.GetBuffer(), 0,
-                                    (int)res_data_stream.Length);
+                       writer.Write (res_data_stream.GetBuffer(), 0,
+                                    (int) res_data_stream.Length);
 
-                       res_name.Close();
-                       res_data.Close();
+                       res_name.Close ();
+                       res_data.Close ();
 
                        /* Don't close writer, according to the spec */
-                       writer.Flush();
+                       writer.Flush ();
+
+                       // ResourceWriter is no longer editable
+                       resources = null;
+               }
+
+#if NET_4_0
+               byte [] ReadStream (Stream stream)
+               {
+                       byte [] buff = new byte [stream.Length];
+                       int pos = 0;
+
+                       // Read Stream.Length bytes at most, and stop
+                       // immediately if Read returns 0.
+                       do {
+                               int n = stream.Read (buff, pos, buff.Length - pos);
+                               if (n == 0)
+                                       break;
+
+                               pos += n;
+
+                       } while (pos < stream.Length);
+
+                       return buff;
                }
+#endif
 
                // looks like it is (similar to) DJB hash
-               private int GetHash(string name)
+               int GetHash (string name)
                {
-                       uint hash=5381;
+                       uint hash = 5381;
 
-                       for(int i=0; i<name.Length; i++) {
-                               hash=((hash<<5)+hash)^name[i];
-                       }
+                       for (int i=0; i<name.Length; i++)
+                               hash = ((hash << 5) + hash) ^ name [i];
                        
-                       return((int)hash);
+                       return ((int) hash);
                }
 
                /* Cut and pasted from BinaryWriter, because it's
                 * 'protected' there.
                 */
-               private void Write7BitEncodedInt(BinaryWriter writer,
-                                                int value)
+               void Write7BitEncodedInt (BinaryWriter writer, int value)
                {
                        do {
                                int high = (value >> 7) & 0x01ffffff;
-                               byte b = (byte)(value & 0x7f);
+                               byte b = (byte) (value & 0x7f);
 
-                               if (high != 0) {
-                                       b = (byte)(b | 0x80);
-                               }
+                               if (high != 0)
+                                       b = (byte) (b | 0x80);
 
-                               writer.Write(b);
+                               writer.Write (b);
                                value = high;
-                       } while(value != 0);
+                       } while (value != 0);
                }
 
                internal Stream Stream {