using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Text;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//OptimizeValues();
var path1 = @"public1.xml";
var path2 = @"public2.xml";
Resolve(path1, path2);
}
static Dictionary<string, string> GetTypeDictionary(List<Resource> resources)
{
var typeDictionary = new Dictionary<string, string>();
for (var i = 0; i < resources.Count; i++)
{
var resource = resources[i];
if (typeDictionary.ContainsKey(resource.type))
continue;
typeDictionary[resource.type] = resource.id.Substring(2, 4);
}
return typeDictionary;
}
static Dictionary<string, string> GetTypeDictionary(List<Resource> resources1, List<Resource> resources2)
{
var typeDictionary1 = GetTypeDictionary(resources1);
var typeDictionary2 = GetTypeDictionary(resources2);
var max = 0;
foreach (var item in typeDictionary1)
{
var id = Int32.Parse(item.Value, NumberStyles.AllowHexSpecifier);
max = Math.Max(max, id);
}
var typeDictionary = new Dictionary<string, string>(typeDictionary1);
foreach(var item in typeDictionary2)
{
if (typeDictionary.ContainsKey(item.Key))
continue;
if (typeDictionary.ContainsValue(item.Value))
{
max++;
typeDictionary[item.Key] = max.ToString("x4");
}
else
{
typeDictionary[item.Key] = item.Value;
var id = Int32.Parse(item.Value, NumberStyles.AllowHexSpecifier);
max = Math.Max(max, id);
}
}
return typeDictionary;
}
static void OptimizeValues(string[] files)
{
foreach (var path in files)
{
var lines = File.ReadAllLines(path);
var contents = "";
foreach (var line in lines)
{
if (!line.Contains("APKTOOL_DUMMY_"))
contents += line + "\n";
}
File.WriteAllText(path, contents);
}
}
static void Resolve(string path1, string path2)
{
var resources1 = XmlUtility.DeserializeXmlFromFile<Resources>(path1).resources;
var resources2 = XmlUtility.DeserializeXmlFromFile<Resources>(path2).resources;
var typeDictionary = GetTypeDictionary(resources1, resources2);
var idDictionary = new Dictionary<string, string>();
for (var i = 0; i < resources2.Count; i++)
{
var resource = resources2[i];
var old_id = resource.id;
var type_id = typeDictionary[resource.type];
resource.id = "0x" + type_id + resource.id.Substring(6);
if (resource.id != old_id)
idDictionary[old_id] = resource.id;
var item = resources1.Find(delegate (Resource r)
{
return r.type == resource.type && r.name == resource.name && r.id == resource.id;
});
if (item != null)//完全相同
continue;
var item1 = resources1.Find(delegate (Resource r)
{
return r.id == resource.id;
});
var item2 = resources1.Find(delegate (Resource r)
{
return r.type == resource.type && r.name == resource.name;
});
if (item1 == null && item2 == null)
continue;
if (item1 != null && item2 == null)//id冲突,重新分配id
{
var id = Int32.Parse(resource.id.Substring(2), NumberStyles.AllowHexSpecifier);
resource.id = "0x" + (id + 0x00007000).ToString("x8");
idDictionary[old_id] = resource.id;
continue;
}
resource.id = item2.id;
idDictionary[old_id] = resource.id;
}
var smaliPath = @"smali";
var files = Directory.GetFiles(smaliPath, "*", SearchOption.AllDirectories);
foreach (var path in files)
{
var contents = File.ReadAllText(path);
var count = 0;
contents = Regex.Replace(contents, "( const v[0-9]+, )(0x7f[0-9a-f]{6})", delegate (Match match)
{
var old_id = match.Groups[2].Value;
var new_id = "";
if (!idDictionary.TryGetValue(old_id, out new_id))
return match.Groups[1].Value + old_id;
count++;
return match.Groups[1].Value + new_id;
});
//R文件常量
contents = Regex.Replace(contents, "(.field public static final [a-zA-Z_][a-zA-Z0-9_]*:I = )(0x7f[0-9a-f]{6})", delegate (Match match)
{
var old_id = match.Groups[2].Value;
var new_id = "";
if (!idDictionary.TryGetValue(old_id, out new_id))
return match.Groups[1].Value + old_id;
count++;
return match.Groups[1].Value + new_id;
});
if (count != 0)
File.WriteAllText(path, contents);
}
var resources = new Resources();
resources.resources = resources2;
XmlUtility.SerializeXmlToFile(path2, resources);
}
}
[XmlType("resources")]
public class Resources
{
[XmlElement("public")]
public List<Resource> resources;
}
public class Resource
{
[XmlAttribute]
public string type;
[XmlAttribute]
public string name;
[XmlAttribute]
public string id;
}
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding
{
get
{
return Encoding.UTF8;
}
}
}
public class XmlUtility
{
public static T DeserializeXml<T>(byte[] bytes)
{
T value = default(T);
try
{
XmlSerializer deserializer = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(bytes))
{
TextReader textReader = new StreamReader(memoryStream);
value = (T)deserializer.Deserialize(textReader);
textReader.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
return value;
}
public static T DeserializeXml<T>(string text)
{
T value = default(T);
try
{
XmlSerializer deserializer = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(text);
value = (T)deserializer.Deserialize(reader);
reader.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
}
return value;
}
public static T DeserializeXmlFromFile<T>(string path)
{
if (!File.Exists(path))
return default(T);
string text = File.ReadAllText(path);
return DeserializeXml<T>(text);
}
public static string SerializeXml(object o)
{
string contents = null;
try
{
XmlSerializer serializer = new XmlSerializer(o.GetType());
using (StringWriter writer = new Utf8StringWriter())
{
serializer.Serialize(writer, o);
contents = writer.ToString();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
return contents;
}
public static void SerializeXmlToFile(string path, object o)
{
if (string.IsNullOrEmpty(path))
return;
string contents = SerializeXml(o);
if (contents != null)
File.WriteAllText(path, contents);
}
}
}
网友评论