Skip to content
This repository has been archived by the owner on Feb 15, 2023. It is now read-only.

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
NeunEinser committed Nov 29, 2020
0 parents commit de07c29
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 0 deletions.
146 changes: 146 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@

# Created by https://www.toptal.com/developers/gitignore/api/java,intellij,maven
# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,maven

### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr

# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/

# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml

# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/

# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$

# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar

# End of https://www.toptal.com/developers/gitignore/api/java,intellij,maven
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions namespace to language placeholders.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
140 changes: 140 additions & 0 deletions src/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import java.math.BigInteger;
import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Usage: java -jar <jar file> (encode|decode) <value>");
System.exit(-1);
}

switch (args[0]) {
case "encode" -> encode(args[1]);
case "decode" -> decode(args[1]);
default -> System.err.printf("invalid command %s. Expected either \"encode\" or \"decode\".%n", args[0]);
}

final var namespace = args[0];
}

private static void encode(final String namespace) {
if (!namespace.matches("^[a-z0-9_.-]+$")) {
System.err.printf("invalid namespace %s%n", namespace);
System.exit(-1);
}

final boolean fullCharSet = !namespace.matches("^[a-z_]+$");

BigInteger value = BigInteger.ZERO;
final int base = fullCharSet ? 39 : 27;
final BigInteger multiplier = BigInteger.valueOf(base);

for (char curChar : namespace.toCharArray()) {
//The add one is here to create a consistent offset. In case a namespace starts with 'a', we don't want
// the first digit as 0.
value = value.multiply(multiplier)
.add(BigInteger.valueOf(getCharValue(curChar) + 1));
}

// ceil((value.bitLength() + 1) / 31)
// Int division always floors, but ceil can be expressed with ((n - 1) / m) +1
// Since n = value.bitLength() + 1, the + 1 with the - 1 cancel each other out.
// The + 1 is needed because we use an additional bit to store the value of fullCharSet
final int length = value.bitLength() / 31 + 1;

final int[] placeholders = new int[length];
final BigInteger twoPow31 = BigInteger.valueOf(0x80_00_00_00L);

for (int i = length -1; i >= 0; i--) {
final var divMod = value.divideAndRemainder(twoPow31);

placeholders[i] = divMod[1].intValueExact();
value = divMod[0];

if (i == 0 && fullCharSet) {
placeholders[0] |= 0x40_00_00_00;
}
}

final var result = new StringBuilder();
for (int placeholder : placeholders) {
result.append("%")
.append(Integer.toUnsignedString(placeholder))
.append("$s");
}

System.out.println(result);
}

private static int getCharValue(char c) {
if (c >= 'a') {
return c - 'a';
} else if (c == '_') {
return 26;
} else if (c >= '0') {
return c - '0' + 27;
} else if (c == '-') {
return 37;
} else {
return 38;
}
}

private static void decode(final String encodedNamespace) {
if (!encodedNamespace.matches("^(?:%[1-9][0-9]+\\$s)+$")) {
System.err.printf("invalid encoded namespace %s%n", encodedNamespace);
System.exit(-1);
}

final String trimmed = encodedNamespace.substring(1, encodedNamespace.length() - 2);
final String[] placeholderStrings = trimmed.split("\\$s%");
final int[] placeholders = new int[placeholderStrings.length];

for (int i = 0; i < placeholders.length; i++) {
placeholders[i] = Integer.parseInt(placeholderStrings[i]);
}
boolean fullCharSet = (placeholders[0] & 0x40_00_00_00) > 0;
placeholders[0] &= 0xBF_FF_FF_FF;

final BigInteger twoPow31 = BigInteger.valueOf(0x80_00_00_00L);
BigInteger value = BigInteger.ZERO;

for (int placeholder : placeholders) {
value = value.multiply(twoPow31);
value = value.add(BigInteger.valueOf(placeholder));
}

final int base = fullCharSet ? 39 : 27;
final BigInteger divisor = BigInteger.valueOf(base);
final var characters = new ArrayList<Character>();

while (value.compareTo(BigInteger.ZERO) > 0) {
value = value.subtract(BigInteger.ONE);
final BigInteger[] divMod = value.divideAndRemainder(divisor);

value = divMod[0];
characters.add(getCharFromValue(divMod[1].intValueExact()));
}

final var chars = new char[characters.size()];
for(int i = 0; i < chars.length; i++) {
chars[i] = characters.get(chars.length - i - 1);
}

System.out.println(new String(chars));
}

private static char getCharFromValue(int value) {
if (value < 26) {
return (char) ('a' + value);
} else if (value == 26) {
return '_';
} else if (value < 37) {
return (char) ('0' + value - 27);
} else if (value == 37) {
return '-';
} else {
return '.';
}
}
}

0 comments on commit de07c29

Please sign in to comment.