mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-01 10:56:42 +00:00
Remove CUI and other cleaning
This commit is contained in:
@ -9,7 +9,6 @@ import com.boydti.fawe.regions.general.plot.PlotSquaredFeature;
|
||||
import com.boydti.fawe.util.*;
|
||||
import com.boydti.fawe.util.chat.ChatManager;
|
||||
import com.boydti.fawe.util.chat.PlainChatManager;
|
||||
import com.boydti.fawe.util.cui.CUI;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
@ -199,25 +198,6 @@ public class Fawe {
|
||||
public void onDisable() {
|
||||
}
|
||||
|
||||
public CUI getCUI(Actor actor) {
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(actor);
|
||||
CUI cui = fp.getMeta("CUI");
|
||||
if (cui == null) {
|
||||
cui = Fawe.imp().getCUI(fp);
|
||||
if (cui != null) {
|
||||
synchronized (fp) {
|
||||
CUI tmp = fp.getMeta("CUI");
|
||||
if (tmp == null) {
|
||||
fp.setMeta("CUI", cui);
|
||||
} else {
|
||||
cui = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cui;
|
||||
}
|
||||
|
||||
public ChatManager getChatManager() {
|
||||
return chatManager;
|
||||
}
|
||||
@ -315,11 +295,10 @@ public class Fawe {
|
||||
Settings.IMP.PLATFORM = IMP.getPlatform().replace("\"", "");
|
||||
try (InputStream stream = getClass().getResourceAsStream("/fawe.properties");
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
|
||||
// java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A");
|
||||
String versionString = br.readLine();
|
||||
String commitString = br.readLine();
|
||||
String dateString = br.readLine();
|
||||
// scanner.close();
|
||||
br.close();
|
||||
this.version = FaweVersion.tryParse(versionString, commitString, dateString);
|
||||
Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toGMTString();
|
||||
Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-Breaking/" + version.build;
|
||||
@ -381,7 +360,7 @@ public class Fawe {
|
||||
try {
|
||||
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
|
||||
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
|
||||
boolean x86OS = arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64") ? false : true;
|
||||
boolean x86OS = !arch.endsWith("64") && (wow64Arch == null || !wow64Arch.endsWith("64"));
|
||||
boolean x86JVM = System.getProperty("sun.arch.data.model").equals("32");
|
||||
if (x86OS != x86JVM) {
|
||||
debug("====== UPGRADE TO 64-BIT JAVA ======");
|
||||
|
@ -5,7 +5,6 @@ import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.cui.CUI;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
@ -36,12 +35,8 @@ public interface IFawe {
|
||||
|
||||
void startMetrics();
|
||||
|
||||
default CUI getCUI(FawePlayer player) { return null; }
|
||||
|
||||
default ImageViewer getImageViewer(FawePlayer player) { return null; }
|
||||
|
||||
default void registerPacketListener() {}
|
||||
|
||||
default int getPlayerCount() {
|
||||
return Fawe.get().getCachedPlayers().size();
|
||||
}
|
||||
|
@ -65,12 +65,9 @@ public class PlotLoader {
|
||||
area.setMeta("lastPlot", new PlotId(0, 0));
|
||||
}
|
||||
PlotId lastId = (PlotId) area.getMeta("lastPlot");
|
||||
while (true) {
|
||||
do {
|
||||
lastId = Auto.getNextPlotId(lastId, 1);
|
||||
if (area.canClaim(player, lastId, lastId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!area.canClaim(player, lastId, lastId));
|
||||
area.setMeta("lastPlot", lastId);
|
||||
this.value = area.getPlot(lastId);
|
||||
this.value.setOwner(player.getUUID());
|
||||
|
@ -339,11 +339,6 @@ public class Settings extends Config {
|
||||
"Allows brushes to be persistent (default: true)",
|
||||
})
|
||||
public boolean PERSISTENT_BRUSHES = true;
|
||||
@Comment({
|
||||
"[SAFE] Enable CUI without needing the mod installed (Requires ProtocolLib)",
|
||||
})
|
||||
public boolean VANILLA_CUI = false;
|
||||
|
||||
|
||||
@Comment({
|
||||
"Disable using native libraries",
|
||||
@ -502,4 +497,4 @@ public class Settings extends Config {
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,19 +37,14 @@ import javax.swing.border.EmptyBorder;
|
||||
|
||||
public class InstallerFrame extends JFrame {
|
||||
private final InvisiblePanel loggerPanel;
|
||||
private Color LIGHT_GRAY = new Color(0x66, 0x66, 0x66);
|
||||
private Color GRAY = new Color(0x44, 0x44, 0x46);
|
||||
private Color DARK_GRAY = new Color(0x33, 0x33, 0x36);
|
||||
private Color DARKER_GRAY = new Color(0x26, 0x26, 0x28);
|
||||
private Color DARKER_GRAY;
|
||||
private Color INVISIBLE = new Color(0, 0, 0, 0);
|
||||
private Color OFF_WHITE = new Color(200, 200, 200);
|
||||
|
||||
private JTextArea loggerTextArea;
|
||||
private BrowseButton browse;
|
||||
|
||||
public InstallerFrame() throws Exception {
|
||||
final MovablePanel movable = new MovablePanel(this);
|
||||
|
||||
Container content = this.getContentPane();
|
||||
content.add(movable);
|
||||
this.setSize(480, 320);
|
||||
@ -61,117 +56,109 @@ public class InstallerFrame extends JFrame {
|
||||
this.setLocation(x, y);
|
||||
this.setVisible(true);
|
||||
this.setOpacity(0);
|
||||
movable.setBackground(DARK_GRAY);
|
||||
movable.setBackground(Color.darkGray);
|
||||
movable.setLayout(new BorderLayout());
|
||||
|
||||
fadeIn();
|
||||
|
||||
JPanel topBar = new InvisiblePanel(new BorderLayout());
|
||||
{
|
||||
JPanel topBarLeft = new InvisiblePanel();
|
||||
JPanel topBarRight = new InvisiblePanel();
|
||||
JPanel topBarLeft = new InvisiblePanel();
|
||||
JPanel topBarRight = new InvisiblePanel();
|
||||
|
||||
JLabel title = new JLabel("FastAsyncWorldEdit Installer");
|
||||
title.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
title.setAlignmentX(Component.RIGHT_ALIGNMENT);
|
||||
title.setForeground(LIGHT_GRAY);
|
||||
JLabel title = new JLabel("FastAsyncWorldEdit Installer");
|
||||
title.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
title.setAlignmentX(Component.RIGHT_ALIGNMENT);
|
||||
title.setForeground(Color.lightGray);
|
||||
|
||||
MinimizeButton minimize = new MinimizeButton(this);
|
||||
CloseButton exit = new CloseButton();
|
||||
MinimizeButton minimize = new MinimizeButton(this);
|
||||
CloseButton exit = new CloseButton();
|
||||
|
||||
topBarLeft.add(title);
|
||||
topBarRight.add(minimize);
|
||||
topBarRight.add(exit);
|
||||
topBarLeft.add(title);
|
||||
topBarRight.add(minimize);
|
||||
topBarRight.add(exit);
|
||||
|
||||
topBar.add(topBarLeft, BorderLayout.CENTER);
|
||||
topBar.add(topBarRight, BorderLayout.EAST);
|
||||
}
|
||||
topBar.add(topBarLeft, BorderLayout.CENTER);
|
||||
topBar.add(topBarRight, BorderLayout.EAST);
|
||||
final JPanel mainContent = new InvisiblePanel(new BorderLayout());
|
||||
{
|
||||
final JPanel browseContent = new InvisiblePanel(new BorderLayout());
|
||||
File dir = MainUtil.getWorkingDirectory("minecraft");
|
||||
JLabel folder = new JLabel("Folder: ");
|
||||
folder.setForeground(OFF_WHITE);
|
||||
final InteractiveButton text = new InteractiveButton(dir.getPath(), DARKER_GRAY) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
browse.actionPerformed(e);
|
||||
}
|
||||
};
|
||||
text.setForeground(OFF_WHITE);
|
||||
text.setBackground(DARKER_GRAY);
|
||||
text.setOpaque(true);
|
||||
text.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||
browse = new BrowseButton("") {
|
||||
@Override
|
||||
public void onSelect(File folder) {
|
||||
text.setText(folder.getPath());
|
||||
movable.repaint();
|
||||
}
|
||||
};
|
||||
InteractiveButton install = new InteractiveButton(">> Create Profile <<", DARKER_GRAY) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
install(text.getText());
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
browseContent.add(folder, BorderLayout.WEST);
|
||||
browseContent.add(text, BorderLayout.CENTER);
|
||||
browseContent.add(browse, BorderLayout.EAST);
|
||||
final JPanel installContent = new InvisiblePanel(new FlowLayout());
|
||||
install.setPreferredSize(new Dimension(416, 32));
|
||||
installContent.add(install);
|
||||
installContent.setBorder(new EmptyBorder(10, 0, 10, 0));
|
||||
this.loggerPanel = new InvisiblePanel(new BorderLayout());
|
||||
this.loggerPanel.setBackground(Color.GREEN);
|
||||
loggerPanel.setPreferredSize(new Dimension(416, 160));
|
||||
loggerTextArea = new JTextArea(12, 52);
|
||||
loggerTextArea.setBackground(GRAY);
|
||||
loggerTextArea.setForeground(DARKER_GRAY);
|
||||
loggerTextArea.setFont(new Font(loggerTextArea.getFont().getName(), Font.PLAIN, 9));
|
||||
JScrollPane scroll = new JScrollPane(loggerTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scroll.setBackground(DARK_GRAY);
|
||||
scroll.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
loggerPanel.add(scroll);
|
||||
loggerPanel.setVisible(false);
|
||||
|
||||
mainContent.setBorder(new EmptyBorder(6, 32, 6, 32));
|
||||
mainContent.add(browseContent, BorderLayout.NORTH);
|
||||
mainContent.add(installContent, BorderLayout.CENTER);
|
||||
mainContent.add(loggerPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
JPanel bottomBar = new InvisiblePanel();
|
||||
{
|
||||
try {
|
||||
InputStream stream = getClass().getResourceAsStream("/fawe.properties");
|
||||
java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A");
|
||||
String versionString = scanner.next().trim();
|
||||
scanner.close();
|
||||
FaweVersion version = null;
|
||||
String date = new Date(100 + version.year, version.month, version.day).toGMTString();
|
||||
String build = "https://ci.athion.net/job/FastAsyncWorldEdit/" + version.build;
|
||||
String commit = "https://github.com/boy0001/FastAsyncWorldedit/commit/" + Integer.toHexString(version.hash);
|
||||
String footerMessage = "FAWE v" + version.year + "." + version.month + "." + version.day + " by Empire92 (c) 2017 (GPL v3.0)";
|
||||
URL licenseUrl = new URL("https://github.com/boy0001/FastAsyncWorldedit/blob/master/LICENSE");
|
||||
URLButton licenseButton = new URLButton(licenseUrl, footerMessage);
|
||||
bottomBar.add(licenseButton);
|
||||
} catch (Throwable ignore) {
|
||||
ignore.printStackTrace();
|
||||
DARKER_GRAY = new Color(0x26, 0x26, 0x28);
|
||||
final JPanel browseContent = new InvisiblePanel(new BorderLayout());
|
||||
File dir = MainUtil.getWorkingDirectory("minecraft");
|
||||
JLabel folder = new JLabel("Folder: ");
|
||||
folder.setForeground(Color.white);
|
||||
final InteractiveButton text = new InteractiveButton(dir.getPath(), DARKER_GRAY) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
browse.actionPerformed(e);
|
||||
}
|
||||
URL chat = new URL("https://discord.gg/ngZCzbU");
|
||||
URLButton chatButton = new URLButton(chat, "Chat");
|
||||
bottomBar.add(chatButton);
|
||||
URL wiki = new URL("https://github.com/boy0001/FastAsyncWorldedit/wiki");
|
||||
URLButton wikiButton = new URLButton(wiki, "Wiki");
|
||||
bottomBar.add(wikiButton);
|
||||
URL issue = new URL("https://github.com/boy0001/FastAsyncWorldedit/issues/new");
|
||||
URLButton issueButton = new URLButton(issue, "Report Issue");
|
||||
bottomBar.add(issueButton);
|
||||
};
|
||||
text.setForeground(Color.white);
|
||||
text.setBackground(DARKER_GRAY);
|
||||
text.setOpaque(true);
|
||||
text.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||
browse = new BrowseButton("") {
|
||||
@Override
|
||||
public void onSelect(File folder) {
|
||||
text.setText(folder.getPath());
|
||||
movable.repaint();
|
||||
}
|
||||
};
|
||||
InteractiveButton install = new InteractiveButton(">> Create Profile <<", DARKER_GRAY) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
install(text.getText());
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
browseContent.add(folder, BorderLayout.WEST);
|
||||
browseContent.add(text, BorderLayout.CENTER);
|
||||
browseContent.add(browse, BorderLayout.EAST);
|
||||
final JPanel installContent = new InvisiblePanel(new FlowLayout());
|
||||
install.setPreferredSize(new Dimension(416, 32));
|
||||
installContent.add(install);
|
||||
installContent.setBorder(new EmptyBorder(10, 0, 10, 0));
|
||||
this.loggerPanel = new InvisiblePanel(new BorderLayout());
|
||||
this.loggerPanel.setBackground(Color.GREEN);
|
||||
loggerPanel.setPreferredSize(new Dimension(416, 160));
|
||||
loggerTextArea = new JTextArea(12, 52);
|
||||
Color GRAY = new Color(0x44, 0x44, 0x46);
|
||||
loggerTextArea.setBackground(GRAY);
|
||||
loggerTextArea.setForeground(DARKER_GRAY);
|
||||
loggerTextArea.setFont(new Font(loggerTextArea.getFont().getName(), Font.PLAIN, 9));
|
||||
JScrollPane scroll = new JScrollPane(loggerTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scroll.setBackground(Color.darkGray);
|
||||
scroll.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
loggerPanel.add(scroll);
|
||||
loggerPanel.setVisible(false);
|
||||
|
||||
mainContent.setBorder(new EmptyBorder(6, 32, 6, 32));
|
||||
mainContent.add(browseContent, BorderLayout.NORTH);
|
||||
mainContent.add(installContent, BorderLayout.CENTER);
|
||||
mainContent.add(loggerPanel, BorderLayout.SOUTH);
|
||||
JPanel bottomBar = new InvisiblePanel();
|
||||
try {
|
||||
FaweVersion version = null;
|
||||
String date = new Date(100 + version.year, version.month, version.day).toGMTString();
|
||||
String build = "https://ci.athion.net/job/FastAsyncWorldEdit/" + version.build;
|
||||
String commit = "https://github.com/boy0001/FastAsyncWorldedit/commit/" + Integer.toHexString(version.hash);
|
||||
String footerMessage = "FAWE v" + version.year + "." + version.month + "." + version.day + " by Empire92 (c) 2017 (GPL v3.0)";
|
||||
URL licenseUrl = new URL("https://github.com/boy0001/FastAsyncWorldedit/blob/master/LICENSE");
|
||||
URLButton licenseButton = new URLButton(licenseUrl, footerMessage);
|
||||
bottomBar.add(licenseButton);
|
||||
} catch (Throwable ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
URL chat = new URL("https://discord.gg/ngZCzbU");
|
||||
URLButton chatButton = new URLButton(chat, "Chat");
|
||||
bottomBar.add(chatButton);
|
||||
URL wiki = new URL("https://github.com/boy0001/FastAsyncWorldedit/wiki");
|
||||
URLButton wikiButton = new URLButton(wiki, "Wiki");
|
||||
bottomBar.add(wikiButton);
|
||||
URL issue = new URL("https://github.com/boy0001/FastAsyncWorldedit/issues/new");
|
||||
URLButton issueButton = new URLButton(issue, "Report Issue");
|
||||
bottomBar.add(issueButton);
|
||||
|
||||
// We want to add these a bit later
|
||||
movable.add(topBar, BorderLayout.NORTH);
|
||||
@ -214,140 +201,134 @@ public class InstallerFrame extends JFrame {
|
||||
prompt("You must select a folder, not a file");
|
||||
return;
|
||||
}
|
||||
Thread installThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<String> supported = Arrays.asList("v1710", "v189", "v194", "v110", "v111");
|
||||
String supportedString = null;
|
||||
for (String version : supported) {
|
||||
try {
|
||||
Class.forName("com.boydti.fawe.forge." + version + ".ForgeChunk_All");
|
||||
supportedString = version;
|
||||
break;
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
}
|
||||
}
|
||||
if (supportedString == null) {
|
||||
prompt("This version of FAWE cannot be installed this way.");
|
||||
return;
|
||||
}
|
||||
debug("Selected version " + supportedString);
|
||||
URL forgeUrl;
|
||||
URL worldEditUrl;
|
||||
URL worldEditCuiUrl;
|
||||
Thread installThread = new Thread(() -> {
|
||||
List<String> supported = Arrays.asList("v1710", "v189", "v194", "v110", "v111");
|
||||
String supportedString = null;
|
||||
for (String version : supported) {
|
||||
try {
|
||||
switch (supportedString) {
|
||||
case "v111":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.11.2-13.20.0.2201/forge-1.11.2-13.20.0.2201-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9593/download/worldedit-forge-mc1.11-6.1.6-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/241/worldeditcuife-v1.0.6-mf-1.11.2-13.20.0.2201.jar");
|
||||
break;
|
||||
case "v110":
|
||||
forgeUrl = new URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.10.2-12.18.3.2185/forge-1.10.2-12.18.3.2185-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9395/download/worldedit-forge-mc1.10.2-6.1.4-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/239/WorldEditCuiFe-v1.0.6-mf-1.10.2-12.18.2.2125.jar");
|
||||
break;
|
||||
case "v194":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.9.4-12.17.0.2051/forge-1.9.4-12.17.0.2051-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9171/download/worldedit-forge-mc1.9.4-6.1.3-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/236/WorldEditCuiFe-v1.0.6-mf-1.9.4-12.17.0.1976.jar");
|
||||
break;
|
||||
case "v189":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.8.9-11.15.1.1902-1.8.9/forge-1.8.9-11.15.1.1902-1.8.9-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/8755/download/worldedit-forge-mc1.8.9-6.1.1-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/235/WorldEditCuiFe-v1.0.6-mf-1.8.9-11.15.1.1855.jar");
|
||||
break;
|
||||
case "v1710":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.7.10-10.13.4.1614-1.7.10/forge-1.7.10-10.13.4.1614-1.7.10-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9194/download/worldedit-forge-mc1.7.10-6.1.2-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/234/WorldEditCuiFe-v1.0.6-mf-1.7.10-10.13.4.1566.jar");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
Class.forName("com.boydti.fawe.forge." + version + ".ForgeChunk_All");
|
||||
supportedString = version;
|
||||
break;
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
}
|
||||
try { // install forge
|
||||
debug("Downloading forge installer from:\n - https://files.minecraftforge.net/");
|
||||
URLClassLoader loader = new URLClassLoader(new URL[]{forgeUrl});
|
||||
debug("Connected");
|
||||
Class<?> forgeInstallClass = loader.loadClass("net.minecraftforge.installer.ClientInstall");
|
||||
debug("Found ClientInstall class");
|
||||
Object forgeInstallInstance = forgeInstallClass.newInstance();
|
||||
debug(forgeInstallInstance + " | " + forgeInstallClass + " | " + StringMan.getString(forgeInstallClass.getMethods()));
|
||||
debug("Created instance " + forgeInstallInstance);
|
||||
Method methodRun = forgeInstallClass.getDeclaredMethods()[0];//("run", File.class, Predicate.class);
|
||||
Object alwaysTrue = loader.loadClass("com.google.common.base.Predicates").getDeclaredMethod("alwaysTrue").invoke(null);
|
||||
methodRun.invoke(forgeInstallInstance, dirMc, alwaysTrue);
|
||||
debug("Forge profile created, now installing WorldEdit");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
prompt("[ERROR] Forge install failed, download from:\nhttps://files.minecraftforge.net/");
|
||||
}
|
||||
File mods = new File(dirMc, "mods");
|
||||
if (!mods.exists()) {
|
||||
debug("Creating mods directory");
|
||||
mods.mkdirs();
|
||||
} else {
|
||||
for (File file : mods.listFiles()) {
|
||||
String name = file.getName().toLowerCase();
|
||||
if ((name.contains("worldedit") || name.contains("fawe"))) {
|
||||
debug("Delete existing: " + file.getName());
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
try { // install worldedit
|
||||
debug("Downloading WE-CUI from:\n - https://minecraft.curseforge.com/projects/worldeditcui-forge-edition");
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(worldEditCuiUrl.openStream())) {
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(mods, "WorldEditCUI.jar"))) {
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
debug("Successfully downloaded WorldEdit-CUI");
|
||||
} catch (Throwable e) {
|
||||
prompt("[ERROR] WorldEdit install failed, download from:\nhttp://builds.enginehub.org/job/worldedit");
|
||||
}
|
||||
try { // install worldedit
|
||||
debug("Downloading WorldEdit from:\n - http://builds.enginehub.org/job/worldedit");
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(worldEditUrl.openStream())) {
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(mods, "WorldEdit.jar"))) {
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
|
||||
}
|
||||
}
|
||||
debug("Successfully downloaded WorldEdit");
|
||||
} catch (Throwable e) {
|
||||
prompt("[ERROR] WorldEdit install failed, download from:\nhttp://builds.enginehub.org/job/worldedit");
|
||||
}
|
||||
try { // install FAWE
|
||||
debug("Copying FastAsyncWorldEdit to mods directory");
|
||||
File file = new File(InstallerFrame.class.getProtectionDomain().getCodeSource().getLocation().getPath());
|
||||
debug(" - " + file.getPath());
|
||||
MainUtil.copyFile(file, new File(mods, "FastAsyncWorldEdit.jar"));
|
||||
debug("Installation complete!");
|
||||
} catch (Throwable e) {
|
||||
prompt("[ERROR] Copy installer failed, please copy this installer jar manually");
|
||||
}
|
||||
prompt("Installation complete!\nLaunch the game using the forge profile.");
|
||||
}
|
||||
if (supportedString == null) {
|
||||
prompt("This version of FAWE cannot be installed this way.");
|
||||
return;
|
||||
}
|
||||
debug("Selected version " + supportedString);
|
||||
URL forgeUrl;
|
||||
URL worldEditUrl;
|
||||
URL worldEditCuiUrl;
|
||||
try {
|
||||
switch (supportedString) {
|
||||
case "v111":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.11.2-13.20.0.2201/forge-1.11.2-13.20.0.2201-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9593/download/worldedit-forge-mc1.11-6.1.6-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/241/worldeditcuife-v1.0.6-mf-1.11.2-13.20.0.2201.jar");
|
||||
break;
|
||||
case "v110":
|
||||
forgeUrl = new URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.10.2-12.18.3.2185/forge-1.10.2-12.18.3.2185-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9395/download/worldedit-forge-mc1.10.2-6.1.4-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/239/WorldEditCuiFe-v1.0.6-mf-1.10.2-12.18.2.2125.jar");
|
||||
break;
|
||||
case "v194":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.9.4-12.17.0.2051/forge-1.9.4-12.17.0.2051-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9171/download/worldedit-forge-mc1.9.4-6.1.3-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/236/WorldEditCuiFe-v1.0.6-mf-1.9.4-12.17.0.1976.jar");
|
||||
break;
|
||||
case "v189":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.8.9-11.15.1.1902-1.8.9/forge-1.8.9-11.15.1.1902-1.8.9-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/8755/download/worldedit-forge-mc1.8.9-6.1.1-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/235/WorldEditCuiFe-v1.0.6-mf-1.8.9-11.15.1.1855.jar");
|
||||
break;
|
||||
case "v1710":
|
||||
forgeUrl = new URL("https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.7.10-10.13.4.1614-1.7.10/forge-1.7.10-10.13.4.1614-1.7.10-installer.jar");
|
||||
worldEditUrl = new URL("http://builds.enginehub.org/job/worldedit/9194/download/worldedit-forge-mc1.7.10-6.1.2-SNAPSHOT-dist.jar");
|
||||
worldEditCuiUrl = new URL("https://addons-origin.cursecdn.com/files/2361/234/WorldEditCuiFe-v1.0.6-mf-1.7.10-10.13.4.1566.jar");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
try { // install forge
|
||||
debug("Downloading forge installer from:\n - https://files.minecraftforge.net/");
|
||||
URLClassLoader loader = new URLClassLoader(new URL[]{forgeUrl});
|
||||
debug("Connected");
|
||||
Class<?> forgeInstallClass = loader.loadClass("net.minecraftforge.installer.ClientInstall");
|
||||
debug("Found ClientInstall class");
|
||||
Object forgeInstallInstance = forgeInstallClass.newInstance();
|
||||
debug(forgeInstallInstance + " | " + forgeInstallClass + " | " + StringMan.getString(forgeInstallClass.getMethods()));
|
||||
debug("Created instance " + forgeInstallInstance);
|
||||
Method methodRun = forgeInstallClass.getDeclaredMethods()[0];//("run", File.class, Predicate.class);
|
||||
Object alwaysTrue = loader.loadClass("com.google.common.base.Predicates").getDeclaredMethod("alwaysTrue").invoke(null);
|
||||
methodRun.invoke(forgeInstallInstance, dirMc, alwaysTrue);
|
||||
debug("Forge profile created, now installing WorldEdit");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
prompt("[ERROR] Forge install failed, download from:\nhttps://files.minecraftforge.net/");
|
||||
}
|
||||
File mods = new File(dirMc, "mods");
|
||||
if (!mods.exists()) {
|
||||
debug("Creating mods directory");
|
||||
mods.mkdirs();
|
||||
} else {
|
||||
for (File file : mods.listFiles()) {
|
||||
String name1 = file.getName().toLowerCase();
|
||||
if ((name1.contains("worldedit") || name1.contains("fawe"))) {
|
||||
debug("Delete existing: " + file.getName());
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
try { // install worldedit
|
||||
debug("Downloading WE-CUI from:\n - https://minecraft.curseforge.com/projects/worldeditcui-forge-edition");
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(worldEditCuiUrl.openStream())) {
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(mods, "WorldEditCUI.jar"))) {
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
debug("Successfully downloaded WorldEdit-CUI");
|
||||
} catch (Throwable e) {
|
||||
prompt("[ERROR] WorldEdit install failed, download from:\nhttp://builds.enginehub.org/job/worldedit");
|
||||
}
|
||||
try { // install worldedit
|
||||
debug("Downloading WorldEdit from:\n - http://builds.enginehub.org/job/worldedit");
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(worldEditUrl.openStream())) {
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(mods, "WorldEdit.jar"))) {
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
|
||||
}
|
||||
}
|
||||
debug("Successfully downloaded WorldEdit");
|
||||
} catch (Throwable e) {
|
||||
prompt("[ERROR] WorldEdit install failed, download from:\nhttp://builds.enginehub.org/job/worldedit");
|
||||
}
|
||||
try { // install FAWE
|
||||
debug("Copying FastAsyncWorldEdit to mods directory");
|
||||
File file = new File(InstallerFrame.class.getProtectionDomain().getCodeSource().getLocation().getPath());
|
||||
debug(" - " + file.getPath());
|
||||
MainUtil.copyFile(file, new File(mods, "FastAsyncWorldEdit.jar"));
|
||||
debug("Installation complete!");
|
||||
} catch (Throwable e) {
|
||||
prompt("[ERROR] Copy installer failed, please copy this installer jar manually");
|
||||
}
|
||||
prompt("Installation complete!\nLaunch the game using the forge profile.");
|
||||
});
|
||||
installThread.start();
|
||||
}
|
||||
|
||||
public void fadeIn() {
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (float i = 0; i <= 1; i += 0.001) {
|
||||
InstallerFrame.this.setOpacity(i);
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Thread thread = new Thread(() -> {
|
||||
for (float i = 0; i <= 1; i += 0.001) {
|
||||
InstallerFrame.this.setOpacity(i);
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.highestBit;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
import static com.boydti.fawe.object.io.zstd.ZstdFrameDecompressor.SIZE_OF_LONG;
|
||||
|
||||
/**
|
||||
* Bit streams are encoded as a byte-aligned little-endian stream. Thus, bits are laid out
|
||||
* in the following manner, and the stream is read from right to left.
|
||||
* <p>
|
||||
* <p>
|
||||
* ... [16 17 18 19 20 21 22 23] [8 9 10 11 12 13 14 15] [0 1 2 3 4 5 6 7]
|
||||
*/
|
||||
class BitStream
|
||||
{
|
||||
private BitStream()
|
||||
{
|
||||
}
|
||||
|
||||
public static boolean isEndOfStream(long startAddress, long currentAddress, int bitsConsumed)
|
||||
{
|
||||
return startAddress == currentAddress && bitsConsumed == Long.SIZE;
|
||||
}
|
||||
|
||||
static long readTail(Object inputBase, long inputAddress, int inputSize)
|
||||
{
|
||||
long bits = UNSAFE.getByte(inputBase, inputAddress) & 0xFF;
|
||||
|
||||
switch (inputSize) {
|
||||
case 7:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 6) & 0xFFL) << 48;
|
||||
case 6:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 5) & 0xFFL) << 40;
|
||||
case 5:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 4) & 0xFFL) << 32;
|
||||
case 4:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 3) & 0xFFL) << 24;
|
||||
case 3:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 2) & 0xFFL) << 16;
|
||||
case 2:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 1) & 0xFFL) << 8;
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return numberOfBits in the low order bits of a long
|
||||
*/
|
||||
public static long peekBits(int bitsConsumed, long bitContainer, int numberOfBits)
|
||||
{
|
||||
return (((bitContainer << bitsConsumed) >>> 1) >>> (63 - numberOfBits));
|
||||
}
|
||||
|
||||
/**
|
||||
* numberOfBits must be > 0
|
||||
*
|
||||
* @return numberOfBits in the low order bits of a long
|
||||
*/
|
||||
public static long peekBitsFast(int bitsConsumed, long bitContainer, int numberOfBits)
|
||||
{
|
||||
return ((bitContainer << bitsConsumed) >>> (64 - numberOfBits));
|
||||
}
|
||||
|
||||
static class Initializer
|
||||
{
|
||||
private final Object inputBase;
|
||||
private final long startAddress;
|
||||
private final long endAddress;
|
||||
private long bits;
|
||||
private long currentAddress;
|
||||
private int bitsConsumed;
|
||||
|
||||
public Initializer(Object inputBase, long startAddress, long endAddress)
|
||||
{
|
||||
this.inputBase = inputBase;
|
||||
this.startAddress = startAddress;
|
||||
this.endAddress = endAddress;
|
||||
}
|
||||
|
||||
public long getBits()
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
|
||||
public long getCurrentAddress()
|
||||
{
|
||||
return currentAddress;
|
||||
}
|
||||
|
||||
public int getBitsConsumed()
|
||||
{
|
||||
return bitsConsumed;
|
||||
}
|
||||
|
||||
public void initialize()
|
||||
{
|
||||
verify(endAddress - startAddress >= 1, startAddress, "Bitstream is empty");
|
||||
|
||||
int lastByte = UNSAFE.getByte(inputBase, endAddress - 1) & 0xFF;
|
||||
verify(lastByte != 0, endAddress, "Bitstream end mark not present");
|
||||
|
||||
bitsConsumed = SIZE_OF_LONG - highestBit(lastByte);
|
||||
|
||||
int inputSize = (int) (endAddress - startAddress);
|
||||
if (inputSize >= SIZE_OF_LONG) { /* normal case */
|
||||
currentAddress = endAddress - SIZE_OF_LONG;
|
||||
bits = UNSAFE.getLong(inputBase, currentAddress);
|
||||
}
|
||||
else {
|
||||
currentAddress = startAddress;
|
||||
bits = readTail(inputBase, startAddress, inputSize);
|
||||
|
||||
bitsConsumed += (SIZE_OF_LONG - inputSize) * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class Loader
|
||||
{
|
||||
private final Object inputBase;
|
||||
private final long startAddress;
|
||||
private long bits;
|
||||
private long currentAddress;
|
||||
private int bitsConsumed;
|
||||
private boolean overflow;
|
||||
|
||||
public Loader(Object inputBase, long startAddress, long currentAddress, long bits, int bitsConsumed)
|
||||
{
|
||||
this.inputBase = inputBase;
|
||||
this.startAddress = startAddress;
|
||||
this.bits = bits;
|
||||
this.currentAddress = currentAddress;
|
||||
this.bitsConsumed = bitsConsumed;
|
||||
}
|
||||
|
||||
public long getBits()
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
|
||||
public long getCurrentAddress()
|
||||
{
|
||||
return currentAddress;
|
||||
}
|
||||
|
||||
public int getBitsConsumed()
|
||||
{
|
||||
return bitsConsumed;
|
||||
}
|
||||
|
||||
public boolean isOverflow()
|
||||
{
|
||||
return overflow;
|
||||
}
|
||||
|
||||
public boolean load()
|
||||
{
|
||||
if (bitsConsumed > 64) {
|
||||
overflow = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (currentAddress == startAddress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int bytes = bitsConsumed >>> 3; // divide by 8
|
||||
if (currentAddress >= startAddress + SIZE_OF_LONG) {
|
||||
if (bytes > 0) {
|
||||
currentAddress -= bytes;
|
||||
bits = UNSAFE.getLong(inputBase, currentAddress);
|
||||
}
|
||||
bitsConsumed &= 0b111;
|
||||
}
|
||||
else if (currentAddress - bytes < startAddress) {
|
||||
bytes = (int) (currentAddress - startAddress);
|
||||
currentAddress = startAddress;
|
||||
bitsConsumed -= bytes * SIZE_OF_LONG;
|
||||
bits = UNSAFE.getLong(inputBase, startAddress);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
currentAddress -= bytes;
|
||||
bitsConsumed -= bytes * SIZE_OF_LONG;
|
||||
bits = UNSAFE.getLong(inputBase, currentAddress);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.peekBits;
|
||||
import static com.boydti.fawe.object.io.zstd.FseTableReader.FSE_MAX_SYMBOL_VALUE;
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
class FiniteStateEntropy
|
||||
{
|
||||
private static final int MAX_TABLE_LOG = 12;
|
||||
|
||||
private final FiniteStateEntropy.Table table;
|
||||
private final FseTableReader reader = new FseTableReader();
|
||||
|
||||
public FiniteStateEntropy(int maxLog)
|
||||
{
|
||||
table = new FiniteStateEntropy.Table(maxLog);
|
||||
}
|
||||
|
||||
public int decompress(final Object inputBase, final long inputAddress, final long inputLimit, byte[] weights)
|
||||
{
|
||||
long input = inputAddress;
|
||||
input += reader.readFseTable(table, inputBase, input, inputLimit, FSE_MAX_SYMBOL_VALUE, MAX_TABLE_LOG);
|
||||
|
||||
final Object outputBase = weights;
|
||||
final long outputAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
final long outputLimit = outputAddress + weights.length;
|
||||
|
||||
long output = outputAddress;
|
||||
|
||||
// initialize bit stream
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, input, inputLimit);
|
||||
initializer.initialize();
|
||||
int bitsConsumed = initializer.getBitsConsumed();
|
||||
long currentAddress = initializer.getCurrentAddress();
|
||||
long bits = initializer.getBits();
|
||||
|
||||
// initialize first FSE stream
|
||||
int state1 = (int) peekBits(bitsConsumed, bits, table.log2Size);
|
||||
bitsConsumed += table.log2Size;
|
||||
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bits = loader.getBits();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
// initialize second FSE stream
|
||||
int state2 = (int) peekBits(bitsConsumed, bits, table.log2Size);
|
||||
bitsConsumed += table.log2Size;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bits = loader.getBits();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
byte[] symbols = table.symbol;
|
||||
byte[] numbersOfBits = table.numberOfBits;
|
||||
int[] newStates = table.newState;
|
||||
|
||||
// decode 4 symbols per loop
|
||||
while (output < outputLimit) {
|
||||
int numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output, symbols[state1]);
|
||||
numberOfBits = numbersOfBits[state1];
|
||||
state1 = (int) (newStates[state1] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output + 1, symbols[state2]);
|
||||
numberOfBits = numbersOfBits[state2];
|
||||
state2 = (int) (newStates[state2] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output + 2, symbols[state1]);
|
||||
numberOfBits = numbersOfBits[state1];
|
||||
state1 = (int) (newStates[state1] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output + 3, symbols[state2]);
|
||||
numberOfBits = numbersOfBits[state2];
|
||||
state2 = (int) (newStates[state2] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
output += ZstdFrameDecompressor.SIZE_OF_INT;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state1]);
|
||||
int numberOfBits = numbersOfBits[state1];
|
||||
state1 = (int) (newStates[state1] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (loader.isOverflow()) {
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state2]);
|
||||
break;
|
||||
}
|
||||
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state2]);
|
||||
int numberOfBits1 = numbersOfBits[state2];
|
||||
state2 = (int) (newStates[state2] + peekBits(bitsConsumed, bits, numberOfBits1));
|
||||
bitsConsumed += numberOfBits1;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (loader.isOverflow()) {
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (int) (output - outputAddress);
|
||||
}
|
||||
|
||||
public static final class Table
|
||||
{
|
||||
int log2Size;
|
||||
final int[] newState;
|
||||
final byte[] symbol;
|
||||
final byte[] numberOfBits;
|
||||
|
||||
public Table(int log2Size)
|
||||
{
|
||||
int size = 1 << log2Size;
|
||||
newState = new int[size];
|
||||
symbol = new byte[size];
|
||||
numberOfBits = new byte[size];
|
||||
}
|
||||
|
||||
public Table(int log2Size, int[] newState, byte[] symbol, byte[] numberOfBits)
|
||||
{
|
||||
int size = 1 << log2Size;
|
||||
if (newState.length != size || symbol.length != size || numberOfBits.length != size) {
|
||||
throw new IllegalArgumentException("Expected arrays to match provided size");
|
||||
}
|
||||
|
||||
this.log2Size = log2Size;
|
||||
this.newState = newState;
|
||||
this.symbol = symbol;
|
||||
this.numberOfBits = numberOfBits;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.highestBit;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
|
||||
class FseTableReader
|
||||
{
|
||||
private static final int FSE_MIN_TABLE_LOG = 5;
|
||||
|
||||
public static final int FSE_MAX_SYMBOL_VALUE = 255;
|
||||
private final short[] nextSymbol = new short[FSE_MAX_SYMBOL_VALUE + 1];
|
||||
private final short[] normalizedCounters = new short[FSE_MAX_SYMBOL_VALUE + 1];
|
||||
|
||||
public int readFseTable(FiniteStateEntropy.Table table, Object inputBase, long inputAddress, long inputLimit, int maxSymbol, int maxTableLog)
|
||||
{
|
||||
// read table headers
|
||||
long input = inputAddress;
|
||||
verify(inputLimit - inputAddress >= 4, input, "Not enough input bytes");
|
||||
|
||||
int threshold;
|
||||
int symbolNumber = 0;
|
||||
boolean previousIsZero = false;
|
||||
|
||||
int bitStream = UNSAFE.getInt(inputBase, input);
|
||||
|
||||
int tableLog = (bitStream & 0xF) + FSE_MIN_TABLE_LOG;
|
||||
|
||||
int numberOfBits = tableLog + 1;
|
||||
bitStream >>>= 4;
|
||||
int bitCount = 4;
|
||||
|
||||
verify(tableLog <= maxTableLog, input, "FSE table size exceeds maximum allowed size");
|
||||
|
||||
int remaining = (1 << tableLog) + 1;
|
||||
threshold = 1 << tableLog;
|
||||
|
||||
while (remaining > 1 && symbolNumber <= maxSymbol) {
|
||||
if (previousIsZero) {
|
||||
int n0 = symbolNumber;
|
||||
while ((bitStream & 0xFFFF) == 0xFFFF) {
|
||||
n0 += 24;
|
||||
if (input < inputLimit - 5) {
|
||||
input += 2;
|
||||
bitStream = (UNSAFE.getInt(inputBase, input) >>> bitCount);
|
||||
}
|
||||
else {
|
||||
// end of bit stream
|
||||
bitStream >>>= 16;
|
||||
bitCount += 16;
|
||||
}
|
||||
}
|
||||
while ((bitStream & 3) == 3) {
|
||||
n0 += 3;
|
||||
bitStream >>>= 2;
|
||||
bitCount += 2;
|
||||
}
|
||||
n0 += bitStream & 3;
|
||||
bitCount += 2;
|
||||
|
||||
verify(n0 <= maxSymbol, input, "Symbol larger than max value");
|
||||
|
||||
while (symbolNumber < n0) {
|
||||
normalizedCounters[symbolNumber++] = 0;
|
||||
}
|
||||
if ((input <= inputLimit - 7) || (input + (bitCount >>> 3) <= inputLimit - 4)) {
|
||||
input += bitCount >>> 3;
|
||||
bitCount &= 7;
|
||||
bitStream = UNSAFE.getInt(inputBase, input) >>> bitCount;
|
||||
}
|
||||
else {
|
||||
bitStream >>>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
short max = (short) ((2 * threshold - 1) - remaining);
|
||||
short count;
|
||||
|
||||
if ((bitStream & (threshold - 1)) < max) {
|
||||
count = (short) (bitStream & (threshold - 1));
|
||||
bitCount += numberOfBits - 1;
|
||||
}
|
||||
else {
|
||||
count = (short) (bitStream & (2 * threshold - 1));
|
||||
if (count >= threshold) {
|
||||
count -= max;
|
||||
}
|
||||
bitCount += numberOfBits;
|
||||
}
|
||||
count--; // extra accuracy
|
||||
|
||||
remaining -= Math.abs(count);
|
||||
normalizedCounters[symbolNumber++] = count;
|
||||
previousIsZero = count == 0;
|
||||
while (remaining < threshold) {
|
||||
numberOfBits--;
|
||||
threshold >>>= 1;
|
||||
}
|
||||
|
||||
if ((input <= inputLimit - 7) || (input + (bitCount >> 3) <= inputLimit - 4)) {
|
||||
input += bitCount >>> 3;
|
||||
bitCount &= 7;
|
||||
}
|
||||
else {
|
||||
bitCount -= (int) (8 * (inputLimit - 4 - input));
|
||||
input = inputLimit - 4;
|
||||
}
|
||||
bitStream = UNSAFE.getInt(inputBase, input) >>> (bitCount & 31);
|
||||
}
|
||||
|
||||
verify(remaining == 1 && bitCount <= 32, input, "Input is corrupted");
|
||||
|
||||
maxSymbol = symbolNumber - 1;
|
||||
verify(maxSymbol <= FSE_MAX_SYMBOL_VALUE, input, "Max symbol value too large (too many symbols for FSE)");
|
||||
|
||||
input += (bitCount + 7) >> 3;
|
||||
|
||||
// populate decoding table
|
||||
int symbolCount = maxSymbol + 1;
|
||||
int tableSize = 1 << tableLog;
|
||||
int highThreshold = tableSize - 1;
|
||||
|
||||
table.log2Size = tableLog;
|
||||
|
||||
for (byte symbol = 0; symbol < symbolCount; symbol++) {
|
||||
if (normalizedCounters[symbol] == -1) {
|
||||
table.symbol[highThreshold--] = symbol;
|
||||
nextSymbol[symbol] = 1;
|
||||
}
|
||||
else {
|
||||
nextSymbol[symbol] = normalizedCounters[symbol];
|
||||
}
|
||||
}
|
||||
|
||||
// spread symbols
|
||||
int tableMask = tableSize - 1;
|
||||
int step = (tableSize >>> 1) + (tableSize >>> 3) + 3;
|
||||
int position = 0;
|
||||
for (byte symbol = 0; symbol < symbolCount; symbol++) {
|
||||
for (int i = 0; i < normalizedCounters[symbol]; i++) {
|
||||
table.symbol[position] = symbol;
|
||||
do {
|
||||
position = (position + step) & tableMask;
|
||||
}
|
||||
while (position > highThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
// position must reach all cells once, otherwise normalizedCounter is incorrect
|
||||
verify(position == 0, input, "Input is corrupted");
|
||||
|
||||
for (int i = 0; i < tableSize; i++) {
|
||||
byte symbol = table.symbol[i];
|
||||
short nextState = nextSymbol[symbol]++;
|
||||
table.numberOfBits[i] = (byte) (tableLog - highestBit(nextState));
|
||||
table.newState[i] = (short) ((nextState << table.numberOfBits[i]) - tableSize);
|
||||
}
|
||||
|
||||
return (int) (input - inputAddress);
|
||||
}
|
||||
|
||||
public static void buildRleTable(FiniteStateEntropy.Table table, byte value)
|
||||
{
|
||||
table.log2Size = 0;
|
||||
table.symbol[0] = value;
|
||||
table.newState[0] = 0;
|
||||
table.numberOfBits[0] = 0;
|
||||
}
|
||||
}
|
@ -1,317 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.isEndOfStream;
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.peekBitsFast;
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.isPowerOf2;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
import static com.boydti.fawe.object.io.zstd.ZstdFrameDecompressor.SIZE_OF_INT;
|
||||
import static com.boydti.fawe.object.io.zstd.ZstdFrameDecompressor.SIZE_OF_SHORT;
|
||||
|
||||
class Huffman
|
||||
{
|
||||
private static final int MAX_SYMBOL = 255;
|
||||
private static final int MAX_TABLE_LOG = 12;
|
||||
|
||||
// stats
|
||||
private final byte[] weights = new byte[MAX_SYMBOL + 1];
|
||||
private final int[] ranks = new int[MAX_TABLE_LOG + 1];
|
||||
|
||||
// table
|
||||
private int tableLog = -1;
|
||||
private final byte[] symbols = new byte[1 << MAX_TABLE_LOG];
|
||||
private final byte[] numbersOfBits = new byte[1 << MAX_TABLE_LOG];
|
||||
|
||||
private final FiniteStateEntropy finiteStateEntropy = new FiniteStateEntropy(6);
|
||||
|
||||
public boolean isLoaded()
|
||||
{
|
||||
return tableLog != -1;
|
||||
}
|
||||
|
||||
public int readTable(final Object inputBase, final long inputAddress, final int size)
|
||||
{
|
||||
Arrays.fill(ranks, 0);
|
||||
long input = inputAddress;
|
||||
|
||||
// read table header
|
||||
verify(size > 0, input, "Not enough input bytes");
|
||||
int inputSize = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
|
||||
int outputSize;
|
||||
if (inputSize >= 128) {
|
||||
outputSize = inputSize - 127;
|
||||
inputSize = ((outputSize + 1) / 2);
|
||||
|
||||
verify(inputSize + 1 <= size, input, "Not enough input bytes");
|
||||
verify(outputSize <= MAX_SYMBOL + 1, input, "Input is corrupted");
|
||||
|
||||
for (int i = 0; i < outputSize; i += 2) {
|
||||
int value = UNSAFE.getByte(inputBase, input + i / 2) & 0xFF;
|
||||
weights[i] = (byte) (value >>> 4);
|
||||
weights[i + 1] = (byte) (value & 0b1111);
|
||||
}
|
||||
}
|
||||
else {
|
||||
verify(inputSize + 1 <= size, input, "Not enough input bytes");
|
||||
|
||||
outputSize = finiteStateEntropy.decompress(inputBase, input, input + inputSize, weights);
|
||||
}
|
||||
|
||||
int totalWeight = 0;
|
||||
for (int i = 0; i < outputSize; i++) {
|
||||
ranks[weights[i]]++;
|
||||
totalWeight += (1 << weights[i]) >> 1; // TODO same as 1 << (weights[n] - 1)?
|
||||
}
|
||||
verify(totalWeight != 0, input, "Input is corrupted");
|
||||
|
||||
tableLog = Util.highestBit(totalWeight) + 1;
|
||||
verify(tableLog <= MAX_TABLE_LOG, input, "Input is corrupted");
|
||||
|
||||
int total = 1 << tableLog;
|
||||
int rest = total - totalWeight;
|
||||
verify(isPowerOf2(rest), input, "Input is corrupted");
|
||||
|
||||
int lastWeight = Util.highestBit(rest) + 1;
|
||||
|
||||
weights[outputSize] = (byte) lastWeight;
|
||||
ranks[lastWeight]++;
|
||||
|
||||
int numberOfSymbols = outputSize + 1;
|
||||
|
||||
// populate table
|
||||
int nextRankStart = 0;
|
||||
for (int i = 1; i < tableLog + 1; ++i) {
|
||||
int current = nextRankStart;
|
||||
nextRankStart += ranks[i] << (i - 1);
|
||||
ranks[i] = current;
|
||||
}
|
||||
|
||||
for (int n = 0; n < numberOfSymbols; n++) {
|
||||
int weight = weights[n];
|
||||
int length = (1 << weight) >> 1; // TODO: 1 << (weight - 1) ??
|
||||
|
||||
byte symbol = (byte) n;
|
||||
byte numberOfBits = (byte) (tableLog + 1 - weight);
|
||||
for (int i = ranks[weight]; i < ranks[weight] + length; i++) {
|
||||
symbols[i] = symbol;
|
||||
numbersOfBits[i] = numberOfBits;
|
||||
}
|
||||
ranks[weight] += length;
|
||||
}
|
||||
|
||||
verify(ranks[1] >= 2 && (ranks[1] & 1) == 0, input, "Input is corrupted");
|
||||
|
||||
return inputSize + 1;
|
||||
}
|
||||
|
||||
public void decodeSingleStream(final Object inputBase, final long inputAddress, final long inputLimit, final Object outputBase, final long outputAddress, final long outputLimit)
|
||||
{
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, inputAddress, inputLimit);
|
||||
initializer.initialize();
|
||||
|
||||
long bits = initializer.getBits();
|
||||
int bitsConsumed = initializer.getBitsConsumed();
|
||||
long currentAddress = initializer.getCurrentAddress();
|
||||
|
||||
int tableLog = this.tableLog;
|
||||
byte[] numbersOfBits = this.numbersOfBits;
|
||||
byte[] symbols = this.symbols;
|
||||
|
||||
// 4 symbols at a time
|
||||
long output = outputAddress;
|
||||
long fastOutputLimit = outputLimit - 4;
|
||||
while (output < fastOutputLimit) {
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, inputAddress, currentAddress, bits, bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
bits = loader.getBits();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
bitsConsumed = decodeSymbol(outputBase, output, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
bitsConsumed = decodeSymbol(outputBase, output + 1, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
bitsConsumed = decodeSymbol(outputBase, output + 2, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
bitsConsumed = decodeSymbol(outputBase, output + 3, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
output += SIZE_OF_INT;
|
||||
}
|
||||
|
||||
decodeTail(inputBase, inputAddress, currentAddress, bitsConsumed, bits, outputBase, output, outputLimit);
|
||||
}
|
||||
|
||||
public void decode4Streams(final Object inputBase, final long inputAddress, final long inputLimit, final Object outputBase, final long outputAddress, final long outputLimit)
|
||||
{
|
||||
verify(inputLimit - inputAddress >= 10, inputAddress, "Input is corrupted"); // jump table + 1 byte per stream
|
||||
|
||||
long start1 = inputAddress + 3 * SIZE_OF_SHORT; // for the shorts we read below
|
||||
long start2 = start1 + (UNSAFE.getShort(inputBase, inputAddress) & 0xFFFF);
|
||||
long start3 = start2 + (UNSAFE.getShort(inputBase, inputAddress + 2) & 0xFFFF);
|
||||
long start4 = start3 + (UNSAFE.getShort(inputBase, inputAddress + 4) & 0xFFFF);
|
||||
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, start1, start2);
|
||||
initializer.initialize();
|
||||
int stream1bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream1currentAddress = initializer.getCurrentAddress();
|
||||
long stream1bits = initializer.getBits();
|
||||
|
||||
initializer = new BitStream.Initializer(inputBase, start2, start3);
|
||||
initializer.initialize();
|
||||
int stream2bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream2currentAddress = initializer.getCurrentAddress();
|
||||
long stream2bits = initializer.getBits();
|
||||
|
||||
initializer = new BitStream.Initializer(inputBase, start3, start4);
|
||||
initializer.initialize();
|
||||
int stream3bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream3currentAddress = initializer.getCurrentAddress();
|
||||
long stream3bits = initializer.getBits();
|
||||
|
||||
initializer = new BitStream.Initializer(inputBase, start4, inputLimit);
|
||||
initializer.initialize();
|
||||
int stream4bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream4currentAddress = initializer.getCurrentAddress();
|
||||
long stream4bits = initializer.getBits();
|
||||
|
||||
int segmentSize = (int) ((outputLimit - outputAddress + 3) / 4);
|
||||
|
||||
long outputStart2 = outputAddress + segmentSize;
|
||||
long outputStart3 = outputStart2 + segmentSize;
|
||||
long outputStart4 = outputStart3 + segmentSize;
|
||||
|
||||
long output1 = outputAddress;
|
||||
long output2 = outputStart2;
|
||||
long output3 = outputStart3;
|
||||
long output4 = outputStart4;
|
||||
|
||||
long fastOutputLimit = outputLimit - 7;
|
||||
int tableLog = this.tableLog;
|
||||
byte[] numbersOfBits = this.numbersOfBits;
|
||||
byte[] symbols = this.symbols;
|
||||
|
||||
while (output4 < fastOutputLimit) {
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1 + 1, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2 + 1, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3 + 1, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4 + 1, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1 + 2, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2 + 2, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3 + 2, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4 + 2, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1 + 3, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2 + 3, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3 + 3, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4 + 3, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
output1 += SIZE_OF_INT;
|
||||
output2 += SIZE_OF_INT;
|
||||
output3 += SIZE_OF_INT;
|
||||
output4 += SIZE_OF_INT;
|
||||
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, start1, stream1currentAddress, stream1bits, stream1bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
stream1bitsConsumed = loader.getBitsConsumed();
|
||||
stream1bits = loader.getBits();
|
||||
stream1currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
loader = new BitStream.Loader(inputBase, start2, stream2currentAddress, stream2bits, stream2bitsConsumed);
|
||||
done = loader.load();
|
||||
stream2bitsConsumed = loader.getBitsConsumed();
|
||||
stream2bits = loader.getBits();
|
||||
stream2currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
loader = new BitStream.Loader(inputBase, start3, stream3currentAddress, stream3bits, stream3bitsConsumed);
|
||||
done = loader.load();
|
||||
stream3bitsConsumed = loader.getBitsConsumed();
|
||||
stream3bits = loader.getBits();
|
||||
stream3currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
loader = new BitStream.Loader(inputBase, start4, stream4currentAddress, stream4bits, stream4bitsConsumed);
|
||||
done = loader.load();
|
||||
stream4bitsConsumed = loader.getBitsConsumed();
|
||||
stream4bits = loader.getBits();
|
||||
stream4currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
verify(output1 <= outputStart2 && output2 <= outputStart3 && output3 <= outputStart4, inputAddress, "Input is corrupted");
|
||||
|
||||
/// finish streams one by one
|
||||
decodeTail(inputBase, start1, stream1currentAddress, stream1bitsConsumed, stream1bits, outputBase, output1, outputStart2);
|
||||
decodeTail(inputBase, start2, stream2currentAddress, stream2bitsConsumed, stream2bits, outputBase, output2, outputStart3);
|
||||
decodeTail(inputBase, start3, stream3currentAddress, stream3bitsConsumed, stream3bits, outputBase, output3, outputStart4);
|
||||
decodeTail(inputBase, start4, stream4currentAddress, stream4bitsConsumed, stream4bits, outputBase, output4, outputLimit);
|
||||
}
|
||||
|
||||
private void decodeTail(final Object inputBase, final long startAddress, long currentAddress, int bitsConsumed, long bits, final Object outputBase, long outputAddress, final long outputLimit)
|
||||
{
|
||||
int tableLog = this.tableLog;
|
||||
byte[] numbersOfBits = this.numbersOfBits;
|
||||
byte[] symbols = this.symbols;
|
||||
|
||||
// closer to the end
|
||||
while (outputAddress < outputLimit) {
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, startAddress, currentAddress, bits, bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
bitsConsumed = decodeSymbol(outputBase, outputAddress++, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
}
|
||||
|
||||
// not more data in bit stream, so no need to reload
|
||||
while (outputAddress < outputLimit) {
|
||||
bitsConsumed = decodeSymbol(outputBase, outputAddress++, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
}
|
||||
|
||||
verify(isEndOfStream(startAddress, currentAddress, bitsConsumed), startAddress, "Bit stream is not fully consumed");
|
||||
}
|
||||
|
||||
private static int decodeSymbol(Object outputBase, long outputAddress, long bitContainer, int bitsConsumed, int tableLog, byte[] numbersOfBits, byte[] symbols)
|
||||
{
|
||||
int value = (int) peekBitsFast(bitsConsumed, bitContainer, tableLog);
|
||||
UNSAFE.putByte(outputBase, outputAddress, symbols[value]);
|
||||
return bitsConsumed + numbersOfBits[value];
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.Buffer;
|
||||
|
||||
final class UnsafeUtil
|
||||
{
|
||||
public static final Unsafe UNSAFE;
|
||||
private static final Field ADDRESS_ACCESSOR;
|
||||
|
||||
private UnsafeUtil() {}
|
||||
|
||||
static {
|
||||
try {
|
||||
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
UNSAFE = (Unsafe) theUnsafe.get(null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
Field field = Buffer.class.getDeclaredField("address");
|
||||
field.setAccessible(true);
|
||||
ADDRESS_ACCESSOR = field;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static long getAddress(Buffer buffer)
|
||||
{
|
||||
try {
|
||||
return (long) ADDRESS_ACCESSOR.get(buffer);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.getAddress;
|
||||
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
public class ZstdDecompressor
|
||||
{
|
||||
private final ZstdFrameDecompressor decompressor = new ZstdFrameDecompressor();
|
||||
|
||||
public int decompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int maxOutputLength)
|
||||
throws MalformedInputException
|
||||
{
|
||||
long inputAddress = ARRAY_BYTE_BASE_OFFSET + inputOffset;
|
||||
long inputLimit = inputAddress + inputLength;
|
||||
long outputAddress = ARRAY_BYTE_BASE_OFFSET + outputOffset;
|
||||
long outputLimit = outputAddress + maxOutputLength;
|
||||
|
||||
return decompressor.decompress(input, inputAddress, inputLimit, output, outputAddress, outputLimit);
|
||||
}
|
||||
|
||||
public void decompress(ByteBuffer input, ByteBuffer output)
|
||||
throws MalformedInputException
|
||||
{
|
||||
Object inputBase;
|
||||
long inputAddress;
|
||||
long inputLimit;
|
||||
if (input.isDirect()) {
|
||||
inputBase = null;
|
||||
long address = getAddress(input);
|
||||
inputAddress = address + input.position();
|
||||
inputLimit = address + input.limit();
|
||||
}
|
||||
else if (input.hasArray()) {
|
||||
inputBase = input.array();
|
||||
inputAddress = ARRAY_BYTE_BASE_OFFSET + input.arrayOffset() + input.position();
|
||||
inputLimit = ARRAY_BYTE_BASE_OFFSET + input.arrayOffset() + input.limit();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported input ByteBuffer implementation " + input.getClass().getName());
|
||||
}
|
||||
|
||||
Object outputBase;
|
||||
long outputAddress;
|
||||
long outputLimit;
|
||||
if (output.isDirect()) {
|
||||
outputBase = null;
|
||||
long address = getAddress(output);
|
||||
outputAddress = address + output.position();
|
||||
outputLimit = address + output.limit();
|
||||
}
|
||||
else if (output.hasArray()) {
|
||||
outputBase = output.array();
|
||||
outputAddress = ARRAY_BYTE_BASE_OFFSET + output.arrayOffset() + output.position();
|
||||
outputLimit = ARRAY_BYTE_BASE_OFFSET + output.arrayOffset() + output.limit();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported output ByteBuffer implementation " + output.getClass().getName());
|
||||
}
|
||||
|
||||
// HACK: Assure JVM does not collect Slice wrappers while decompressing, since the
|
||||
// collection may trigger freeing of the underlying memory resulting in a segfault
|
||||
// There is no other known way to signal to the JVM that an object should not be
|
||||
// collected in a block, and technically, the JVM is allowed to eliminate these locks.
|
||||
synchronized (input) {
|
||||
synchronized (output) {
|
||||
int written = new ZstdFrameDecompressor().decompress(inputBase, inputAddress, inputLimit, outputBase, outputAddress, outputLimit);
|
||||
output.position(output.position() + written);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static long getDecompressedSize(byte[] input, int offset, int length)
|
||||
{
|
||||
int baseAddress = ARRAY_BYTE_BASE_OFFSET + offset;
|
||||
return ZstdFrameDecompressor.getDecompressedSize(input, baseAddress, baseAddress + length);
|
||||
}
|
||||
}
|
@ -1,958 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.peekBits;
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.fail;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.mask;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
class ZstdFrameDecompressor
|
||||
{
|
||||
private static final int MIN_MATCH = 3;
|
||||
|
||||
private static final int[] DEC_32_TABLE = {4, 1, 2, 1, 4, 4, 4, 4};
|
||||
private static final int[] DEC_64_TABLE = {0, 0, 0, -1, 0, 1, 2, 3};
|
||||
|
||||
private static final int MAGIC_NUMBER = 0xFD2FB528; // v0.5
|
||||
|
||||
private static final int MIN_SEQUENCES_SIZE = 1;
|
||||
private static final int MIN_BLOCK_SIZE = 1 // block type tag
|
||||
+ 1 // min size of raw or rle length header
|
||||
+ MIN_SEQUENCES_SIZE;
|
||||
|
||||
private static final int MAX_BLOCK_SIZE = 128 * 1024;
|
||||
|
||||
private static final int MIN_WINDOW_LOG = 10;
|
||||
private static final int MAX_WINDOW_SIZE = 1 << 23;
|
||||
|
||||
public static final int SIZE_OF_BYTE = 1;
|
||||
public static final int SIZE_OF_SHORT = 2;
|
||||
public static final int SIZE_OF_INT = 4;
|
||||
public static final int SIZE_OF_LONG = 8;
|
||||
|
||||
private static final long SIZE_OF_BLOCK_HEADER = 3;
|
||||
|
||||
// block types
|
||||
private static final int RAW_BLOCK = 0;
|
||||
private static final int RLE_BLOCK = 1;
|
||||
private static final int COMPRESSED_BLOCK = 2;
|
||||
|
||||
// literal block types
|
||||
private static final int RAW_LITERALS_BLOCK = 0;
|
||||
private static final int RLE_LITERALS_BLOCK = 1;
|
||||
private static final int COMPRESSED_LITERALS_BLOCK = 2;
|
||||
private static final int REPEAT_STATS_LITERALS_BLOCK = 3;
|
||||
|
||||
private static final int LONG_NUMBER_OF_SEQUENCES = 0x7F00;
|
||||
|
||||
private static final int MAX_LITERALS_LENGTH_SYMBOL = 35;
|
||||
private static final int MAX_MATCH_LENGTH_SYMBOL = 52;
|
||||
private static final int MAX_OFFSET_CODE_SYMBOL = 28;
|
||||
|
||||
private static final int LITERALS_LENGTH_FSE_LOG = 9;
|
||||
private static final int MATCH_LENGTH_FSE_LOG = 9;
|
||||
private static final int OFFSET_CODES_FSE_LOG = 8;
|
||||
|
||||
private static final int SET_BASIC = 0;
|
||||
private static final int SET_RLE = 1;
|
||||
private static final int SET_COMPRESSED = 2;
|
||||
private static final int SET_REPEAT = 3;
|
||||
|
||||
private static final int[] LITERALS_LENGTH_BASE = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
|
||||
0x2000, 0x4000, 0x8000, 0x10000};
|
||||
|
||||
private static final int[] MATCH_LENGTH_BASE = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
|
||||
35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
|
||||
0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
|
||||
|
||||
private static final int[] OFFSET_CODES_BASE = {
|
||||
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
|
||||
0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
|
||||
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
|
||||
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
|
||||
|
||||
private static final int[] LITERALS_LENGTH_BITS = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12,
|
||||
13, 14, 15, 16};
|
||||
|
||||
private static final int[] MATCH_LENGTH_BITS = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16};
|
||||
|
||||
private static final FiniteStateEntropy.Table DEFAULT_LITERALS_LENGTH_TABLE = new FiniteStateEntropy.Table(
|
||||
6,
|
||||
new int[] {
|
||||
0, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 32, 0, 0, 32, 0, 32, 0, 32, 0, 0, 32, 0, 32, 0, 32, 0, 0, 16, 32, 0, 0, 48, 16, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0},
|
||||
new byte[] {
|
||||
0, 0, 1, 3, 4, 6, 7, 9, 10, 12, 14, 16, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 0, 1, 2, 4, 5, 7, 8, 10, 11, 13, 16, 17, 19, 20, 22, 23, 25, 25, 26, 28, 30, 0,
|
||||
1, 2, 3, 5, 6, 8, 9, 11, 12, 15, 17, 18, 20, 21, 23, 24, 35, 34, 33, 32},
|
||||
new byte[] {
|
||||
4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 4, 4, 5, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6});
|
||||
|
||||
private static final FiniteStateEntropy.Table DEFAULT_OFFSET_CODES_TABLE = new FiniteStateEntropy.Table(
|
||||
5,
|
||||
new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0},
|
||||
new byte[] {0, 6, 9, 15, 21, 3, 7, 12, 18, 23, 5, 8, 14, 20, 2, 7, 11, 17, 22, 4, 8, 13, 19, 1, 6, 10, 16, 28, 27, 26, 25, 24},
|
||||
new byte[] {5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5});
|
||||
|
||||
private static final FiniteStateEntropy.Table DEFAULT_MATCH_LENGTH_TABLE = new FiniteStateEntropy.Table(
|
||||
6,
|
||||
new int[] {
|
||||
0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 48, 16, 32, 32, 32, 32,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
new byte[] {
|
||||
0, 1, 2, 3, 5, 6, 8, 10, 13, 16, 19, 22, 25, 28, 31, 33, 35, 37, 39, 41, 43, 45, 1, 2, 3, 4, 6, 7, 9, 12, 15, 18, 21, 24, 27, 30, 32, 34, 36, 38, 40, 42, 44, 1,
|
||||
1, 2, 4, 5, 7, 8, 11, 14, 17, 20, 23, 26, 29, 52, 51, 50, 49, 48, 47, 46},
|
||||
new byte[] {
|
||||
6, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6});
|
||||
|
||||
private final byte[] literals = new byte[MAX_BLOCK_SIZE + SIZE_OF_LONG]; // extra space to allow for long-at-a-time copy
|
||||
|
||||
// current buffer containing literals
|
||||
private Object literalsBase;
|
||||
private long literalsAddress;
|
||||
private long literalsLimit;
|
||||
|
||||
private final int[] previousOffsets = new int[3];
|
||||
|
||||
private final FiniteStateEntropy.Table literalsLengthTable = new FiniteStateEntropy.Table(LITERALS_LENGTH_FSE_LOG);
|
||||
private final FiniteStateEntropy.Table offsetCodesTable = new FiniteStateEntropy.Table(OFFSET_CODES_FSE_LOG);
|
||||
private final FiniteStateEntropy.Table matchLengthTable = new FiniteStateEntropy.Table(MATCH_LENGTH_FSE_LOG);
|
||||
|
||||
private FiniteStateEntropy.Table currentLiteralsLengthTable;
|
||||
private FiniteStateEntropy.Table currentOffsetCodesTable;
|
||||
private FiniteStateEntropy.Table currentMatchLengthTable;
|
||||
|
||||
private final Huffman huffman = new Huffman();
|
||||
private final FseTableReader fse = new FseTableReader();
|
||||
|
||||
public int decompress(
|
||||
final Object inputBase,
|
||||
final long inputAddress,
|
||||
final long inputLimit,
|
||||
final Object outputBase,
|
||||
final long outputAddress,
|
||||
final long outputLimit)
|
||||
{
|
||||
if (outputAddress == outputLimit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
long input = inputAddress;
|
||||
long output = outputAddress;
|
||||
|
||||
input += verifyMagic(inputBase, inputAddress, inputLimit);
|
||||
|
||||
FrameHeader frameHeader = readFrameHeader(inputBase, input, inputLimit);
|
||||
input += frameHeader.headerSize;
|
||||
|
||||
boolean lastBlock;
|
||||
do {
|
||||
verify(input + SIZE_OF_BLOCK_HEADER <= inputLimit, input, "Not enough input bytes");
|
||||
|
||||
// read block header
|
||||
int header = UNSAFE.getInt(inputBase, input) & 0xFF_FFFF;
|
||||
input += SIZE_OF_BLOCK_HEADER;
|
||||
|
||||
lastBlock = (header & 1) != 0;
|
||||
int blockType = (header >>> 1) & 0b11;
|
||||
int blockSize = (header >>> 3) & 0x1F_FFFF; // 21 bits
|
||||
|
||||
int decodedSize;
|
||||
switch (blockType) {
|
||||
case RAW_BLOCK:
|
||||
verify(inputAddress + blockSize <= inputLimit, input, "Not enough input bytes");
|
||||
decodedSize = decodeRawBlock(inputBase, input, blockSize, outputBase, output, outputLimit);
|
||||
input += blockSize;
|
||||
break;
|
||||
case RLE_BLOCK:
|
||||
verify(inputAddress + 1 <= inputLimit, input, "Not enough input bytes");
|
||||
decodedSize = decodeRleBlock(blockSize, inputBase, input, outputBase, output, outputLimit);
|
||||
input += 1;
|
||||
break;
|
||||
case COMPRESSED_BLOCK:
|
||||
verify(inputAddress + blockSize <= inputLimit, input, "Not enough input bytes");
|
||||
decodedSize = decodeCompressedBlock(inputBase, input, blockSize, outputBase, output, outputLimit, frameHeader.windowSize);
|
||||
input += blockSize;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid block type");
|
||||
}
|
||||
|
||||
output += decodedSize;
|
||||
}
|
||||
while (!lastBlock);
|
||||
|
||||
if (frameHeader.hasChecksum) {
|
||||
// TODO checksum
|
||||
}
|
||||
|
||||
return (int) (output - outputAddress);
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
previousOffsets[0] = 1;
|
||||
previousOffsets[1] = 4;
|
||||
previousOffsets[2] = 8;
|
||||
|
||||
currentLiteralsLengthTable = null;
|
||||
currentOffsetCodesTable = null;
|
||||
currentMatchLengthTable = null;
|
||||
}
|
||||
|
||||
private static int decodeRawBlock(Object inputBase, long inputAddress, int blockSize, Object outputBase, long outputAddress, long outputLimit)
|
||||
{
|
||||
verify(outputAddress + blockSize <= outputLimit, inputAddress, "Output buffer too small");
|
||||
|
||||
UNSAFE.copyMemory(inputBase, inputAddress, outputBase, outputAddress, blockSize);
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private static int decodeRleBlock(int size, Object inputBase, long inputAddress, Object outputBase, long outputAddress, long outputLimit)
|
||||
{
|
||||
verify(outputAddress + size <= outputLimit, inputAddress, "Output buffer too small");
|
||||
|
||||
long output = outputAddress;
|
||||
long value = UNSAFE.getByte(inputBase, inputAddress) & 0xFFL;
|
||||
|
||||
int remaining = size;
|
||||
if (remaining >= SIZE_OF_LONG) {
|
||||
long packed = value
|
||||
| (value << 8)
|
||||
| (value << 16)
|
||||
| (value << 24)
|
||||
| (value << 32)
|
||||
| (value << 40)
|
||||
| (value << 48)
|
||||
| (value << 56);
|
||||
|
||||
do {
|
||||
UNSAFE.putLong(outputBase, output, packed);
|
||||
output += SIZE_OF_LONG;
|
||||
remaining -= SIZE_OF_LONG;
|
||||
}
|
||||
while (remaining >= SIZE_OF_LONG);
|
||||
}
|
||||
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
UNSAFE.putByte(outputBase, output, (byte) value);
|
||||
output++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private int decodeCompressedBlock(Object inputBase, final long inputAddress, int blockSize, Object outputBase, long outputAddress, long outputLimit, int windowSize)
|
||||
{
|
||||
long inputLimit = inputAddress + blockSize;
|
||||
long input = inputAddress;
|
||||
|
||||
verify(blockSize <= MAX_BLOCK_SIZE, input, "Expected match length table to be present");
|
||||
verify(blockSize >= MIN_BLOCK_SIZE, input, "Compressed block size too small");
|
||||
|
||||
// decode literals
|
||||
int literalsBlockType = UNSAFE.getByte(inputBase, input) & 0b11;
|
||||
|
||||
switch (literalsBlockType) {
|
||||
case RAW_LITERALS_BLOCK: {
|
||||
input += decodeRawLiterals(inputBase, input, inputLimit);
|
||||
break;
|
||||
}
|
||||
case RLE_LITERALS_BLOCK: {
|
||||
input += decodeRleLiterals(inputBase, input, blockSize);
|
||||
break;
|
||||
}
|
||||
case REPEAT_STATS_LITERALS_BLOCK:
|
||||
verify(huffman.isLoaded(), input, "Dictionary is corrupted");
|
||||
case COMPRESSED_LITERALS_BLOCK: {
|
||||
input += decodeCompressedLiterals(inputBase, input, blockSize, literalsBlockType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw fail(input, "Invalid literals block encoding type");
|
||||
}
|
||||
|
||||
verify(windowSize <= MAX_WINDOW_SIZE, input, "Window size too large (not yet supported)");
|
||||
|
||||
return decompressSequences(
|
||||
inputBase, input, inputAddress + blockSize,
|
||||
outputBase, outputAddress, outputLimit,
|
||||
literalsBase, literalsAddress, literalsLimit);
|
||||
}
|
||||
|
||||
private int decompressSequences(
|
||||
final Object inputBase, final long inputAddress, final long inputLimit,
|
||||
final Object outputBase, final long outputAddress, final long outputLimit,
|
||||
final Object literalsBase, final long literalsAddress, final long literalsLimit)
|
||||
{
|
||||
final long fastOutputLimit = outputLimit - SIZE_OF_LONG;
|
||||
|
||||
long input = inputAddress;
|
||||
long output = outputAddress;
|
||||
|
||||
long literalsInput = literalsAddress;
|
||||
|
||||
int size = (int) (inputLimit - inputAddress);
|
||||
verify(size >= MIN_SEQUENCES_SIZE, input, "Not enough input bytes");
|
||||
|
||||
// decode header
|
||||
int sequenceCount = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
if (sequenceCount != 0) {
|
||||
if (sequenceCount == 255) {
|
||||
verify(input + SIZE_OF_SHORT <= inputLimit, input, "Not enough input bytes");
|
||||
sequenceCount = (UNSAFE.getShort(inputBase, input) & 0xFFFF) + LONG_NUMBER_OF_SEQUENCES;
|
||||
input += SIZE_OF_SHORT;
|
||||
}
|
||||
else if (sequenceCount > 127) {
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
sequenceCount = ((sequenceCount - 128) << 8) + (UNSAFE.getByte(inputBase, input++) & 0xFF);
|
||||
}
|
||||
|
||||
verify(input + SIZE_OF_INT <= inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte type = UNSAFE.getByte(inputBase, input++);
|
||||
|
||||
int literalsLengthType = (type & 0xFF) >>> 6;
|
||||
int offsetCodesType = (type >>> 4) & 0b11;
|
||||
int matchLengthType = (type >>> 2) & 0b11;
|
||||
|
||||
input = computeLiteralsTable(literalsLengthType, inputBase, input, inputLimit);
|
||||
input = computeOffsetsTable(offsetCodesType, inputBase, input, inputLimit);
|
||||
input = computeMatchLengthTable(matchLengthType, inputBase, input, inputLimit);
|
||||
|
||||
// decompress sequences
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, input, inputLimit);
|
||||
initializer.initialize();
|
||||
int bitsConsumed = initializer.getBitsConsumed();
|
||||
long bits = initializer.getBits();
|
||||
long currentAddress = initializer.getCurrentAddress();
|
||||
|
||||
FiniteStateEntropy.Table currentLiteralsLengthTable = this.currentLiteralsLengthTable;
|
||||
FiniteStateEntropy.Table currentOffsetCodesTable = this.currentOffsetCodesTable;
|
||||
FiniteStateEntropy.Table currentMatchLengthTable = this.currentMatchLengthTable;
|
||||
|
||||
int literalsLengthState = (int) peekBits(bitsConsumed, bits, currentLiteralsLengthTable.log2Size);
|
||||
bitsConsumed += currentLiteralsLengthTable.log2Size;
|
||||
|
||||
int offsetCodesState = (int) peekBits(bitsConsumed, bits, currentOffsetCodesTable.log2Size);
|
||||
bitsConsumed += currentOffsetCodesTable.log2Size;
|
||||
|
||||
int matchLengthState = (int) peekBits(bitsConsumed, bits, currentMatchLengthTable.log2Size);
|
||||
bitsConsumed += currentMatchLengthTable.log2Size;
|
||||
|
||||
int[] previousOffsets = this.previousOffsets;
|
||||
|
||||
byte[] literalsLengthNumbersOfBits = currentLiteralsLengthTable.numberOfBits;
|
||||
int[] literalsLengthNewStates = currentLiteralsLengthTable.newState;
|
||||
byte[] literalsLengthSymbols = currentLiteralsLengthTable.symbol;
|
||||
|
||||
byte[] matchLengthNumbersOfBits = currentMatchLengthTable.numberOfBits;
|
||||
int[] matchLengthNewStates = currentMatchLengthTable.newState;
|
||||
byte[] matchLengthSymbols = currentMatchLengthTable.symbol;
|
||||
|
||||
byte[] offsetCodesNumbersOfBits = currentOffsetCodesTable.numberOfBits;
|
||||
int[] offsetCodesNewStates = currentOffsetCodesTable.newState;
|
||||
byte[] offsetCodesSymbols = currentOffsetCodesTable.symbol;
|
||||
|
||||
while (sequenceCount > 0) {
|
||||
sequenceCount--;
|
||||
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (loader.isOverflow()) {
|
||||
verify(sequenceCount == 0, input, "Not all sequences were consumed");
|
||||
break;
|
||||
}
|
||||
|
||||
// decode sequence
|
||||
int literalsLengthCode = literalsLengthSymbols[literalsLengthState];
|
||||
int matchLengthCode = matchLengthSymbols[matchLengthState];
|
||||
int offsetCode = offsetCodesSymbols[offsetCodesState];
|
||||
|
||||
int literalsLengthBits = LITERALS_LENGTH_BITS[literalsLengthCode];
|
||||
int matchLengthBits = MATCH_LENGTH_BITS[matchLengthCode];
|
||||
int offsetBits = offsetCode;
|
||||
|
||||
int offset = OFFSET_CODES_BASE[offsetCode];
|
||||
if (offsetCode > 0) {
|
||||
offset += peekBits(bitsConsumed, bits, offsetBits);
|
||||
bitsConsumed += offsetBits;
|
||||
}
|
||||
|
||||
if (offsetCode <= 1) {
|
||||
if (literalsLengthCode == 0) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (offset != 0) {
|
||||
int temp;
|
||||
if (offset == 3) {
|
||||
temp = previousOffsets[0] - 1;
|
||||
}
|
||||
else {
|
||||
temp = previousOffsets[offset];
|
||||
}
|
||||
|
||||
if (temp == 0) {
|
||||
temp = 1;
|
||||
}
|
||||
|
||||
if (offset != 1) {
|
||||
previousOffsets[2] = previousOffsets[1];
|
||||
}
|
||||
previousOffsets[1] = previousOffsets[0];
|
||||
previousOffsets[0] = temp;
|
||||
|
||||
offset = temp;
|
||||
}
|
||||
else {
|
||||
offset = previousOffsets[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
previousOffsets[2] = previousOffsets[1];
|
||||
previousOffsets[1] = previousOffsets[0];
|
||||
previousOffsets[0] = offset;
|
||||
}
|
||||
|
||||
int matchLength = MATCH_LENGTH_BASE[matchLengthCode];
|
||||
if (matchLengthCode > 31) {
|
||||
matchLength += peekBits(bitsConsumed, bits, matchLengthBits);
|
||||
bitsConsumed += matchLengthBits;
|
||||
}
|
||||
|
||||
int literalsLength = LITERALS_LENGTH_BASE[literalsLengthCode];
|
||||
if (literalsLengthCode > 15) {
|
||||
literalsLength += peekBits(bitsConsumed, bits, literalsLengthBits);
|
||||
bitsConsumed += literalsLengthBits;
|
||||
}
|
||||
|
||||
int totalBits = literalsLengthBits + matchLengthBits + offsetBits;
|
||||
if (totalBits > 64 - 7 - (LITERALS_LENGTH_FSE_LOG + MATCH_LENGTH_FSE_LOG + OFFSET_CODES_FSE_LOG)) {
|
||||
BitStream.Loader loader1 = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader1.load();
|
||||
|
||||
bitsConsumed = loader1.getBitsConsumed();
|
||||
bits = loader1.getBits();
|
||||
currentAddress = loader1.getCurrentAddress();
|
||||
}
|
||||
|
||||
int numberOfBits;
|
||||
|
||||
numberOfBits = literalsLengthNumbersOfBits[literalsLengthState];
|
||||
literalsLengthState = (int) (literalsLengthNewStates[literalsLengthState] + peekBits(bitsConsumed, bits, numberOfBits)); // <= 9 bits
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
numberOfBits = matchLengthNumbersOfBits[matchLengthState];
|
||||
matchLengthState = (int) (matchLengthNewStates[matchLengthState] + peekBits(bitsConsumed, bits, numberOfBits)); // <= 9 bits
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
numberOfBits = offsetCodesNumbersOfBits[offsetCodesState];
|
||||
offsetCodesState = (int) (offsetCodesNewStates[offsetCodesState] + peekBits(bitsConsumed, bits, numberOfBits)); // <= 8 bits
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
final long literalOutputLimit = output + literalsLength;
|
||||
final long matchOutputLimit = literalOutputLimit + matchLength;
|
||||
|
||||
verify(matchOutputLimit <= outputLimit, input, "Output buffer too small");
|
||||
verify(literalsInput + literalsLength <= literalsLimit, input, "Input is corrupted");
|
||||
|
||||
long matchAddress = literalOutputLimit - offset;
|
||||
|
||||
if (literalOutputLimit > fastOutputLimit) {
|
||||
executeLastSequence(outputBase, output, literalOutputLimit, matchOutputLimit, fastOutputLimit, literalsInput, matchAddress);
|
||||
}
|
||||
else {
|
||||
// copy literals. literalOutputLimit <= fastOutputLimit, so we can copy
|
||||
// long at a time with over-copy
|
||||
output = copyLiterals(outputBase, literalsBase, output, literalsInput, literalOutputLimit);
|
||||
copyMatch(outputBase, fastOutputLimit, output, offset, matchOutputLimit, matchAddress);
|
||||
}
|
||||
output = matchOutputLimit;
|
||||
literalsInput += literalsLength;
|
||||
}
|
||||
}
|
||||
|
||||
// last literal segment
|
||||
output = copyLastLiteral(outputBase, literalsBase, literalsLimit, output, literalsInput);
|
||||
|
||||
return (int) (output - outputAddress);
|
||||
}
|
||||
|
||||
private long copyLastLiteral(Object outputBase, Object literalsBase, long literalsLimit, long output, long literalsInput)
|
||||
{
|
||||
long lastLiteralsSize = literalsLimit - literalsInput;
|
||||
UNSAFE.copyMemory(literalsBase, literalsInput, outputBase, output, lastLiteralsSize);
|
||||
output += lastLiteralsSize;
|
||||
return output;
|
||||
}
|
||||
|
||||
private void copyMatch(Object outputBase, long fastOutputLimit, long output, int offset, long matchOutputLimit, long matchAddress)
|
||||
{
|
||||
matchAddress = copyMatchHead(outputBase, output, offset, matchAddress);
|
||||
output += SIZE_OF_LONG;
|
||||
|
||||
copyMatchTail(outputBase, fastOutputLimit, output, matchOutputLimit, matchAddress);
|
||||
}
|
||||
|
||||
private void copyMatchTail(Object outputBase, long fastOutputLimit, long output, long matchOutputLimit, long matchAddress)
|
||||
{
|
||||
if (matchOutputLimit > fastOutputLimit) {
|
||||
while (output < fastOutputLimit) {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(outputBase, matchAddress));
|
||||
matchAddress += SIZE_OF_LONG;
|
||||
output += SIZE_OF_LONG;
|
||||
}
|
||||
|
||||
while (output < matchOutputLimit) {
|
||||
UNSAFE.putByte(outputBase, output++, UNSAFE.getByte(outputBase, matchAddress++));
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (output < matchOutputLimit) {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(outputBase, matchAddress));
|
||||
matchAddress += SIZE_OF_LONG;
|
||||
output += SIZE_OF_LONG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long copyMatchHead(Object outputBase, long output, int offset, long matchAddress)
|
||||
{
|
||||
// copy match
|
||||
if (offset < 8) {
|
||||
// 8 bytes apart so that we can copy long-at-a-time below
|
||||
int increment32 = DEC_32_TABLE[offset];
|
||||
int decrement64 = DEC_64_TABLE[offset];
|
||||
|
||||
UNSAFE.putByte(outputBase, output, UNSAFE.getByte(outputBase, matchAddress));
|
||||
UNSAFE.putByte(outputBase, output + 1, UNSAFE.getByte(outputBase, matchAddress + 1));
|
||||
UNSAFE.putByte(outputBase, output + 2, UNSAFE.getByte(outputBase, matchAddress + 2));
|
||||
UNSAFE.putByte(outputBase, output + 3, UNSAFE.getByte(outputBase, matchAddress + 3));
|
||||
matchAddress += increment32;
|
||||
|
||||
UNSAFE.putInt(outputBase, output + 4, UNSAFE.getInt(outputBase, matchAddress));
|
||||
matchAddress -= decrement64;
|
||||
}
|
||||
else {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(outputBase, matchAddress));
|
||||
matchAddress += SIZE_OF_LONG;
|
||||
}
|
||||
return matchAddress;
|
||||
}
|
||||
|
||||
private long copyLiterals(Object outputBase, Object literalsBase, long output, long literalsInput, long literalOutputLimit)
|
||||
{
|
||||
long literalInput = literalsInput;
|
||||
do {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(literalsBase, literalInput));
|
||||
output += SIZE_OF_LONG;
|
||||
literalInput += SIZE_OF_LONG;
|
||||
}
|
||||
while (output < literalOutputLimit);
|
||||
output = literalOutputLimit; // correction in case we over-copied
|
||||
return output;
|
||||
}
|
||||
|
||||
private long computeMatchLengthTable(int matchLengthType, Object inputBase, long input, long inputLimit)
|
||||
{
|
||||
switch (matchLengthType) {
|
||||
case SET_RLE:
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
verify(value <= MAX_MATCH_LENGTH_SYMBOL, input, "Value exceeds expected maximum value");
|
||||
|
||||
FseTableReader.buildRleTable(matchLengthTable, value);
|
||||
currentMatchLengthTable = matchLengthTable;
|
||||
break;
|
||||
case SET_BASIC:
|
||||
currentMatchLengthTable = DEFAULT_MATCH_LENGTH_TABLE;
|
||||
break;
|
||||
case SET_REPEAT:
|
||||
verify(currentMatchLengthTable != null, input, "Expected match length table to be present");
|
||||
break;
|
||||
case SET_COMPRESSED:
|
||||
input += fse.readFseTable(matchLengthTable, inputBase, input, inputLimit, MAX_MATCH_LENGTH_SYMBOL, MATCH_LENGTH_FSE_LOG);
|
||||
currentMatchLengthTable = matchLengthTable;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid match length encoding type");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private long computeOffsetsTable(int offsetCodesType, Object inputBase, long input, long inputLimit)
|
||||
{
|
||||
switch (offsetCodesType) {
|
||||
case SET_RLE:
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
verify(value <= MAX_OFFSET_CODE_SYMBOL, input, "Value exceeds expected maximum value");
|
||||
|
||||
FseTableReader.buildRleTable(offsetCodesTable, value);
|
||||
currentOffsetCodesTable = offsetCodesTable;
|
||||
break;
|
||||
case SET_BASIC:
|
||||
currentOffsetCodesTable = DEFAULT_OFFSET_CODES_TABLE;
|
||||
break;
|
||||
case SET_REPEAT:
|
||||
verify(currentOffsetCodesTable != null, input, "Expected match length table to be present");
|
||||
break;
|
||||
case SET_COMPRESSED:
|
||||
input += fse.readFseTable(offsetCodesTable, inputBase, input, inputLimit, MAX_OFFSET_CODE_SYMBOL, OFFSET_CODES_FSE_LOG);
|
||||
currentOffsetCodesTable = offsetCodesTable;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid offset code encoding type");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private long computeLiteralsTable(int literalsLengthType, Object inputBase, long input, long inputLimit)
|
||||
{
|
||||
switch (literalsLengthType) {
|
||||
case SET_RLE:
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
verify(value <= MAX_LITERALS_LENGTH_SYMBOL, input, "Value exceeds expected maximum value");
|
||||
|
||||
FseTableReader.buildRleTable(literalsLengthTable, value);
|
||||
currentLiteralsLengthTable = literalsLengthTable;
|
||||
break;
|
||||
case SET_BASIC:
|
||||
currentLiteralsLengthTable = DEFAULT_LITERALS_LENGTH_TABLE;
|
||||
break;
|
||||
case SET_REPEAT:
|
||||
verify(currentLiteralsLengthTable != null, input, "Expected match length table to be present");
|
||||
break;
|
||||
case SET_COMPRESSED:
|
||||
input += fse.readFseTable(literalsLengthTable, inputBase, input, inputLimit, MAX_LITERALS_LENGTH_SYMBOL, LITERALS_LENGTH_FSE_LOG);
|
||||
currentLiteralsLengthTable = literalsLengthTable;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid literals length encoding type");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private void executeLastSequence(Object outputBase, long output, long literalOutputLimit, long matchOutputLimit, long fastOutputLimit, long literalInput, long matchAddress)
|
||||
{
|
||||
// copy literals
|
||||
if (output < fastOutputLimit) {
|
||||
// wild copy
|
||||
do {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(literalsBase, literalInput));
|
||||
output += SIZE_OF_LONG;
|
||||
literalInput += SIZE_OF_LONG;
|
||||
}
|
||||
while (output < fastOutputLimit);
|
||||
|
||||
literalInput -= output - fastOutputLimit;
|
||||
output = fastOutputLimit;
|
||||
}
|
||||
|
||||
while (output < literalOutputLimit) {
|
||||
UNSAFE.putByte(outputBase, output, UNSAFE.getByte(literalsBase, literalInput));
|
||||
output++;
|
||||
literalInput++;
|
||||
}
|
||||
|
||||
// copy match
|
||||
while (output < matchOutputLimit) {
|
||||
UNSAFE.putByte(outputBase, output, UNSAFE.getByte(outputBase, matchAddress));
|
||||
output++;
|
||||
matchAddress++;
|
||||
}
|
||||
}
|
||||
|
||||
private int decodeCompressedLiterals(Object inputBase, final long inputAddress, int blockSize, int literalsBlockType)
|
||||
{
|
||||
long input = inputAddress;
|
||||
verify(blockSize >= 5, input, "Not enough input bytes");
|
||||
|
||||
// compressed
|
||||
int compressedSize;
|
||||
int uncompressedSize;
|
||||
boolean singleStream = false;
|
||||
int headerSize;
|
||||
int type = (UNSAFE.getByte(inputBase, input) >> 2) & 0b11;
|
||||
switch (type) {
|
||||
case 0:
|
||||
singleStream = true;
|
||||
case 1: {
|
||||
int header = UNSAFE.getInt(inputBase, input);
|
||||
|
||||
headerSize = 3;
|
||||
uncompressedSize = (header >>> 4) & mask(10);
|
||||
compressedSize = (header >>> 14) & mask(10);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int header = UNSAFE.getInt(inputBase, input);
|
||||
|
||||
headerSize = 4;
|
||||
uncompressedSize = (header >>> 4) & mask(14);
|
||||
compressedSize = (header >>> 18) & mask(14);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// read 5 little-endian bytes
|
||||
long header = UNSAFE.getByte(inputBase, input) & 0xFF |
|
||||
(UNSAFE.getInt(inputBase, input + 1) & 0xFFFF_FFFFL) << 8;
|
||||
|
||||
headerSize = 5;
|
||||
uncompressedSize = (int) ((header >>> 4) & mask(18));
|
||||
compressedSize = (int) ((header >>> 22) & mask(18));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw fail(input, "Invalid literals header size type");
|
||||
}
|
||||
|
||||
verify(uncompressedSize <= MAX_BLOCK_SIZE, input, "Block exceeds maximum size");
|
||||
verify(headerSize + compressedSize <= blockSize, input, "Input is corrupted");
|
||||
|
||||
input += headerSize;
|
||||
|
||||
long inputLimit = input + compressedSize;
|
||||
if (literalsBlockType != REPEAT_STATS_LITERALS_BLOCK) {
|
||||
input += huffman.readTable(inputBase, input, compressedSize);
|
||||
}
|
||||
|
||||
literalsBase = literals;
|
||||
literalsAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
literalsLimit = ARRAY_BYTE_BASE_OFFSET + uncompressedSize;
|
||||
|
||||
if (singleStream) {
|
||||
huffman.decodeSingleStream(inputBase, input, inputLimit, literals, literalsAddress, literalsLimit);
|
||||
}
|
||||
else {
|
||||
huffman.decode4Streams(inputBase, input, inputLimit, literals, literalsAddress, literalsLimit);
|
||||
}
|
||||
|
||||
return headerSize + compressedSize;
|
||||
}
|
||||
|
||||
private int decodeRleLiterals(Object inputBase, final long inputAddress, int blockSize)
|
||||
{
|
||||
long input = inputAddress;
|
||||
int outputSize;
|
||||
|
||||
int type = (UNSAFE.getByte(inputBase, input) >> 2) & 0b11;
|
||||
switch (type) {
|
||||
case 0:
|
||||
case 2:
|
||||
outputSize = (UNSAFE.getByte(inputBase, input) & 0xFF) >>> 3;
|
||||
input++;
|
||||
break;
|
||||
case 1:
|
||||
outputSize = (UNSAFE.getShort(inputBase, input) & 0xFFFF) >>> 4;
|
||||
input += 2;
|
||||
break;
|
||||
case 3:
|
||||
// we need at least 4 bytes (3 for the header, 1 for the payload)
|
||||
verify(blockSize >= SIZE_OF_INT, input, "Not enough input bytes");
|
||||
outputSize = (UNSAFE.getInt(inputBase, input) & 0xFF_FFFF) >>> 4;
|
||||
input += 3;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid RLE literals header encoding type");
|
||||
}
|
||||
|
||||
verify(outputSize <= MAX_BLOCK_SIZE, input, "Output exceeds maximum block size");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
Arrays.fill(literals, 0, outputSize + SIZE_OF_LONG, value);
|
||||
|
||||
literalsBase = literals;
|
||||
literalsAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
literalsLimit = ARRAY_BYTE_BASE_OFFSET + outputSize;
|
||||
|
||||
return (int) (input - inputAddress);
|
||||
}
|
||||
|
||||
private int decodeRawLiterals(Object inputBase, final long inputAddress, long inputLimit)
|
||||
{
|
||||
long input = inputAddress;
|
||||
int type = (UNSAFE.getByte(inputBase, input) >> 2) & 0b11;
|
||||
|
||||
int literalSize;
|
||||
switch (type) {
|
||||
case 0:
|
||||
case 2:
|
||||
literalSize = (UNSAFE.getByte(inputBase, input) & 0xFF) >>> 3;
|
||||
input++;
|
||||
break;
|
||||
case 1:
|
||||
literalSize = (UNSAFE.getShort(inputBase, input) & 0xFFFF) >>> 4;
|
||||
input += 2;
|
||||
break;
|
||||
case 3:
|
||||
// read 3 little-endian bytes
|
||||
int header = ((UNSAFE.getByte(inputBase, input) & 0xFF) |
|
||||
((UNSAFE.getShort(inputBase, input + 1) & 0xFFFF) << 8));
|
||||
|
||||
literalSize = header >>> 4;
|
||||
input += 3;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid raw literals header encoding type");
|
||||
}
|
||||
|
||||
verify(input + literalSize <= inputLimit, input, "Not enough input bytes");
|
||||
|
||||
// Set literals pointer to [input, literalSize], but only if we can copy 8 bytes at a time during sequence decoding
|
||||
// Otherwise, copy literals into buffer that's big enough to guarantee that
|
||||
if (literalSize > (inputLimit - input) - SIZE_OF_LONG) {
|
||||
literalsBase = literals;
|
||||
literalsAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
literalsLimit = ARRAY_BYTE_BASE_OFFSET + literalSize;
|
||||
|
||||
UNSAFE.copyMemory(inputBase, input, literals, literalsAddress, literalSize);
|
||||
Arrays.fill(literals, literalSize, literalSize + SIZE_OF_LONG, (byte) 0);
|
||||
}
|
||||
else {
|
||||
literalsBase = inputBase;
|
||||
literalsAddress = input;
|
||||
literalsLimit = literalsAddress + literalSize;
|
||||
}
|
||||
input += literalSize;
|
||||
|
||||
return (int) (input - inputAddress);
|
||||
}
|
||||
|
||||
private static FrameHeader readFrameHeader(final Object inputBase, final long inputAddress, final long inputLimit)
|
||||
{
|
||||
long input = inputAddress;
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
int frameHeaderDescriptor = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
boolean singleSegment = (frameHeaderDescriptor & 0b100000) != 0;
|
||||
int dictionaryDescriptor = frameHeaderDescriptor & 0b11;
|
||||
int contentSizeDescriptor = frameHeaderDescriptor >>> 6;
|
||||
|
||||
int headerSize = 1 +
|
||||
(singleSegment ? 0 : 1) +
|
||||
(dictionaryDescriptor == 0 ? 0 : (1 << (dictionaryDescriptor - 1))) +
|
||||
(contentSizeDescriptor == 0 ? (singleSegment ? 1 : 0) : (1 << contentSizeDescriptor));
|
||||
|
||||
verify(headerSize <= inputLimit - inputAddress, input, "Not enough input bytes");
|
||||
|
||||
// decode window size
|
||||
int windowSize = -1;
|
||||
if (!singleSegment) {
|
||||
int windowDescriptor = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
int exponent = windowDescriptor >>> 3;
|
||||
int mantissa = windowDescriptor & 0b111;
|
||||
|
||||
int base = 1 << (MIN_WINDOW_LOG + exponent);
|
||||
windowSize = base + (base / 8) * mantissa;
|
||||
}
|
||||
|
||||
// decode dictionary id
|
||||
long dictionaryId = -1;
|
||||
switch (dictionaryDescriptor) {
|
||||
case 1:
|
||||
dictionaryId = UNSAFE.getByte(inputBase, input) & 0xFF;
|
||||
input += SIZE_OF_BYTE;
|
||||
break;
|
||||
case 2:
|
||||
dictionaryId = UNSAFE.getShort(inputBase, input) & 0xFFFF;
|
||||
input += SIZE_OF_SHORT;
|
||||
break;
|
||||
case 3:
|
||||
dictionaryId = UNSAFE.getInt(inputBase, input) & 0xFFFF_FFFFL;
|
||||
input += SIZE_OF_INT;
|
||||
break;
|
||||
}
|
||||
verify(dictionaryId == -1, input, "Custom dictionaries not supported");
|
||||
|
||||
// decode content size
|
||||
long contentSize = -1;
|
||||
switch (contentSizeDescriptor) {
|
||||
case 0:
|
||||
if (singleSegment) {
|
||||
contentSize = UNSAFE.getByte(inputBase, input) & 0xFF;
|
||||
input += SIZE_OF_BYTE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
contentSize = UNSAFE.getShort(inputBase, input) & 0xFFFF;
|
||||
contentSize += 256;
|
||||
input += SIZE_OF_SHORT;
|
||||
break;
|
||||
case 2:
|
||||
contentSize = UNSAFE.getInt(inputBase, input) & 0xFFFF_FFFFL;
|
||||
input += SIZE_OF_INT;
|
||||
break;
|
||||
case 3:
|
||||
contentSize = UNSAFE.getLong(inputBase, input);
|
||||
input += SIZE_OF_LONG;
|
||||
break;
|
||||
}
|
||||
|
||||
boolean hasChecksum = (frameHeaderDescriptor & 0b100) != 0;
|
||||
|
||||
return new FrameHeader(
|
||||
input - inputAddress,
|
||||
windowSize,
|
||||
contentSize,
|
||||
dictionaryId,
|
||||
hasChecksum);
|
||||
}
|
||||
|
||||
public static long getDecompressedSize(final Object inputBase, final long inputAddress, final long inputLimit)
|
||||
{
|
||||
long input = inputAddress;
|
||||
input += verifyMagic(inputBase, input, inputLimit);
|
||||
return readFrameHeader(inputBase, input, inputLimit).contentSize;
|
||||
}
|
||||
|
||||
private static int verifyMagic(Object inputBase, long inputAddress, long inputLimit)
|
||||
{
|
||||
verify(inputLimit - inputAddress >= 4, inputAddress, "Not enough input bytes");
|
||||
|
||||
int magic = UNSAFE.getInt(inputBase, inputAddress);
|
||||
if (magic != MAGIC_NUMBER) {
|
||||
throw new MalformedInputException(inputAddress, "Invalid magic prefix: " + Integer.toHexString(magic));
|
||||
}
|
||||
|
||||
return SIZE_OF_INT;
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@ public class ReflectionUtils {
|
||||
return t.isInstance(o) ? t.cast(o) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName) {
|
||||
try {
|
||||
return addEnum(enumType, enumName, new Class<?>[]{}, new Object[]{});
|
||||
|
@ -157,19 +157,6 @@ public class PlayerWrapper extends AbstractPlayerActor {
|
||||
parent.setGameMode(gameMode);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
@Override
|
||||
public void findFreePosition(final Location searchPos) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
|
Reference in New Issue
Block a user