We need you! We're working hard on the next version of Developer Fusion -
Let us know what you think we should be up to!
- namespace System.Resources
- {
- using System;
- using System.IO;
- using System.Text;
- using System.Collections;
- using System.Collections.Generic;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.Globalization;
- using System.Runtime.Versioning;
-
-
-
-
-
-
-
-
-
-
-
-
- [System.Runtime.InteropServices.ComVisible(true)]
- public sealed class ResourceWriter : IResourceWriter
- {
-
-
-
- private class PrecannedResource
- {
- internal string TypeName;
- internal byte[] Data;
-
- internal PrecannedResource(string typeName, byte[] data)
- {
- TypeName = typeName;
- Data = data;
- }
- }
-
-
- private const int _ExpectedNumberOfResources = 1000;
- private const int AverageNameSize = 20 * 2;
-
- private const int AverageValueSize = 40;
-
- private Hashtable _resourceList;
-
- private Stream _output;
- private Hashtable _caseInsensitiveDups;
-
- private Hashtable _preserializedData;
-
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- public ResourceWriter(string fileName)
- {
- if (fileName == null)
- throw new ArgumentNullException("fileName");
- _output = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
- _resourceList = new Hashtable(_ExpectedNumberOfResources, FastResourceComparer.Default);
- _caseInsensitiveDups = new Hashtable(StringComparer.OrdinalIgnoreCase);
- }
-
- public ResourceWriter(Stream stream)
- {
- if (stream == null)
- throw new ArgumentNullException("stream");
- if (!stream.CanWrite)
- throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
- _output = stream;
- _resourceList = new Hashtable(_ExpectedNumberOfResources, FastResourceComparer.Default);
- _caseInsensitiveDups = new Hashtable(StringComparer.OrdinalIgnoreCase);
- }
-
-
-
-
-
- public void AddResource(string name, string value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
- if (_resourceList == null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceWriterSaved"));
-
-
- _caseInsensitiveDups.Add(name, null);
- _resourceList.Add(name, value);
- }
-
-
-
-
- public void AddResource(string name, object value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
- if (_resourceList == null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceWriterSaved"));
-
-
- _caseInsensitiveDups.Add(name, null);
- _resourceList.Add(name, value);
- }
-
-
-
-
- public void AddResource(string name, byte[] value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
- if (_resourceList == null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceWriterSaved"));
-
-
- _caseInsensitiveDups.Add(name, null);
- _resourceList.Add(name, value);
- }
-
- public void AddResourceData(string name, string typeName, byte[] serializedData)
- {
- if (name == null)
- throw new ArgumentNullException("name");
- if (typeName == null)
- throw new ArgumentNullException("typeName");
- if (serializedData == null)
- throw new ArgumentNullException("serializedData");
- if (_resourceList == null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceWriterSaved"));
-
-
- _caseInsensitiveDups.Add(name, null);
- if (_preserializedData == null)
- _preserializedData = new Hashtable(FastResourceComparer.Default);
-
- _preserializedData.Add(name, new PrecannedResource(typeName, serializedData));
- }
-
-
-
- public void Close()
- {
- Dispose(true);
- }
-
- private void Dispose(bool disposing)
- {
- if (disposing) {
- if (_resourceList != null) {
- Generate();
- }
- if (_output != null) {
- _output.Close();
- }
- }
- _output = null;
- _caseInsensitiveDups = null;
-
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
-
-
-
-
-
- public void Generate()
- {
- if (_resourceList == null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceWriterSaved"));
-
- BinaryWriter bw = new BinaryWriter(_output, Encoding.UTF8);
- List<string> typeNames = new List<string>();
-
-
-
- bw.Write(ResourceManager.MagicNumber);
-
-
- bw.Write(ResourceManager.HeaderVersionNumber);
-
- MemoryStream resMgrHeaderBlob = new MemoryStream(240);
- BinaryWriter resMgrHeaderPart = new BinaryWriter(resMgrHeaderBlob);
-
-
-
- resMgrHeaderPart.Write(typeof(ResourceReader).AssemblyQualifiedName);
-
-
-
- resMgrHeaderPart.Write(ResourceManager.ResSetTypeName);
- resMgrHeaderPart.Flush();
-
-
- bw.Write((int)resMgrHeaderBlob.Length);
-
-
- bw.Write(resMgrHeaderBlob.GetBuffer(), 0, (int)resMgrHeaderBlob.Length);
-
-
-
-
-
- bw.Write(RuntimeResourceSet.Version);
- #if RESOURCE_FILE_FORMAT_DEBUG
-
-
- bw.Write("***DEBUG***");
- #endif
-
-
- int numResources = _resourceList.Count;
- if (_preserializedData != null)
- numResources += _preserializedData.Count;
- bw.Write(numResources);
-
-
- int[] nameHashes = new int[numResources];
- int[] namePositions = new int[numResources];
- int curNameNumber = 0;
- MemoryStream nameSection = new MemoryStream(numResources * AverageNameSize);
- BinaryWriter names = new BinaryWriter(nameSection, Encoding.Unicode);
- MemoryStream dataSection = new MemoryStream(numResources * AverageValueSize);
- BinaryWriter data = new BinaryWriter(dataSection, Encoding.UTF8);
- IFormatter objFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence));
-
- #if RESOURCE_FILE_FORMAT_DEBUG
-
- names.Write(new byte[] {(byte)'N', (byte)'A', (byte)'M', (byte)'E', (byte)'S', (byte)'-', (byte)'-', (byte)'>'});
-
-
- data.Write(new byte[] {(byte)'D', (byte)'A', (byte)'T', (byte)'A', (byte)'-', (byte)'-', (byte)'-', (byte)'>'});
- #endif
-
-
-
-
-
-
-
-
- SortedList sortedResources = new SortedList(_resourceList, FastResourceComparer.Default);
- if (_preserializedData != null) {
- foreach (DictionaryEntry entry in _preserializedData)
- sortedResources.Add(entry.Key, entry.Value);
- }
-
-
- IDictionaryEnumerator items = sortedResources.GetEnumerator();
-
-
- while (items.MoveNext()) {
- nameHashes[curNameNumber] = FastResourceComparer.HashFunction((string)items.Key);
- namePositions[curNameNumber++] = (int)names.Seek(0, SeekOrigin.Current);
- names.Write((string)items.Key);
-
- names.Write((int)data.Seek(0, SeekOrigin.Current));
-
- #if RESOURCE_FILE_FORMAT_DEBUG
- names.Write((byte)'*');
- #endif
- object value = items.Value;
- ResourceTypeCode typeCode = FindTypeCode(value, typeNames);
-
-
- Write7BitEncodedInt(data, (int)typeCode);
-
-
- PrecannedResource userProvidedResource = value as PrecannedResource;
- if (userProvidedResource != null) {
- data.Write(userProvidedResource.Data);
- }
- else {
- WriteValue(typeCode, value, data, objFormatter);
- }
-
- #if RESOURCE_FILE_FORMAT_DEBUG
- data.Write(new byte[] {(byte)'S', (byte)'T', (byte)'O', (byte)'P'});
- #endif
- }
-
-
-
-
- bw.Write(typeNames.Count);
- for (int i = 0; i < typeNames.Count; i++)
- bw.Write(typeNames[i]);
-
-
-
-
- Array.Sort(nameHashes, namePositions);
-
-
-
-
-
- bw.Flush();
- int alignBytes = ((int)bw.BaseStream.Position) & 7;
- if (alignBytes > 0) {
- for (int i = 0; i < 8 - alignBytes; i++)
- bw.Write("PAD"[i % 3]);
- }
-
-
-
- BCLDebug.Assert((bw.BaseStream.Position & 7) == 0, "ResourceWriter: Name hashes array won't be 8 byte aligned! Ack!");
- #if RESOURCE_FILE_FORMAT_DEBUG
- bw.Write(new byte[] {(byte)'H', (byte)'A', (byte)'S', (byte)'H', (byte)'E', (byte)'S', (byte)'-', (byte)'>'});
- #endif
- foreach (int hash in nameHashes)
- bw.Write(hash);
- #if RESOURCE_FILE_FORMAT_DEBUG
- Console.Write("Name hashes: ");
- foreach (int hash in nameHashes)
- Console.Write(hash.ToString("x") + " ");
- Console.WriteLine();
- #endif
-
-
-
-
-
- BCLDebug.Assert((bw.BaseStream.Position & 3) == 0, "ResourceWriter: Name positions array won't be 4 byte aligned! Ack!");
- #if RESOURCE_FILE_FORMAT_DEBUG
- bw.Write(new byte[] {(byte)'P', (byte)'O', (byte)'S', (byte)'-', (byte)'-', (byte)'-', (byte)'-', (byte)'>'});
- #endif
- foreach (int pos in namePositions)
- bw.Write(pos);
- #if RESOURCE_FILE_FORMAT_DEBUG
- Console.Write("Name positions: ");
- foreach (int pos in namePositions)
- Console.Write(pos.ToString("x") + " ");
- Console.WriteLine();
- #endif
-
-
- bw.Flush();
- names.Flush();
- data.Flush();
-
-
- int startOfDataSection = (int)(bw.Seek(0, SeekOrigin.Current) + nameSection.Length);
- startOfDataSection += 4;
-
- BCLDebug.Log("RESMGRFILEFORMAT", "Generate: start of DataSection: 0x" + startOfDataSection.ToString("x", CultureInfo.InvariantCulture) + " nameSection length: " + nameSection.Length);
- bw.Write(startOfDataSection);
-
-
- bw.Write(nameSection.GetBuffer(), 0, (int)nameSection.Length);
- names.Close();
-
-
- BCLDebug.Assert(startOfDataSection == bw.Seek(0, SeekOrigin.Current), "ResourceWriter::Generate - start of data section is wrong!");
- bw.Write(dataSection.GetBuffer(), 0, (int)dataSection.Length);
- data.Close();
- bw.Flush();
-
-
- _resourceList = null;
- }
-
-
-
- private ResourceTypeCode FindTypeCode(object value, List<string> types)
- {
- if (value == null)
- return ResourceTypeCode.Null;
-
- Type type = value.GetType();
- if (type == typeof(string))
- return ResourceTypeCode.String;
- else if (type == typeof(Int32))
- return ResourceTypeCode.Int32;
- else if (type == typeof(bool))
- return ResourceTypeCode.Boolean;
- else if (type == typeof(char))
- return ResourceTypeCode.Char;
- else if (type == typeof(byte))
- return ResourceTypeCode.Byte;
- else if (type == typeof(sbyte))
- return ResourceTypeCode.SByte;
- else if (type == typeof(Int16))
- return ResourceTypeCode.Int16;
- else if (type == typeof(Int64))
- return ResourceTypeCode.Int64;
- else if (type == typeof(UInt16))
- return ResourceTypeCode.UInt16;
- else if (type == typeof(UInt32))
- return ResourceTypeCode.UInt32;
- else if (type == typeof(UInt64))
- return ResourceTypeCode.UInt64;
- else if (type == typeof(float))
- return ResourceTypeCode.Single;
- else if (type == typeof(double))
- return ResourceTypeCode.Double;
- else if (type == typeof(decimal))
- return ResourceTypeCode.Decimal;
- else if (type == typeof(DateTime))
- return ResourceTypeCode.DateTime;
- else if (type == typeof(TimeSpan))
- return ResourceTypeCode.TimeSpan;
- else if (type == typeof(byte[]))
- return ResourceTypeCode.ByteArray;
- else if (type == typeof(MemoryStream))
- return ResourceTypeCode.Stream;
-
-
-
-
- string typeName;
- if (type == typeof(PrecannedResource)) {
- typeName = ((PrecannedResource)value).TypeName;
- if (typeName.StartsWith("ResourceTypeCode.", StringComparison.Ordinal)) {
- typeName = typeName.Substring(17);
-
- ResourceTypeCode typeCode = (ResourceTypeCode)Enum.Parse(typeof(ResourceTypeCode), typeName);
- return typeCode;
- }
- }
- else
- typeName = type.AssemblyQualifiedName;
-
- int typeIndex = types.IndexOf(typeName);
- if (typeIndex == -1) {
- typeIndex = types.Count;
- types.Add(typeName);
- }
-
- return (ResourceTypeCode)(typeIndex + ResourceTypeCode.StartOfUserTypes);
- }
-
-
-
-
-
-
-
-
-
-
-
-
- private void WriteValue(ResourceTypeCode typeCode, object value, BinaryWriter writer, IFormatter objFormatter)
- {
- switch (typeCode) {
- case ResourceTypeCode.Null:
- break;
- case ResourceTypeCode.String:
-
- writer.Write((string)value);
- break;
- case ResourceTypeCode.Boolean:
-
- writer.Write((bool)value);
- break;
- case ResourceTypeCode.Char:
-
- writer.Write((UInt16)(char)value);
- break;
- case ResourceTypeCode.Byte:
-
- writer.Write((byte)value);
- break;
- case ResourceTypeCode.SByte:
-
- writer.Write((sbyte)value);
- break;
- case ResourceTypeCode.Int16:
-
- writer.Write((Int16)value);
- break;
- case ResourceTypeCode.UInt16:
-
- writer.Write((UInt16)value);
- break;
- case ResourceTypeCode.Int32:
-
- writer.Write((Int32)value);
- break;
- case ResourceTypeCode.UInt32:
-
- writer.Write((UInt32)value);
- break;
- case ResourceTypeCode.Int64:
-
- writer.Write((Int64)value);
- break;
- case ResourceTypeCode.UInt64:
-
- writer.Write((UInt64)value);
- break;
- case ResourceTypeCode.Single:
-
- writer.Write((float)value);
- break;
- case ResourceTypeCode.Double:
-
- writer.Write((double)value);
- break;
- case ResourceTypeCode.Decimal:
-
- writer.Write((decimal)value);
- break;
- case ResourceTypeCode.DateTime:
-
-
- Int64 data = ((DateTime)value).ToBinary();
- writer.Write(data);
- break;
- case ResourceTypeCode.TimeSpan:
-
- writer.Write(((TimeSpan)value).Ticks);
- break;
- case ResourceTypeCode.ByteArray:
-
-
-
- {
- byte[] bytes = (byte[])value;
- writer.Write(bytes.Length);
- writer.Write(bytes, 0, bytes.Length);
- break;
- }
- break;
- case ResourceTypeCode.Stream:
-
-
- {
- MemoryStream ms = (MemoryStream)value;
- if (ms.Length > Int32.MaxValue)
- throw new ArgumentException(Environment.GetResourceString("ArgumentOutOfRange_MemStreamLength"));
- int offset;
- int len;
- ms.InternalGetOriginAndLength(out offset, out len);
- byte[] bytes = ms.InternalGetBuffer();
- writer.Write(len);
- writer.Write(bytes, offset, len);
- break;
- }
- break;
- default:
-
- BCLDebug.Assert(typeCode >= ResourceTypeCode.StartOfUserTypes, String.Format(CultureInfo.InvariantCulture, "ResourceReader: Unsupported ResourceTypeCode in .resources file! {0}", typeCode));
- objFormatter.Serialize(writer.BaseStream, value);
- break;
- }
- }
-
- private static void Write7BitEncodedInt(BinaryWriter store, int value)
- {
-
-
- uint v = (uint)value;
-
- while (v >= 128) {
- store.Write((byte)(v | 128));
- v >>= 7;
- }
- store.Write((byte)v);
- }
- }
- }