-
Notifications
You must be signed in to change notification settings - Fork 528
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a2705db
commit d702b62
Showing
8 changed files
with
373 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright (C) 2022 Microsoft Ltd, Inc. All rights reserved. | ||
using System; | ||
using System.CodeDom; | ||
using System.CodeDom.Compiler; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using Microsoft.Build.Framework; | ||
using Microsoft.Build.Utilities; | ||
using Microsoft.Android.Build.Tasks; | ||
|
||
namespace Xamarin.Android.Tasks | ||
{ | ||
public class GenerateRtxt : AndroidTask | ||
{ | ||
public override string TaskPrefix => "GR"; | ||
|
||
public string RTxtFile { get; set; } | ||
|
||
[Required] | ||
public string ResourceDirectory { get; set; } | ||
|
||
public string[] AdditionalResourceDirectories { get; set; } | ||
|
||
public string JavaPlatformJarPath { get; set; } | ||
|
||
public string CaseMapFile { get; set; } | ||
|
||
public override bool RunTask () | ||
{ | ||
// Parse the Resource files and then generate an R.txt file | ||
var writer = new RtxtWriter (); | ||
|
||
var resource_fixup = MonoAndroidHelper.LoadMapFile (BuildEngine4, CaseMapFile, StringComparer.OrdinalIgnoreCase); | ||
|
||
var javaPlatformDirectory = Path.GetDirectoryName (JavaPlatformJarPath); | ||
var parser = new FileResourceParser () { Log = Log, JavaPlatformDirectory = javaPlatformDirectory, ResourceFlagFile = ResourceFlagFile}; | ||
var resources = parser.Parse (ResourceDirectory, AdditionalResourceDirectories, resource_fixup); | ||
|
||
writer.Write (RTxtFile, resources); | ||
|
||
return !Log.HasLoggedErrors; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
219 changes: 219 additions & 0 deletions
219
src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
using System; | ||
using System.CodeDom; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Xml; | ||
using System.Xml.Linq; | ||
using System.Xml.XPath; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
using Microsoft.Build.Utilities; | ||
using Microsoft.Android.Build.Tasks; | ||
|
||
namespace Xamarin.Android.Tasks | ||
{ | ||
class FileResourceParser : ResourceParser | ||
{ | ||
Dictionary<R, R []> arrayMapping = new Dictionary<R, R []> (); | ||
public Dictionary<string, R> Parse (string resourceDirectory, IEnumerable<string> additionalResourceDirectories, Dictionary<string, string> resourceMap) | ||
{ | ||
Log.LogDebugMessage ($"Processing Directory {resourceDirectory}"); | ||
var result = new Dictionary<string, R> (); | ||
Dictionary<string, SortedSet<R>> resources = new Dictionary<string, SortedSet<R>> (); | ||
foreach (var dir in Directory.EnumerateDirectories (resourceDirectory, "*", SearchOption.TopDirectoryOnly)) { | ||
foreach (var file in Directory.EnumerateFiles (dir, "*.*", SearchOption.AllDirectories)) { | ||
ProcessResourceFile (file, resources); | ||
} | ||
} | ||
if (additionalResourceDirectories != null) { | ||
foreach (var dir in additionalResourceDirectories) { | ||
Log.LogDebugMessage ($"Processing Directory {dir}"); | ||
if (Directory.Exists (dir)) { | ||
foreach (var file in Directory.EnumerateFiles (dir, "*.*", SearchOption.AllDirectories)) { | ||
ProcessResourceFile (file, resources); | ||
} | ||
} else { | ||
Log.LogDebugMessage ($"Skipping non-existent directory: {dir}"); | ||
} | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
void ProcessResourceFile (string file, Dictionary<string, SortedSet<R>> resources) | ||
{ | ||
var fileName = Path.GetFileNameWithoutExtension (file); | ||
if (string.IsNullOrEmpty (fileName)) | ||
return; | ||
if (fileName.EndsWith (".9", StringComparison.OrdinalIgnoreCase)) | ||
fileName = Path.GetFileNameWithoutExtension (fileName); | ||
var path = Directory.GetParent (file).Name; | ||
var ext = Path.GetExtension (file); | ||
switch (ext) { | ||
case ".xml": | ||
case ".axml": | ||
if (string.Compare (path, "raw", StringComparison.OrdinalIgnoreCase) == 0) | ||
goto default; | ||
try { | ||
ProcessXmlFile (file, resources); | ||
} catch (XmlException ex) { | ||
Log.LogCodedWarning ("XA1000", Properties.Resources.XA1000, file, ex); | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
if (!resources.ContainsKey (path)) | ||
resources[path] = new SortedSet<R>(); | ||
var r = new R () { | ||
ResourceTypeName = path, | ||
Identifier = fileName, | ||
Id = -1, | ||
}; | ||
resources[path].Add (r); | ||
} | ||
|
||
void ProcessStyleable (XmlReader reader, Dictionary<string, SortedSet<R>> resources) | ||
{ | ||
string topName = null; | ||
int fieldCount = 0; | ||
List<R> fields = new List<R> (); | ||
List<string> attribs = new List<string> (); | ||
while (reader.Read ()) { | ||
if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) | ||
continue; | ||
string name = null; | ||
if (string.IsNullOrEmpty (topName)) { | ||
if (reader.HasAttributes) { | ||
while (reader.MoveToNextAttribute ()) { | ||
if (reader.Name.Replace ("android:", "") == "name") | ||
topName = reader.Value; | ||
} | ||
} | ||
} | ||
if (!reader.IsStartElement () || reader.LocalName == "declare-styleable") | ||
continue; | ||
if (reader.HasAttributes) { | ||
while (reader.MoveToNextAttribute ()) { | ||
if (reader.Name.Replace ("android:", "") == "name") | ||
name = reader.Value; | ||
} | ||
} | ||
reader.MoveToElement (); | ||
if (reader.LocalName == "attr") { | ||
attribs.Add (name); | ||
} else { | ||
if (name != null) { | ||
var r = new R () { | ||
ResourceTypeName = "id", | ||
Identifier = name, | ||
Id = -1, | ||
}; | ||
resources [r.ResourceTypeName].Add (r); | ||
} | ||
} | ||
} | ||
var field = new R () { | ||
ResourceTypeName = "styleable", | ||
Identifier = topName, | ||
Type = RType.Array, | ||
}; | ||
if (!arrayMapping.ContainsKey (field)) { | ||
attribs.Sort (StringComparer.OrdinalIgnoreCase); | ||
for (int i = 0; i < attribs.Count; i++) { | ||
string name = attribs [i]; | ||
if (!name.StartsWith ("android:", StringComparison.OrdinalIgnoreCase)) { | ||
var r = new R () { | ||
ResourceTypeName = "attrib", | ||
Identifier = name, | ||
Id = -1, | ||
}; | ||
resources [r.ResourceTypeName].Add (r); | ||
fields.Add (r); | ||
} else { | ||
// this is an android:xxx resource, we should not calculate the id | ||
// we should get it from "somewhere" maybe the pubic.xml | ||
var r = new R () { | ||
ResourceTypeName = "attrib", | ||
Identifier = name, | ||
Id = 0, | ||
}; | ||
fields.Add (r); | ||
} | ||
} | ||
if (field.Type != RType.Array) | ||
return; | ||
arrayMapping.Add (field, fields.ToArray ()); | ||
} | ||
} | ||
|
||
void ProcessXmlFile (string file, Dictionary<string, SortedSet<R>> resources) | ||
{ | ||
using (var reader = XmlReader.Create (file)) { | ||
while (reader.Read ()) { | ||
if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) | ||
continue; | ||
if (reader.IsStartElement ()) { | ||
var elementName = reader.Name; | ||
if (reader.HasAttributes) { | ||
string name = null; | ||
string type = null; | ||
string id = null; | ||
string custom_id = null; | ||
while (reader.MoveToNextAttribute ()) { | ||
if (reader.LocalName == "name") | ||
name = reader.Value; | ||
if (reader.LocalName == "type") | ||
type = reader.Value; | ||
if (reader.LocalName == "id") { | ||
string[] values = reader.Value.Split ('/'); | ||
if (values.Length != 2) { | ||
id = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); | ||
} else { | ||
if (values [0] != "@+id" && values [0] != "@id" && !values [0].Contains ("android:")) { | ||
custom_id = values [0].Replace ("@", "").Replace ("+", ""); | ||
} | ||
id = values [1]; | ||
} | ||
|
||
} | ||
if (reader.LocalName == "inflatedId") { | ||
string inflateId = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); | ||
var r = new R () { | ||
ResourceTypeName = "id", | ||
Identifier = inflateId, | ||
Id = -1, | ||
}; | ||
resources[r.ResourceTypeName].Add (r); | ||
} | ||
} | ||
if (name?.Contains ("android:") ?? false) | ||
continue; | ||
if (id?.Contains ("android:") ?? false) | ||
continue; | ||
// Move the reader back to the element node. | ||
reader.MoveToElement (); | ||
//if (!string.IsNullOrEmpty (name)) | ||
//CreateResourceField (type ?? elementName, name, reader.ReadSubtree ()); | ||
//if (!string.IsNullOrEmpty (custom_id) && !custom_types.TryGetValue (custom_id, out customClass)) { | ||
//customClass = CreateClass (custom_id); | ||
//custom_types.Add (custom_id, customClass); | ||
//} | ||
if (!string.IsNullOrEmpty (id)) { | ||
//CreateIntField (customClass ?? ids, id); | ||
var r = new R () { | ||
ResourceTypeName = custom_id ?? "id", | ||
Identifier = id, | ||
Id = -1, | ||
}; | ||
resources[r.ResourceTypeName].Add (r); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.