Skip to content

Commit 33581a4

Browse files
committed
feat(obfuscator): began works on custom renderer for progress bar + hard dependency requirement
1 parent af42a90 commit 33581a4

File tree

8 files changed

+546
-1
lines changed

8 files changed

+546
-1
lines changed

maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ClassTree.java

+33-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
// so a dfs goes through edges towards the root
2424
public class ClassTree extends FastDirectedGraph<ClassNode, InheritanceEdge> {
2525
private static final Logger LOGGER = Logger.getLogger(ClassTree.class);
26-
private static final boolean ALLOW_PHANTOM_CLASSES = true;
26+
private static final boolean ALLOW_PHANTOM_CLASSES = false;
2727

2828
private final ApplicationClassSource source;
2929
private final ClassNode rootNode;
@@ -45,6 +45,12 @@ protected void init() {
4545
addVertex(node);
4646
}
4747
}
48+
49+
public void verify() {
50+
for (ClassNode node : source.iterateWithLibraries()) {
51+
verifyVertex(node);
52+
}
53+
}
4854

4955
public ClassNode getRootNode() {
5056
return rootNode;
@@ -166,6 +172,32 @@ private ClassNode requestClass0(String name, String from) {
166172
throw new RuntimeException("request from " + from, e);
167173
}
168174
}
175+
176+
public void verifyVertex(ClassNode cn) {
177+
if(cn == null) {
178+
throw new IllegalStateException("Vertex is null!");
179+
}
180+
181+
if (!containsVertex(cn)) {
182+
addVertex(cn);
183+
}
184+
185+
if(cn != rootNode) {
186+
ClassNode sup = cn.node.superName != null
187+
? requestClass0(cn.node.superName, cn.getName())
188+
: rootNode;
189+
if(sup == null) {
190+
throw new IllegalStateException(String.format("No superclass %s for %s", cn.node.superName, cn.getName()));
191+
}
192+
193+
for (String s : cn.node.interfaces) {
194+
ClassNode iface = requestClass0(s, cn.getName());
195+
if(iface == null) {
196+
throw new IllegalStateException(String.format("No superinterface %s for %s", s, cn.getName()));
197+
}
198+
}
199+
}
200+
}
169201

170202
@Override
171203
public boolean addVertex(ClassNode cn) {

obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java

+21
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,27 @@ public void run() {
383383
}
384384
LOGGER.log("Finished importing the JVM!");
385385

386+
/* Checking for errors */
387+
LOGGER.post("Starting verification");
388+
try {
389+
classSource.getClassTree().verify();
390+
} catch (Exception e) {
391+
System.out.println(
392+
"-----------------------------------------------------\n"
393+
+ "/!\\ Skidfuscator failed to compute some libraries!\n"
394+
+ "It it advised to read https://github.com/terminalsin/skidfuscator-java-obfuscator/wiki/Libraries\n"
395+
+ "\n"
396+
+ "Error: " + e.getMessage() + "\n" +
397+
(e.getCause() == null
398+
? "\n"
399+
: " " + e.getCause().getMessage() + "\n"
400+
)
401+
+ "-----------------------------------------------------\n"
402+
);
403+
System.exit(1);
404+
return;
405+
}
406+
386407
/* Resolve context */
387408
LOGGER.post("Resolving basic context...");
388409
this.cxt = new BasicAnalysisContext.BasicContextBuilder()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package dev.skidfuscator.obfuscator.util.progress;
2+
3+
import me.tongfei.progressbar.ProgressBarRenderer;
4+
import me.tongfei.progressbar.ProgressBarStyle;
5+
6+
import java.text.DecimalFormat;
7+
import java.time.Duration;
8+
import java.time.Instant;
9+
import java.time.temporal.ChronoUnit;
10+
11+
import static dev.skidfuscator.obfuscator.util.progress.StringDisplayUtils.getStringDisplayLength;
12+
import static dev.skidfuscator.obfuscator.util.progress.StringDisplayUtils.trimDisplayLength;
13+
14+
/**
15+
* Default progress bar renderer (see {@link ProgressBarRenderer}).
16+
* @author Tongfei Chen
17+
* @author Muhammet Sakarya
18+
* @since 0.8.0
19+
*/
20+
public class SkidProgressBarRenderer {
21+
22+
private ProgressBarStyle style;
23+
private String unitName;
24+
private long unitSize;
25+
private boolean isSpeedShown;
26+
private DecimalFormat speedFormat;
27+
private ChronoUnit speedUnit;
28+
private Spinner<String> values = new Spinner<>(
29+
"⠋",
30+
"⠙",
31+
"⠹",
32+
"⠸",
33+
"⠼",
34+
"⠴",
35+
"⠦",
36+
"⠧",
37+
"⠇",
38+
"⠏"
39+
);
40+
41+
protected SkidProgressBarRenderer(
42+
ProgressBarStyle style,
43+
String unitName,
44+
long unitSize,
45+
boolean isSpeedShown,
46+
DecimalFormat speedFormat,
47+
ChronoUnit speedUnit
48+
) {
49+
this.style = style;
50+
this.unitName = unitName;
51+
this.unitSize = unitSize;
52+
this.isSpeedShown = isSpeedShown;
53+
this.speedFormat = isSpeedShown && speedFormat == null ? new DecimalFormat() : speedFormat;
54+
this.speedUnit = speedUnit;
55+
}
56+
57+
// Number of full blocks
58+
protected int progressIntegralPart(SkidProgressState progress, int length) {
59+
return (int)(progress.getNormalizedProgress() * length);
60+
}
61+
62+
protected int progressFractionalPart(SkidProgressState progress, int length) {
63+
double p = progress.getNormalizedProgress() * length;
64+
double fraction = (p - Math.floor(p)) ;//* style.fractionSymbols.length();
65+
return (int) Math.floor(fraction);
66+
}
67+
68+
protected String eta(SkidProgressState progress, Duration elapsed) {
69+
if (progress.max <= 0 || progress.indefinite) return "?";
70+
else if (progress.current - progress.start == 0) return "?";
71+
else return Util.formatDuration(
72+
elapsed.dividedBy(progress.current - progress.start).multipliedBy(progress.max - progress.current)
73+
);
74+
}
75+
76+
protected String percentage(SkidProgressState progress) {
77+
String res;
78+
if (progress.max <= 0 || progress.indefinite) res = "? %";
79+
else res = String.valueOf((int) Math.floor(100.0 * progress.current / progress.max)) + "%";
80+
return Util.repeat(' ', 4 - res.length()) + res;
81+
}
82+
83+
protected String ratio(SkidProgressState progress) {
84+
String m = progress.indefinite ? "?" : String.valueOf(progress.max / unitSize);
85+
String c = String.valueOf(progress.current / unitSize);
86+
return Util.repeat(' ', m.length() - c.length()) + c + "/" + m + unitName;
87+
}
88+
89+
protected String speed(SkidProgressState progress, Duration elapsed) {
90+
String suffix = "/s";
91+
double elapsedSeconds = elapsed.getSeconds();
92+
double elapsedInUnit = elapsedSeconds;
93+
if (null != speedUnit)
94+
switch (speedUnit) {
95+
case MINUTES:
96+
suffix = "/min";
97+
elapsedInUnit /= 60;
98+
break;
99+
case HOURS:
100+
suffix = "/h";
101+
elapsedInUnit /= (60 * 60);
102+
break;
103+
case DAYS:
104+
suffix = "/d";
105+
elapsedInUnit /= (60 * 60 * 24);
106+
break;
107+
}
108+
109+
if (elapsedSeconds == 0)
110+
return "?" + unitName + suffix;
111+
double speed = (double) (progress.current - progress.start) / elapsedInUnit;
112+
double speedWithUnit = speed / unitSize;
113+
return speedFormat.format(speedWithUnit) + unitName + suffix;
114+
}
115+
116+
public String render(SkidProgressState progress, int maxLength) {
117+
if (maxLength <= 0) {
118+
return "";
119+
}
120+
/*
121+
122+
Instant currTime = Instant.now();
123+
Duration elapsed = Duration.between(progress.startInstant, currTime);
124+
125+
String prefix = progress.taskName + " (" + percentage(progress) + ") " + style.leftBracket;
126+
int prefixLength = getStringDisplayLength(prefix);
127+
128+
if (prefixLength > maxLength) {
129+
prefix = trimDisplayLength(prefix, maxLength - 1);
130+
prefixLength = maxLength - 1;
131+
}
132+
133+
// length of progress should be at least 1
134+
int maxSuffixLength = Math.max(maxLength - prefixLength - 1, 0);
135+
136+
String speedString = isSpeedShown ? speed(progress, elapsed) : "";
137+
String suffix = style.rightBracket + " " + ratio(progress) + " ("
138+
+ Util.formatDuration(elapsed) + " / " + eta(progress, elapsed) + ") "
139+
+ speedString + progress.extraMessage;
140+
int suffixLength = getStringDisplayLength(suffix);
141+
// trim excessive suffix
142+
if (suffixLength > maxSuffixLength) {
143+
suffix = trimDisplayLength(suffix, maxSuffixLength);
144+
suffixLength = maxSuffixLength;
145+
}
146+
147+
int length = maxLength - prefixLength - suffixLength;
148+
149+
StringBuilder sb = new StringBuilder(maxLength);
150+
sb.append(prefix);
151+
152+
// case of indefinite progress bars
153+
if (progress.indefinite) {
154+
int pos = (int)(progress.current % length);
155+
sb.append(Util.repeat(' ', pos));
156+
sb.append(values.next());
157+
sb.append(Util.repeat(' ', length - pos - 1));
158+
}
159+
// case of definite progress bars
160+
else {
161+
sb.append(Util.repeat(style.block, progressIntegralPart(progress, length)));
162+
if (progress.current < progress.max) {
163+
sb.append(style.fractionSymbols.charAt(progressFractionalPart(progress, length)));
164+
sb.append(Util.repeat(style.space, length - progressIntegralPart(progress, length) - 1));
165+
}
166+
}
167+
168+
sb.append(suffix);*/
169+
return null; //sb.toString();
170+
}
171+
172+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package dev.skidfuscator.obfuscator.util.progress;
2+
3+
import java.time.Duration;
4+
import java.time.Instant;
5+
6+
/**
7+
* Encapsulates the internal states of a progress bar.
8+
* @author Tongfei Chen
9+
* @since 0.5.0
10+
*/
11+
class SkidProgressState {
12+
13+
String taskName;
14+
String extraMessage = "";
15+
16+
boolean indefinite = false;
17+
18+
// 0 start current max
19+
// [===============|=========> ]
20+
long start;
21+
long current;
22+
long max;
23+
24+
Instant startInstant = null;
25+
Duration elapsedBeforeStart = Duration.ZERO;
26+
27+
volatile boolean alive = true;
28+
volatile boolean paused = false;
29+
30+
SkidProgressState(String taskName, long initialMax, long startFrom, Duration elapsedBeforeStart) {
31+
this.taskName = taskName;
32+
this.max = initialMax;
33+
if (initialMax < 0) indefinite = true;
34+
this.start = startFrom;
35+
this.current = startFrom;
36+
this.elapsedBeforeStart = elapsedBeforeStart;
37+
this.startInstant = Instant.now();
38+
}
39+
40+
String getTaskName() {
41+
return taskName;
42+
}
43+
44+
synchronized String getExtraMessage() {
45+
return extraMessage;
46+
}
47+
48+
synchronized long getCurrent() {
49+
return current;
50+
}
51+
52+
synchronized long getMax() {
53+
return max;
54+
}
55+
56+
// The progress, normalized to range [0, 1].
57+
synchronized double getNormalizedProgress() {
58+
if (max <= 0) return 0.0;
59+
else if (current > max) return 1.0;
60+
else return ((double)current) / max;
61+
}
62+
63+
synchronized void setAsDefinite() {
64+
indefinite = false;
65+
}
66+
67+
synchronized void setAsIndefinite() {
68+
indefinite = true;
69+
}
70+
71+
synchronized void maxHint(long n) {
72+
max = n;
73+
}
74+
75+
synchronized void stepBy(long n) {
76+
current += n;
77+
if (current > max) max = current;
78+
}
79+
80+
synchronized void stepTo(long n) {
81+
current = n;
82+
if (current > max) max = current;
83+
}
84+
85+
synchronized void setExtraMessage(String msg) {
86+
extraMessage = msg;
87+
}
88+
89+
synchronized void pause() {
90+
paused = true;
91+
start = current;
92+
elapsedBeforeStart = elapsedBeforeStart.plus(Duration.between(startInstant, Instant.now()));
93+
}
94+
95+
synchronized void resume() {
96+
paused = false;
97+
startInstant = Instant.now();
98+
}
99+
100+
synchronized void reset() {
101+
start = 0;
102+
current = 0;
103+
startInstant = Instant.now();
104+
elapsedBeforeStart = Duration.ZERO;
105+
}
106+
107+
synchronized void kill() {
108+
alive = false;
109+
}
110+
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dev.skidfuscator.obfuscator.util.progress;
2+
3+
/**
4+
* @author Ghast
5+
* @since 07/02/2021
6+
* Artemis © 2021
7+
*/
8+
public class Spinner<T> {
9+
private final T[] values;
10+
private int index;
11+
12+
public Spinner(T... values) {
13+
this.values = values;
14+
this.index = 0;
15+
}
16+
17+
public T next() {
18+
return values[index = (++index % values.length)];
19+
}
20+
}

0 commit comments

Comments
 (0)