Skip to content

Commit 1770f1f

Browse files
committed
Add Newtonsoft.Json analyzer
1 parent 2b4f482 commit 1770f1f

3 files changed

Lines changed: 157 additions & 1 deletion

File tree

Confuser.Renamer/AnalyzePhase.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa
6060
void RegisterRenamers(ConfuserContext context, NameService service) {
6161
bool wpf = false,
6262
caliburn = false,
63-
winforms = false;
63+
winforms = false,
64+
json = false;
6465

6566
foreach (var module in context.Modules)
6667
foreach (var asmRef in module.GetAssemblyRefs()) {
@@ -74,6 +75,9 @@ void RegisterRenamers(ConfuserContext context, NameService service) {
7475
else if (asmRef.Name == "System.Windows.Forms") {
7576
winforms = true;
7677
}
78+
else if (asmRef.Name == "Newtonsoft.Json") {
79+
json = true;
80+
}
7781
}
7882

7983
if (wpf) {
@@ -91,6 +95,12 @@ void RegisterRenamers(ConfuserContext context, NameService service) {
9195
context.Logger.Debug("WinForms found, enabling compatibility.");
9296
service.Renamers.Add(winformsAnalyzer);
9397
}
98+
99+
if (json) {
100+
var jsonAnalyzer = new JsonAnalyzer();
101+
context.Logger.Debug("Newtonsoft.Json found, enabling compatibility.");
102+
service.Renamers.Add(jsonAnalyzer);
103+
}
94104
}
95105

96106
internal void Analyze(NameService service, ConfuserContext context, ProtectionParameters parameters, IDnlibDef def, bool runAnalyzer) {
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Confuser.Core;
4+
using Confuser.Renamer.BAML;
5+
using dnlib.DotNet;
6+
7+
namespace Confuser.Renamer.Analyzers {
8+
internal class JsonAnalyzer : IRenamer {
9+
public JsonAnalyzer() {
10+
}
11+
12+
const string JsonProperty = "Newtonsoft.Json.JsonPropertyAttribute";
13+
const string JsonIgnore = "Newtonsoft.Json.JsonIgnoreAttribute";
14+
const string JsonObject = "Newtonsoft.Json.JsonObjectAttribute";
15+
static readonly HashSet<string> JsonContainers = new HashSet<string> {
16+
"Newtonsoft.Json.JsonArrayAttribute",
17+
"Newtonsoft.Json.JsonContainerAttribute",
18+
"Newtonsoft.Json.JsonDictionaryAttribute",
19+
"Newtonsoft.Json.JsonObjectAttribute"
20+
};
21+
22+
static CustomAttribute GetJsonContainerAttribute(IHasCustomAttribute attrs) {
23+
foreach (var attr in attrs.CustomAttributes) {
24+
if (JsonContainers.Contains(attr.TypeFullName))
25+
return attr;
26+
}
27+
return null;
28+
}
29+
30+
static bool ShouldExclude(TypeDef type, IDnlibDef def) {
31+
CustomAttribute attr;
32+
33+
if (def.CustomAttributes.IsDefined(JsonProperty)) {
34+
attr = def.CustomAttributes.Find(JsonProperty);
35+
if (attr.HasConstructorArguments || attr.GetProperty("PropertyName") != null)
36+
return false;
37+
}
38+
39+
attr = GetJsonContainerAttribute(type);
40+
if (attr == null || attr.TypeFullName != JsonObject)
41+
return false;
42+
43+
if (def.CustomAttributes.IsDefined(JsonIgnore))
44+
return false;
45+
46+
int serialization = 0;
47+
if (attr.HasConstructorArguments && attr.ConstructorArguments[0].Type.FullName == "Newtonsoft.Json.MemberSerialization")
48+
serialization = (int)attr.ConstructorArguments[0].Value;
49+
else {
50+
foreach (var property in attr.Properties) {
51+
if (property.Name == "MemberSerialization")
52+
serialization = (int)property.Value;
53+
}
54+
}
55+
56+
if (serialization == 0) { // OptOut
57+
return (def is PropertyDef && ((PropertyDef)def).IsPublic()) ||
58+
(def is FieldDef && ((FieldDef)def).IsPublic);
59+
}
60+
else if (serialization == 1) // OptIn
61+
return false;
62+
else if (serialization == 2) // Fields
63+
return def is FieldDef;
64+
else // Unknown
65+
return false;
66+
}
67+
68+
public void Analyze(ConfuserContext context, INameService service, ProtectionParameters parameters, IDnlibDef def) {
69+
if (def is TypeDef)
70+
Analyze(context, service, (TypeDef)def, parameters);
71+
else if (def is MethodDef)
72+
Analyze(context, service, (MethodDef)def, parameters);
73+
else if (def is PropertyDef)
74+
Analyze(context, service, (PropertyDef)def, parameters);
75+
else if (def is FieldDef)
76+
Analyze(context, service, (FieldDef)def, parameters);
77+
}
78+
79+
void Analyze(ConfuserContext context, INameService service, TypeDef type, ProtectionParameters parameters) {
80+
var attr = GetJsonContainerAttribute(type);
81+
if (attr == null)
82+
return;
83+
84+
bool hasId = false;
85+
if (attr.HasConstructorArguments && attr.ConstructorArguments[0].Type.FullName == "System.String")
86+
hasId = true;
87+
else {
88+
foreach (var property in attr.Properties) {
89+
if (property.Name == "Id")
90+
hasId = true;
91+
}
92+
}
93+
if (!hasId)
94+
service.SetCanRename(type, false);
95+
}
96+
97+
void Analyze(ConfuserContext context, INameService service, MethodDef method, ProtectionParameters parameters) {
98+
if (GetJsonContainerAttribute(method.DeclaringType) != null && method.IsConstructor) {
99+
service.SetParam(method, "renameArgs", "false");
100+
}
101+
}
102+
103+
void Analyze(ConfuserContext context, INameService service, PropertyDef property, ProtectionParameters parameters) {
104+
if (ShouldExclude(property.DeclaringType, property)) {
105+
service.SetCanRename(property, false);
106+
}
107+
}
108+
109+
void Analyze(ConfuserContext context, INameService service, FieldDef field, ProtectionParameters parameters) {
110+
if (ShouldExclude(field.DeclaringType, field)) {
111+
service.SetCanRename(field, false);
112+
}
113+
}
114+
115+
public void PreRename(ConfuserContext context, INameService service, ProtectionParameters parameters, IDnlibDef def) {
116+
//
117+
}
118+
119+
public void PostRename(ConfuserContext context, INameService service, ProtectionParameters parameters, IDnlibDef def) {
120+
//
121+
}
122+
}
123+
}

Confuser.Renamer/NameService.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public interface INameService {
1616
bool CanRename(object obj);
1717
void SetCanRename(object obj, bool val);
1818

19+
void SetParam(IDnlibDef def, string name, string value);
20+
string GetParam(IDnlibDef def, string name);
21+
1922
RenameMode GetRenameMode(object obj);
2023
void SetRenameMode(object obj, RenameMode val);
2124
void ReduceRenameMode(object obj, RenameMode val);
@@ -92,6 +95,26 @@ public void SetCanRename(object obj, bool val) {
9295
context.Annotations.Set(obj, CanRenameKey, val);
9396
}
9497

98+
public void SetParam(IDnlibDef def, string name, string value) {
99+
var param = ProtectionParameters.GetParameters(context, def);
100+
if (param == null)
101+
ProtectionParameters.SetParameters(context, def, param = new ProtectionSettings());
102+
Dictionary<string, string> nameParam;
103+
if (!param.TryGetValue(analyze.Parent, out nameParam))
104+
param[analyze.Parent] = nameParam = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
105+
nameParam[name] = value;
106+
}
107+
108+
public string GetParam(IDnlibDef def, string name) {
109+
var param = ProtectionParameters.GetParameters(context, def);
110+
if (param == null)
111+
return null;
112+
Dictionary<string, string> nameParam;
113+
if (!param.TryGetValue(analyze.Parent, out nameParam))
114+
return null;
115+
return nameParam.GetValueOrDefault(name);
116+
}
117+
95118
public RenameMode GetRenameMode(object obj) {
96119
return context.Annotations.Get(obj, RenameModeKey, RenameMode.Unicode);
97120
}

0 commit comments

Comments
 (0)