X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Resources%2FResourceReader.cs;h=ae5f679ff289ab3a1e05190a788a2da456ab08e0;hb=32ea0e7b89d21c7a7285901e0c1beae62a5e4c31;hp=d943dcb368de24b0fc2bb22ab5c42eb3267b2921;hpb=30c28c41d7859b7de6ecd7afb652468517048d12;p=mono.git diff --git a/mcs/class/corlib/System.Resources/ResourceReader.cs b/mcs/class/corlib/System.Resources/ResourceReader.cs index d943dcb368d..ae5f679ff28 100644 --- a/mcs/class/corlib/System.Resources/ResourceReader.cs +++ b/mcs/class/corlib/System.Resources/ResourceReader.cs @@ -6,9 +6,11 @@ // Nick Drochak // Dick Porter // Marek Safar +// Atsushi Enomoto +// Larry Ewing // // (C) 2001, 2002 Ximian Inc, http://www.ximian.com -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) +// Copyright (C) 2004-2005,2007-2008 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -34,9 +36,11 @@ using System.Collections; using System.Resources; using System.IO; using System.Text; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Permissions; +using System.Collections.Generic; namespace System.Resources { @@ -64,25 +68,55 @@ namespace System.Resources FistCustom = 64 } + [System.Runtime.InteropServices.ComVisible (true)] public sealed class ResourceReader : IResourceReader, IEnumerable, IDisposable { + struct ResourceInfo + { + public readonly long ValuePosition; + public readonly string ResourceName; + public readonly int TypeIndex; + + public ResourceInfo (string resourceName, long valuePosition, int type_index) + { + ValuePosition = valuePosition; + ResourceName = resourceName; + TypeIndex = type_index; + } + } + + struct ResourceCacheItem + { + public readonly string ResourceName; + public readonly object ResourceValue; + + public ResourceCacheItem (string name, object value) + { + ResourceName = name; + ResourceValue = value; + } + } + BinaryReader reader; + object readerLock = new object (); IFormatter formatter; internal int resourceCount = 0; int typeCount = 0; - Type[] types; + string[] typeNames; int[] hashes; - long[] positions; + ResourceInfo[] infos; int dataSectionOffset; long nameSectionOffset; int resource_ver; + ResourceCacheItem[] cache; + object cache_lock = new object (); // Constructors [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)] public ResourceReader (Stream stream) { if (stream == null) - throw new ArgumentNullException ("Value cannot be null."); + throw new ArgumentNullException ("stream"); if (!stream.CanRead) throw new ArgumentException ("Stream was not readable."); @@ -95,12 +129,6 @@ namespace System.Resources public ResourceReader (string fileName) { - if (fileName == null) - throw new ArgumentNullException ("Path cannot be null."); - - if (!System.IO.File.Exists (fileName)) - throw new FileNotFoundException ("Could not find file " + Path.GetFullPath(fileName)); - reader = new BinaryReader (new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)); formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File|StreamingContextStates.Persistence)); @@ -141,21 +169,17 @@ namespace System.Resources /* Now read the ResourceReader header */ resource_ver = reader.ReadInt32(); - if(resource_ver != 1 -#if NET_2_0 - && resource_ver != 2 -#endif - ) { + if(resource_ver != 1 && resource_ver != 2) { throw new NotSupportedException("This .resources file requires unsupported set class version: " + resource_ver.ToString()); } resourceCount = reader.ReadInt32(); typeCount = reader.ReadInt32(); - types=new Type[typeCount]; + typeNames=new string[typeCount]; for(int i=0; i 0 ) { + int x = reader.Read (bytes, 0, (int)Math.Min (bytes.Length, slen)); + + if (x == 0) + throw new FormatException ("The resource data is corrupt. Resource stream ended"); + + ms.Write (bytes, 0, x); + slen -= x; + } + ms.Seek (0, SeekOrigin.Begin); + return ms; + } + } } } @@ -402,6 +476,15 @@ namespace System.Resources { Dispose(true); } + +#if NET_4_0 + public void Dispose () +#else + void IDisposable.Dispose () +#endif + { + Dispose(true); + } public IDictionaryEnumerator GetEnumerator () { if (reader == null){ @@ -416,10 +499,54 @@ namespace System.Resources { return ((IResourceReader) this).GetEnumerator(); } - - void IDisposable.Dispose () + + public void GetResourceData (string resourceName, out string resourceType, out byte [] resourceData) { - Dispose(true); + if (resourceName == null) + throw new ArgumentNullException ("resourceName"); + ResourceEnumerator en = new ResourceEnumerator (this); + while (en.MoveNext ()) + if ((string) en.Key == resourceName) { + GetResourceDataAt (en.Index, out resourceType, out resourceData); + return; + } + throw new ArgumentException (String.Format ("Specified resource not found: {0}", resourceName)); + } + + private void GetResourceDataAt (int index, out string resourceType, out byte [] data) + { + ResourceInfo ri = infos [index]; + int type_index = ri.TypeIndex; + if (type_index == -1) + throw new FormatException ("The resource data is corrupt"); + + lock (readerLock) { + reader.BaseStream.Seek (ri.ValuePosition, SeekOrigin.Begin); + long pos2 = reader.BaseStream.Position; + + // Simply read data, and seek back to the original position + if (resource_ver == 2) { + if (type_index >= (int) PredefinedResourceType.FistCustom) { + int typenameidx = type_index - (int)PredefinedResourceType.FistCustom; + if (typenameidx >= typeNames.Length) + throw new FormatException ("The resource data is corrupt. Invalid index to types"); + resourceType = typeNames[typenameidx]; + } + else + resourceType = "ResourceTypeCode." + (PredefinedResourceType) type_index; + ReadValueVer2 (type_index); + } else { + // resource ver 1 == untyped + resourceType = "ResourceTypeCode.Null"; + ReadValueVer1 (Type.GetType (typeNames [type_index], true)); + } + + // FIXME: the data size is wrong. + int datalen = (int) (reader.BaseStream.Position - pos2); + reader.BaseStream.Seek (-datalen, SeekOrigin.Current); + data = new byte [datalen]; + reader.BaseStream.Read (data, 0, datalen); + } } private void Dispose (bool disposing) @@ -429,61 +556,77 @@ namespace System.Resources reader.Close(); } } - + reader=null; hashes=null; - positions=null; - types=null; + infos=null; + typeNames=null; + cache = null; } - internal class ResourceEnumerator : IDictionaryEnumerator + internal sealed class ResourceEnumerator : IDictionaryEnumerator { private ResourceReader reader; private int index = -1; - private bool finished = false; + private bool finished; - internal ResourceEnumerator(ResourceReader readerToEnumerate){ + internal ResourceEnumerator(ResourceReader readerToEnumerate) + { reader = readerToEnumerate; + FillCache (); } - public virtual DictionaryEntry Entry + public int Index { + get { return index; } + } + + public DictionaryEntry Entry { get { if (reader.reader == null) throw new InvalidOperationException("ResourceReader is closed."); if (index < 0) throw new InvalidOperationException("Enumeration has not started. Call MoveNext."); - DictionaryEntry entry = new DictionaryEntry(); - entry.Key = Key; - entry.Value = Value; - return entry; + return new DictionaryEntry(Key, Value); } } - public virtual object Key + public object Key { get { if (reader.reader == null) throw new InvalidOperationException("ResourceReader is closed."); if (index < 0) throw new InvalidOperationException("Enumeration has not started. Call MoveNext."); - return (reader.ResourceName(index)); + + return reader.cache [index].ResourceName; } } - public virtual object Value + public object Value { get { if (reader.reader == null) throw new InvalidOperationException("ResourceReader is closed."); if (index < 0) throw new InvalidOperationException("Enumeration has not started. Call MoveNext."); - return(reader.ResourceValue(index)); + return reader.cache [index].ResourceValue; + } + } + + public UnmanagedMemoryStream ValueAsStream + { + get { + if (reader.reader == null) + throw new InvalidOperationException("ResourceReader is closed."); + if (index < 0) + throw new InvalidOperationException("Enumeration has not started. Call MoveNext."); + return(reader.ResourceValueAsStream((string) Key, index)); } } - public virtual object Current + public object Current { get { /* Entry does the checking, no @@ -493,7 +636,7 @@ namespace System.Resources } } - public virtual bool MoveNext () + public bool MoveNext () { if (reader.reader == null) throw new InvalidOperationException("ResourceReader is closed."); @@ -504,10 +647,9 @@ namespace System.Resources if (++index < reader.resourceCount){ return true; } - else { - finished=true; - return false; - } + + finished=true; + return false; } public void Reset () { @@ -516,6 +658,21 @@ namespace System.Resources index = -1; finished = false; } + + void FillCache () + { + if (reader.cache != null) + return; + + lock (reader.cache_lock) { + if (reader.cache != null) + return; + + ResourceCacheItem[] resources = new ResourceCacheItem [reader.resourceCount]; + reader.LoadResourceValues (resources); + reader.cache = resources; + } + } } // internal class ResourceEnumerator } // public sealed class ResourceReader } // namespace System.Resources