Skip to content

Instantly share code, notes, and snippets.

@lry127
Created May 3, 2024 10:35
Show Gist options
  • Save lry127/d7096f9217538b33418d1635f18705bf to your computer and use it in GitHub Desktop.
Save lry127/d7096f9217538b33418d1635f18705bf to your computer and use it in GitHub Desktop.
an identifier generator used to generate a lot of confusing identifiers for code obfuscation (e.g. you can use it to generate proguard dictionary)
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Random;
/**
* an identifier generator, each generated value is guaranteed to be unique <br>
* a common use case is to generate a lot of unique sequences like {@code illlllliiilliiiii} when using proguard to obfuscate identifiers <br>
* Usage: {@code java Generator <char 1> <char 2> <eachIdentifierLength (multiple of 64)> <identifierCount> <output file>}
*/
public class Generator {
private final char c1;
private final char c2;
private final int identifierLengthMultiply;
// we need to guarantee the uniqueness of identifier
private final HashSet<Long> generatedValues;
private final Random random;
public Generator(char c1, char c2, int identifierLength) {
if (identifierLength <= 0 || identifierLength % 64 != 0) {
throw new IllegalArgumentException("identifierLength should be a multiple of 64");
}
this.c1 = c1;
this.c2 = c2;
this.identifierLengthMultiply = identifierLength / 64;
generatedValues = new HashSet<>();
random = new Random(System.nanoTime());
}
public static void main(String[] args) {
if (args.length != 5) {
System.err.println("Usage: java Generator <char 1> <char 2> <identifierLength (multiple of 64)> <count> <output file>");
System.err.println("For example: java Generator i l 128 1000000 output.txt");
System.exit(1);
}
char c1 = args[0].charAt(0);
char c2 = args[1].charAt(0);
int identifierLength = Integer.parseInt(args[2]);
long count = Long.parseLong(args[3]);
String outputFile = args[4];
Generator gen = new Generator(c1, c2, identifierLength);
try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outputFile))) {
long startMillis = System.currentTimeMillis();
System.out.println("start generating...");
gen.generate(out, count);
System.out.println("finished generating... time spent: " + (System.currentTimeMillis() - startMillis) + " ms");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void generate(OutputStream out, long generationCount) throws IOException {
for (long i = 0; i < generationCount; i++) {
StringBuilder sb = new StringBuilder();
boolean success = true;
for (long j = 0; j < identifierLengthMultiply; j++) {
long thisRandom = random.nextLong();
if (j == 0) {
if (!generatedValues.add(thisRandom)) {
success = false;
break;
}
}
sb.append(transform(thisRandom));
}
if (success) {
sb.append('\n');
out.write(sb.toString().getBytes(StandardCharsets.UTF_8));
} else {
System.err.println("Generated value caused a hash collision, this should only happen under extremely rare occasion. " + "If you see this message too often, it's a good idea to restart the program and generate a smaller number of identifiers.");
}
}
}
private String transform(long randomNumber) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Long.SIZE; i++) {
if ((randomNumber & (1L << i)) == 0L) {
sb.append(c1);
} else {
sb.append(c2);
}
}
return sb.toString();
}
public void reSeed(long seed) {
random.setSeed(seed);
}
public void reSeed() {
reSeed(System.nanoTime());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment