Do not skip comments, just pluck expressions/tags from within them
[mono.git] / mcs / class / System.Web / System.Web.Compilation / AppResourcesCompiler.cs
index dfe891605598d560e0d50535e2cfea761fbc757a..f851ea73b8f7324e28a504b41d1e606566e9584a 100644 (file)
@@ -2,9 +2,10 @@
 // System.Web.Compilation.AppResourceFilesCollection
 //
 // Authors:
-//   Marek Habersack (grendello@gmail.com)
+//   Marek Habersack (mhabersack@novell.com)
 //
 // (C) 2006 Marek Habersack
+// (C) 2007-2009 Novell, Inc http://novell.com/
 //
 
 //
@@ -33,6 +34,7 @@ using System.CodeDom;
 using System.CodeDom.Compiler;
 using System.Collections;
 using System.Collections.Generic;
+using System.ComponentModel.Design;
 using System.Globalization;
 using System.IO;
 using System.Reflection;
@@ -44,14 +46,176 @@ using System.Web.Util;
 
 namespace System.Web.Compilation 
 {
-       internal class AppResourcesCompiler
+       class AppResourcesCompiler
        {
+               // This class fixes bug #466059
+               class TypeResolutionService : ITypeResolutionService
+               {
+                       List <Assembly> referencedAssemblies;
+                       Dictionary <string, Type> mappedTypes;
+
+                       public Assembly GetAssembly (AssemblyName name)
+                       {
+                               return GetAssembly (name, false);
+                       }
+                       
+                       public Assembly GetAssembly (AssemblyName name, bool throwOnError)
+                       {
+                               try {
+                                       return Assembly.Load (name);
+                               } catch {
+                                       if (throwOnError)
+                                               throw;
+                               }
+
+                               return null;
+                       }
+
+                       public void ReferenceAssembly (AssemblyName name)
+                       {
+                               if (referencedAssemblies == null)
+                                       referencedAssemblies = new List <Assembly> ();
+
+                               Assembly asm = GetAssembly (name, false);
+                               if (asm == null)
+                                       return;
+                               
+                               if (referencedAssemblies.Contains (asm))
+                                       return;
+                               
+                               referencedAssemblies.Add (asm);
+                       }
+
+                       public string GetPathOfAssembly (AssemblyName name)
+                       {
+                               if (name == null)
+                                       return null;
+
+                               Assembly asm = GetAssembly (name, false);
+                               if (asm == null)
+                                       return null;
+                               
+                               return asm.Location;
+                       }
+
+                       public Type GetType (string name)
+                       {
+                               return GetType (name, false, false);
+                       }
+
+                       public Type GetType (string name, bool throwOnError)
+                       {
+                               return GetType (name, throwOnError, false);
+                       }
+
+                       public Type GetType (string name, bool throwOnError, bool ignoreCase)
+                       {
+                               if (String.IsNullOrEmpty (name)) {
+                                       if (throwOnError)
+                                               throw new ArgumentNullException ("name");
+                                       else
+                                               return null;
+                               }
+
+                               int idx = name.IndexOf (',');
+                               Type type = null;
+                               if (idx == -1) {
+                                       type = MapType (name, false);
+                                       if (type != null)
+                                               return type;
+                                       
+                                       type = FindInAssemblies (name, ignoreCase);
+                                       if (type == null) {
+                                               if (throwOnError)
+                                                       throw new InvalidOperationException ("Type '" + name + "' is not fully qualified and there are no referenced assemblies.");
+                                               else
+                                                       return null;
+                                       }
+
+                                       return type;
+                               }
+
+                               type = MapType (name, true);
+                               if (type != null)
+                                       return type;
+                               
+                               return Type.GetType (name, throwOnError, ignoreCase);
+                       }
+
+                       Type MapType (string name, bool full)
+                       {
+                               if (mappedTypes == null)
+                                       mappedTypes = new Dictionary <string, Type> (StringComparer.Ordinal);
+
+                               Type ret;
+                               if (mappedTypes.TryGetValue (name, out ret))
+                                       return ret;
+
+                               if (!full) {
+                                       if (String.Compare (name, "ResXDataNode", StringComparison.Ordinal) == 0)
+                                               return AddMappedType (name, typeof (ResXDataNode));
+                                       if (String.Compare (name, "ResXFileRef", StringComparison.Ordinal) == 0)
+                                               return AddMappedType (name, typeof (ResXFileRef));
+                                       if (String.Compare (name, "ResXNullRef", StringComparison.Ordinal) == 0)
+                                               return AddMappedType (name, typeof (ResXNullRef));
+                                       if (String.Compare (name, "ResXResourceReader", StringComparison.Ordinal) == 0)
+                                               return AddMappedType (name, typeof (ResXResourceReader));
+                                       if (String.Compare (name, "ResXResourceWriter", StringComparison.Ordinal) == 0)
+                                               return AddMappedType (name, typeof (ResXResourceWriter));
+
+                                       return null;
+                               }
+
+                               if (name.IndexOf ("System.Windows.Forms") == -1)
+                                       return null;
+
+                               if (name.IndexOf ("ResXDataNode", StringComparison.Ordinal) != -1)
+                                       return AddMappedType (name, typeof (ResXDataNode));
+                               if (name.IndexOf ("ResXFileRef", StringComparison.Ordinal) != -1)
+                                       return AddMappedType (name, typeof (ResXFileRef));
+                               if (name.IndexOf ("ResXNullRef", StringComparison.Ordinal) != -1)
+                                       return AddMappedType (name, typeof (ResXNullRef));
+                               if (name.IndexOf ("ResXResourceReader", StringComparison.Ordinal) != -1)
+                                       return AddMappedType (name, typeof (ResXResourceReader));
+                               if (name.IndexOf ("ResXResourceWriter", StringComparison.Ordinal) != -1)
+                                       return AddMappedType (name, typeof (ResXResourceWriter));
+
+                               return null;
+                       }
+
+                       Type AddMappedType (string name, Type type)
+                       {
+                               mappedTypes.Add (name, type);
+                               return type;
+                       }
+                       
+                       Type FindInAssemblies (string name, bool ignoreCase)
+                       {
+                               Type ret = Type.GetType (name, false);
+                               if (ret != null)
+                                       return ret;
+
+                               if (referencedAssemblies == null || referencedAssemblies.Count == 0)
+                                       return null;
+
+                               foreach (Assembly asm in referencedAssemblies) {
+                                       ret = asm.GetType (name, false, ignoreCase);
+                                       if (ret != null)
+                                               return ret;
+                               }
+
+                               return null;
+                       }
+               }
+               
                const string cachePrefix = "@@LocalResourcesAssemblies";
+               public const string DefaultCultureKey = ".:!DefaultCulture!:.";
                
                bool isGlobal;
-               HttpContext context;
                AppResourceFilesCollection files;
                string tempDirectory;
+               string virtualPath;
+               Dictionary <string, List <string>> cultureFiles;
                
                string TempDirectory {
                        get {
@@ -60,52 +224,52 @@ namespace System.Web.Compilation
                                return (tempDirectory = AppDomain.CurrentDomain.SetupInformation.DynamicBase);
                        }
                }
+
+               public Dictionary <string, List <string>> CultureFiles {
+                       get { return cultureFiles; }
+               }
                
-               public AppResourcesCompiler (HttpContext context, bool isGlobal)
+               public AppResourcesCompiler (HttpContext context)
                {
-                       this.context = context;
-                       this.isGlobal = isGlobal;
-                       this.files = new AppResourceFilesCollection (context, isGlobal);
+                       this.isGlobal = true;
+                       this.files = new AppResourceFilesCollection (context);
+                       this.cultureFiles = new Dictionary <string, List <string>> ();
                }
 
+               public AppResourcesCompiler (string virtualPath)
+               {
+
+                       this.virtualPath = virtualPath;
+                       this.isGlobal = false;
+                       this.files = new AppResourceFilesCollection (HttpContext.Current.Request.MapPath (virtualPath));
+                       this.cultureFiles = new Dictionary <string, List <string>> ();
+               }
                
-               public void Compile ()
+               public Assembly Compile ()
                {
                        files.Collect ();
                        if (!files.HasFiles)
-                               return;
+                               return null;
                        if (isGlobal)
-                               CompileGlobal ();
+                               return CompileGlobal ();
                        else
-                               CompileLocal ();
+                               return CompileLocal ();
                }
 
-               void CompileGlobal ()
+               Assembly CompileGlobal ()
                {
                        string assemblyPath = FileUtils.CreateTemporaryFile (TempDirectory,
                                                                             "App_GlobalResources",
                                                                             "dll",
                                                                             OnCreateRandomFile) as string;
+
                        if (assemblyPath == null)
                                throw new ApplicationException ("Failed to create global resources assembly");
                        
-                       CompilationSection config = WebConfigurationManager.GetSection ("system.web/compilation") as CompilationSection;
-                       if (config == null || !CodeDomProvider.IsDefinedLanguage (config.DefaultLanguage))
-                               throw new ApplicationException ("Could not get the default compiler.");
-                       CompilerInfo ci = CodeDomProvider.GetCompilerInfo (config.DefaultLanguage);
-                       if (ci == null || !ci.IsCodeDomProviderTypeValid)
-                               throw new ApplicationException ("Failed to obtain the default compiler information.");
-
-                       CompilerParameters cp = ci.CreateDefaultCompilerParameters ();
-                       cp.OutputAssembly = assemblyPath;
-                       cp.GenerateExecutable = false;
-                       cp.TreatWarningsAsErrors = true;
-                       cp.IncludeDebugInformation = config.Debug;
-                       
-                       List <string>[] fileGroups = GroupGlobalFiles (cp);
+                       List <string>[] fileGroups = GroupGlobalFiles ();
                        if (fileGroups == null || fileGroups.Length == 0)
-                               return;
-
+                               return null;
+                       
                        CodeCompileUnit unit = new CodeCompileUnit ();
                        CodeNamespace ns = new CodeNamespace (null);
                        ns.Imports.Add (new CodeNamespaceImport ("System"));
@@ -114,101 +278,73 @@ namespace System.Web.Compilation
                        ns.Imports.Add (new CodeNamespaceImport ("System.Resources"));
                        unit.Namespaces.Add (ns);
 
-                       CodeDomProvider provider;
-                       provider = ci.CreateProvider ();
-                       if (provider == null)
-                               throw new ApplicationException ("Failed to instantiate the default compiler.");
+                       AppResourcesAssemblyBuilder builder = new AppResourcesAssemblyBuilder ("App_GlobalResources", assemblyPath,
+                                                                                              this);
+                       CodeDomProvider provider = builder.Provider;
                        
                        Dictionary <string,bool> assemblies = new Dictionary<string,bool> ();
                        foreach (List<string> ls in fileGroups)
                                DomFromResource (ls [0], unit, assemblies, provider);
+                       
                        foreach (KeyValuePair<string,bool> de in assemblies)
                                unit.ReferencedAssemblies.Add (de.Key);
                        
-                       AssemblyBuilder abuilder = new AssemblyBuilder (provider);
-                       abuilder.AddCodeCompileUnit (unit);
-
-                       CompilerResults results = abuilder.BuildAssembly (cp);
-                       if (results.Errors.Count == 0) {
-                               BuildManager.TopLevelAssemblies.Add (results.CompiledAssembly);
-                               HttpContext.AppGlobalResourcesAssembly = results.CompiledAssembly;
-                       } else {
-                               if (context.IsCustomErrorEnabled)
-                                       throw new ApplicationException ("An error occurred while compiling global resources.");
-                               throw new CompilationException (null, results.Errors, null);
-                       }
+                       builder.Build (unit);
+                       HttpContext.AppGlobalResourcesAssembly = builder.MainAssembly;
+                       
+                       return builder.MainAssembly;
                }
 
-               void CompileLocal ()
+               Assembly CompileLocal ()
                {
-                       string path = Path.GetDirectoryName (VirtualPathUtility.ToAbsolute (context.Request.CurrentExecutionFilePath));
+                       if (String.IsNullOrEmpty (virtualPath))
+                               return null;
                        
-                       if (String.IsNullOrEmpty (path))
-                               throw new ApplicationException ("Unable to determine the request virtual path.");
-
-                       Assembly cached = GetCachedLocalResourcesAssembly (path);
+                       Assembly cached = GetCachedLocalResourcesAssembly (virtualPath);
                        if (cached != null)
-                               return;
+                               return cached;
                        
                        string prefix;
-                       if (path == "/")
+                       if (virtualPath == "/")
                                prefix = "App_LocalResources.root";
                        else
-                               prefix = "App_LocalResources" + path.Replace ('/', '.');
+                               prefix = "App_LocalResources" + virtualPath.Replace ('/', '.');
                        
                        string assemblyPath = FileUtils.CreateTemporaryFile (TempDirectory,
                                                                             prefix,
                                                                             "dll",
                                                                             OnCreateRandomFile) as string;
                        if (assemblyPath == null)
-                               throw new ApplicationException ("Failed to create global resources assembly");
-                       
-                       CompilationSection config = WebConfigurationManager.GetSection ("system.web/compilation") as CompilationSection;
-                       if (config == null || !CodeDomProvider.IsDefinedLanguage (config.DefaultLanguage))
-                               throw new ApplicationException ("Could not get the default compiler.");
-                       CompilerInfo ci = CodeDomProvider.GetCompilerInfo (config.DefaultLanguage);
-                       if (ci == null || !ci.IsCodeDomProviderTypeValid)
-                               throw new ApplicationException ("Failed to obtain the default compiler information.");
-
-                       CompilerParameters cp = ci.CreateDefaultCompilerParameters ();
-                       cp.OutputAssembly = assemblyPath;
-                       cp.GenerateExecutable = false;
-                       cp.TreatWarningsAsErrors = true;
-                       cp.IncludeDebugInformation = config.Debug;
+                               throw new ApplicationException ("Failed to create local resources assembly");
 
                        List<AppResourceFileInfo> files = this.files.Files;
                        foreach (AppResourceFileInfo arfi in files)
-                               GetResourceFile (arfi, cp);
+                               GetResourceFile (arfi, true);
 
-                       CodeDomProvider provider;
-                       provider = ci.CreateProvider ();
-                       if (provider == null)
-                               throw new ApplicationException ("Failed to instantiate the default compiler.");
+                       AppResourcesAssemblyBuilder builder = new AppResourcesAssemblyBuilder ("App_LocalResources", assemblyPath,
+                                                                                              this);
+                       builder.Build ();
+                       Assembly ret = builder.MainAssembly;
                        
-                       AssemblyBuilder abuilder = new AssemblyBuilder (provider);
-                       CompilerResults results = abuilder.BuildAssembly (cp);
-                       if (results.Errors.Count == 0) {
-                               AddAssemblyToCache (path, results.CompiledAssembly);
-                       } else {
-                               if (context.IsCustomErrorEnabled)
-                                       throw new ApplicationException ("An error occurred while compiling global resources.");
-                               throw new CompilationException (null, results.Errors, null);
-                       }
-               }
+                       if (ret != null)
+                               AddAssemblyToCache (virtualPath, ret);
 
+                       return ret;
+               }
+               
                internal static Assembly GetCachedLocalResourcesAssembly (string path)
                {
                        Dictionary <string, Assembly> cache;
 
-                       cache = HttpRuntime.Cache[cachePrefix] as Dictionary <string, Assembly>;
+                       cache = HttpRuntime.InternalCache[cachePrefix] as Dictionary <string, Assembly>;
                        if (cache == null || !cache.ContainsKey (path))
                                return null;
                        return cache [path];
                }
-
+               
                void AddAssemblyToCache (string path, Assembly asm)
                {
-                       Cache runtimeCache = HttpRuntime.Cache;
+                       Cache runtimeCache = HttpRuntime.InternalCache;
                        Dictionary <string, Assembly> cache;
                        
                        cache = runtimeCache[cachePrefix] as Dictionary <string, Assembly>;
@@ -228,7 +364,7 @@ namespace System.Web.Compilation
                        return ret;
                }
 
-               bool IsFileCultureValid (string fileName)
+               string IsFileCultureValid (string fileName)
                 {
                     string tmp = Path.GetFileNameWithoutExtension (fileName);
                     tmp = Path.GetExtension (tmp);
@@ -236,27 +372,40 @@ namespace System.Web.Compilation
                               tmp = tmp.Substring (1);
                             try {
                                 CultureInfo.GetCultureInfo (tmp);
-                                return true;
+                                return tmp;
                             } catch {
-                                return false;
+                                return null;
                             }
                     } 
-                    return false;
+                    return null;
                 }
-
-               string GetResourceFile (AppResourceFileInfo arfi, CompilerParameters cp)
+               
+               string GetResourceFile (AppResourceFileInfo arfi, bool local)
                {
                        string resfile;
                        if (arfi.Kind == AppResourceFileKind.ResX)
-                               resfile = CompileResource (arfi);
+                               resfile = CompileResource (arfi, local);
                        else
                                resfile = arfi.Info.FullName;
-                       if (!String.IsNullOrEmpty (resfile))
-                               cp.EmbeddedResources.Add (resfile);
+                       if (!String.IsNullOrEmpty (resfile)) {
+                               string culture = IsFileCultureValid (resfile);
+                               if (culture == null)
+                                       culture = DefaultCultureKey;
+                               
+                               List <string> cfiles;
+                               if (cultureFiles.ContainsKey (culture))
+                                       cfiles = cultureFiles [culture];
+                               else {
+                                       cfiles = new List <string> (1);
+                                       cultureFiles [culture] = cfiles;
+                               }
+                               cfiles.Add (resfile);
+                       }
+                               
                        return resfile;
                }
                
-               List <string>[] GroupGlobalFiles (CompilerParameters cp)
+               List <string>[] GroupGlobalFiles ()
                {
                        List<AppResourceFileInfo> files = this.files.Files;
                        List<List<string>> groups = new List<List<string>> ();
@@ -287,7 +436,7 @@ namespace System.Web.Compilation
                                        filedots = CountChars ('.', tmp);
 
                                        if (filedots == basedots + 1 && tmp.StartsWith (basename)) {
-                                               if (IsFileCultureValid (s2)) {
+                                               if (IsFileCultureValid (s2) != null) {
                                                        // A valid translated file for this name
                                                        defaultFile = arfi;
                                                        break;
@@ -302,7 +451,7 @@ namespace System.Web.Compilation
                                }
                                if (defaultFile != null) {
                                        List<string> al = new List<string> ();
-                                       al.Add (GetResourceFile (arfi, cp));
+                                       al.Add (GetResourceFile (arfi, false));
                                        arfi.Seen = true;
                                        groups.Add (al);
                                        
@@ -315,16 +464,17 @@ namespace System.Web.Compilation
                        foreach (List<string> al in groups) {
                                s = al [0];
                                tmp = Path.GetFileNameWithoutExtension (s);
+                               if (tmp.StartsWith ("Resources."))
+                                       tmp = tmp.Substring (10);
                                foreach (AppResourceFileInfo arfi in files) {
                                        if (arfi.Seen)
                                                continue;
-                                       
                                        s = arfi.Info.FullName;
                                        if (s == null)
                                                continue;
                                        tmp2 = arfi.Info.Name;
                                        if (tmp2.StartsWith (tmp)) {
-                                               al.Add (GetResourceFile (arfi, cp));
+                                               al.Add (GetResourceFile (arfi, false));
                                                arfi.Seen = true;
                                        }
                                }
@@ -336,17 +486,16 @@ namespace System.Web.Compilation
                        // culture or not. If it is not a culture, then we have a
                        // default file that doesn't have any translations. Otherwise,
                        // the file is ignored (it's the same thing MS.NET does)
-                       string fullName;
                        foreach (AppResourceFileInfo arfi in files) {
                                if (arfi.Seen)
                                        continue;
 
-                               if (IsFileCultureValid (arfi.Info.FullName))
+                               if (IsFileCultureValid (arfi.Info.FullName) != null)
                                        continue; // Culture found, we reject the file
 
                                // A single default file, create a group
                                List<string> al = new List<string> ();
-                               al.Add (GetResourceFile (arfi, cp));
+                               al.Add (GetResourceFile (arfi, false));
                                groups.Add (al);
                        }
                        groups.Sort (lcList);
@@ -357,6 +506,9 @@ namespace System.Web.Compilation
                void DomFromResource (string resfile, CodeCompileUnit unit, Dictionary <string,bool> assemblies,
                                      CodeDomProvider provider)
                {
+                       if (String.IsNullOrEmpty (resfile))
+                               return;
+
                        string fname, nsname, classname;
 
                        fname = Path.GetFileNameWithoutExtension (resfile);
@@ -366,24 +518,38 @@ namespace System.Web.Compilation
                                classname = nsname;
                                nsname = "Resources";
                        } else {
-                               nsname = String.Format ("Resources.{0}", nsname);
+                               if (!nsname.StartsWith ("Resources", StringComparison.InvariantCulture))
+                                       nsname = String.Concat ("Resources.", nsname);
                                classname = classname.Substring(1);
                        }
 
+                       if (!String.IsNullOrEmpty (classname))
+                               classname = classname.Replace ('.', '_');
+                       if (!String.IsNullOrEmpty (nsname))
+                               nsname = nsname.Replace ('.', '_');
+                       
                        if (!provider.IsValidIdentifier (nsname) || !provider.IsValidIdentifier (classname))
                                throw new ApplicationException ("Invalid resource file name.");
+
+                       ResourceReader res;
+                       try {
+                               res = new ResourceReader (resfile);
+                       } catch (ArgumentException) {
+                               // invalid stream, probably empty - ignore silently and abort
+                               return;
+                       }
                        
                        CodeNamespace ns = new CodeNamespace (nsname);
                        CodeTypeDeclaration cls = new CodeTypeDeclaration (classname);
                        cls.IsClass = true;
                        cls.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
 
-                       CodeMemberField cmf = new CodeMemberField (typeof(CultureInfo), "culture");
+                       CodeMemberField cmf = new CodeMemberField (typeof(CultureInfo), "_culture");
                        cmf.InitExpression = new CodePrimitiveExpression (null);
                        cmf.Attributes = MemberAttributes.Private | MemberAttributes.Final | MemberAttributes.Static;
                        cls.Members.Add (cmf);
 
-                       cmf = new CodeMemberField (typeof(ResourceManager), "resourceManager");
+                       cmf = new CodeMemberField (typeof(ResourceManager), "_resourceManager");
                        cmf.InitExpression = new CodePrimitiveExpression (null);
                        cmf.Attributes = MemberAttributes.Private | MemberAttributes.Final | MemberAttributes.Static;
                        cls.Members.Add (cmf);
@@ -405,14 +571,13 @@ namespace System.Web.Compilation
                        cmp.HasGet = true;
                        cmp.HasSet = true;
                        cmp.Type = new CodeTypeReference (typeof(CultureInfo));
-                       CodePropertyGenericGet (cmp.GetStatements, "culture", classname);
-                       CodePropertyGenericSet (cmp.SetStatements, "culture", classname);
+                       CodePropertyGenericGet (cmp.GetStatements, "_culture", classname);
+                       CodePropertyGenericSet (cmp.SetStatements, "_culture", classname);
                        cls.Members.Add (cmp);
 
                        // Add the resource properties
                        Dictionary<string,bool> imports = new Dictionary<string,bool> ();
                        try {
-                               ResourceReader res = new ResourceReader (resfile);
                                foreach (DictionaryEntry de in res) {
                                        Type type = de.Value.GetType ();
 
@@ -432,7 +597,7 @@ namespace System.Web.Compilation
                                        cls.Members.Add (cmp);
                                }
                        } catch (Exception ex) {
-                               throw new ApplicationException ("Failed to comipile global resources.", ex);
+                               throw new ApplicationException ("Failed to compile global resources.", ex);
                        }
                        foreach (KeyValuePair<string,bool> de in imports)
                                ns.Imports.Add (new CodeNamespaceImport(de.Key));
@@ -463,7 +628,7 @@ namespace System.Web.Compilation
                        CodeStatement st;
                        CodeExpression exp;
 
-                       exp = new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typename), "resourceManager");
+                       exp = new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typename), "_resourceManager");
                        st = new CodeConditionStatement (
                                new CodeBinaryOperatorExpression (
                                        exp,
@@ -500,7 +665,7 @@ namespace System.Web.Compilation
                                gotstr ? "GetString" : "GetObject",
                                new CodeExpression [] { new CodePrimitiveExpression (resname),
                                                        new CodeFieldReferenceExpression (
-                                                               new CodeTypeReferenceExpression (typename), "culture") });
+                                                               new CodeTypeReferenceExpression (typename), "_culture") });
                        st = new CodeVariableDeclarationStatement (
                                restype,
                                "obj",
@@ -523,11 +688,14 @@ namespace System.Web.Compilation
                                        new CodeVariableReferenceExpression ("value")));
                }
                
-               string CompileResource (AppResourceFileInfo arfi)
+               string CompileResource (AppResourceFileInfo arfi, bool local)
                {
                        string path = arfi.Info.FullName;
-                       string resource = Path.Combine (TempDirectory,
-                                                       Path.GetFileNameWithoutExtension (path) + ".resources");
+                       string rname = Path.GetFileNameWithoutExtension (path) + ".resources";
+                       if (!local)
+                               rname = "Resources." + rname;
+                       
+                       string resource = Path.Combine (TempDirectory, rname);
                        FileStream source = null, destination = null;
                        IResourceReader reader = null;
                        ResourceWriter writer = null;
@@ -535,7 +703,7 @@ namespace System.Web.Compilation
                        try {
                                source = new FileStream (path, FileMode.Open, FileAccess.Read);
                                destination = new FileStream (resource, FileMode.Create, FileAccess.Write);
-                               reader = GetReaderForKind (arfi.Kind, source);
+                               reader = GetReaderForKind (arfi.Kind, source, path);
                                writer = new ResourceWriter (destination);
                                foreach (DictionaryEntry de in reader) {
                                        object val = de.Value;
@@ -560,11 +728,14 @@ namespace System.Web.Compilation
                        return resource;
                }
 
-               IResourceReader GetReaderForKind (AppResourceFileKind kind, Stream stream)
+               IResourceReader GetReaderForKind (AppResourceFileKind kind, Stream stream, string path)
                {
                        switch (kind) {
                                case AppResourceFileKind.ResX:
-                                       return new ResXResourceReader (stream);
+                                       var ret = new ResXResourceReader (stream, new TypeResolutionService ());
+                                       if (!String.IsNullOrEmpty (path))
+                                               ret.BasePath = Path.GetDirectoryName (path);
+                                       return ret;
 
                                case AppResourceFileKind.Resource:
                                        return new ResourceReader (stream);