update code style
This commit is contained in:
@@ -151,7 +151,7 @@ public final class Launcher {
|
|||||||
|
|
||||||
int flag = 0;
|
int flag = 0;
|
||||||
try {
|
try {
|
||||||
minecraftMain.invoke(null, new Object[]{(String[]) cmdList.toArray(new String[cmdList.size()])});
|
minecraftMain.invoke(null, new Object[] { (String[]) cmdList.toArray(new String[cmdList.size()]) });
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
String trace = StrUtils.getStackTrace(throwable);
|
String trace = StrUtils.getStackTrace(throwable);
|
||||||
final String advice = MinecraftCrashAdvicer.getAdvice(trace);
|
final String advice = MinecraftCrashAdvicer.getAdvice(trace);
|
||||||
@@ -174,15 +174,16 @@ public final class Launcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
static Object getShutdownHaltLock() {
|
* static Object getShutdownHaltLock() {
|
||||||
try {
|
* try {
|
||||||
Class z = Class.forName("java.lang.Shutdown");
|
* Class z = Class.forName("java.lang.Shutdown");
|
||||||
Field haltLock = z.getDeclaredField("haltLock");
|
* Field haltLock = z.getDeclaredField("haltLock");
|
||||||
haltLock.setAccessible(true);
|
* haltLock.setAccessible(true);
|
||||||
return haltLock.get(null);
|
* return haltLock.get(null);
|
||||||
} catch (Throwable ex) {
|
* } catch (Throwable ex) {
|
||||||
ex.printStackTrace();
|
* ex.printStackTrace();
|
||||||
return new Object();
|
* return new Object();
|
||||||
}
|
* }
|
||||||
}*/
|
* }
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public final class Main implements Runnable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
sslContext = SSLContext.getInstance("TLS");
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
X509TrustManager[] xtmArray = new X509TrustManager[]{XTM};
|
X509TrustManager[] xtmArray = new X509TrustManager[] { XTM };
|
||||||
sslContext.init(null, xtmArray, new java.security.SecureRandom());
|
sslContext.init(null, xtmArray, new java.security.SecureRandom());
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ public final class Main implements Runnable {
|
|||||||
public static final Main INSTANCE = new Main();
|
public static final Main INSTANCE = new Main();
|
||||||
public static HelloMinecraftLookAndFeel LOOK_AND_FEEL;
|
public static HelloMinecraftLookAndFeel LOOK_AND_FEEL;
|
||||||
|
|
||||||
@SuppressWarnings({"CallToPrintStackTrace", "UseSpecificCatch"})
|
@SuppressWarnings({ "CallToPrintStackTrace", "UseSpecificCatch" })
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
{
|
{
|
||||||
//PluginManager.getServerPlugin();
|
//PluginManager.getServerPlugin();
|
||||||
@@ -147,7 +147,7 @@ public final class Main implements Runnable {
|
|||||||
|
|
||||||
Settings.UPDATE_CHECKER.outdated.register(IUpgrader.NOW_UPGRADER);
|
Settings.UPDATE_CHECKER.outdated.register(IUpgrader.NOW_UPGRADER);
|
||||||
Settings.UPDATE_CHECKER.process(false).subscribeOn(Schedulers.newThread()).subscribe(t
|
Settings.UPDATE_CHECKER.process(false).subscribeOn(Schedulers.newThread()).subscribe(t
|
||||||
-> Main.invokeUpdate());
|
-> Main.invokeUpdate());
|
||||||
|
|
||||||
if (StrUtils.isNotBlank(Settings.getInstance().getProxyHost()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPort()) && MathUtils.canParseInt(Settings.getInstance().getProxyPort())) {
|
if (StrUtils.isNotBlank(Settings.getInstance().getProxyHost()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPort()) && MathUtils.canParseInt(Settings.getInstance().getProxyPort())) {
|
||||||
HMCLog.log("Initializing customized proxy");
|
HMCLog.log("Initializing customized proxy");
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public interface IPlugin {
|
|||||||
* You can modify the application actions by this method.
|
* You can modify the application actions by this method.
|
||||||
*
|
*
|
||||||
* @param profile info to the Minecraft Loader
|
* @param profile info to the Minecraft Loader
|
||||||
|
*
|
||||||
* @return For example, you can implement IMinecraftProvider to support
|
* @return For example, you can implement IMinecraftProvider to support
|
||||||
* MultiMC
|
* MultiMC
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.jackhuang.hellominecraft.launcher.launch;
|
package org.jackhuang.hellominecraft.launcher.launch;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import org.jackhuang.hellominecraft.C;
|
import org.jackhuang.hellominecraft.C;
|
||||||
import org.jackhuang.hellominecraft.HMCLog;
|
import org.jackhuang.hellominecraft.HMCLog;
|
||||||
import org.jackhuang.hellominecraft.launcher.launch.GameLauncher.DownloadLibraryJob;
|
import org.jackhuang.hellominecraft.launcher.launch.GameLauncher.DownloadLibraryJob;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class GameLauncher {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> lst = null;
|
List<String> lst;
|
||||||
try {
|
try {
|
||||||
lst = loader.makeLaunchingCommand();
|
lst = loader.makeLaunchingCommand();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -146,7 +146,7 @@ public class GameLauncher {
|
|||||||
if (get == null || get.getSelectedMinecraftVersion() == null || StrUtils.isBlank(get.getCanonicalGameDir()))
|
if (get == null || get.getSelectedMinecraftVersion() == null || StrUtils.isBlank(get.getCanonicalGameDir()))
|
||||||
throw new Error("Fucking bug!");
|
throw new Error("Fucking bug!");
|
||||||
builder.directory(provider.getRunDirectory(get.getSelectedMinecraftVersion().id))
|
builder.directory(provider.getRunDirectory(get.getSelectedMinecraftVersion().id))
|
||||||
.environment().put("APPDATA", get.getCanonicalGameDir());
|
.environment().put("APPDATA", get.getCanonicalGameDir());
|
||||||
JavaProcess jp = new JavaProcess(str, builder.start(), PROCESS_MANAGER);
|
JavaProcess jp = new JavaProcess(str, builder.start(), PROCESS_MANAGER);
|
||||||
launchEvent.execute(jp);
|
launchEvent.execute(jp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -159,7 +159,7 @@ public class GameLauncher {
|
|||||||
* According to the name...
|
* According to the name...
|
||||||
*
|
*
|
||||||
* @param launcherName the name of launch bat/sh
|
* @param launcherName the name of launch bat/sh
|
||||||
* @param str launch command
|
* @param str launch command
|
||||||
*
|
*
|
||||||
* @return launcher location
|
* @return launcher location
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ public abstract class IMinecraftDownloadService extends IMinecraftService {
|
|||||||
|
|
||||||
public abstract boolean downloadMinecraftVersionJson(String id);
|
public abstract boolean downloadMinecraftVersionJson(String id);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the libraries that need to download.
|
* Get the libraries that need to download.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public abstract class IMinecraftProvider {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param v should be resolved
|
* @param v should be resolved
|
||||||
|
*
|
||||||
* @return libraries of resolved minecraft version v.
|
* @return libraries of resolved minecraft version v.
|
||||||
*/
|
*/
|
||||||
public abstract GameLauncher.DecompressLibraryJob getDecompressLibraries(MinecraftVersion v);
|
public abstract GameLauncher.DecompressLibraryJob getDecompressLibraries(MinecraftVersion v);
|
||||||
@@ -106,7 +107,7 @@ public abstract class IMinecraftProvider {
|
|||||||
* Rename version
|
* Rename version
|
||||||
*
|
*
|
||||||
* @param from The old name
|
* @param from The old name
|
||||||
* @param to The new name
|
* @param to The new name
|
||||||
*
|
*
|
||||||
* @return Is the action successful?
|
* @return Is the action successful?
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.jackhuang.hellominecraft.launcher.settings.Profile;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public abstract class IMinecraftService {
|
public abstract class IMinecraftService {
|
||||||
|
|
||||||
public Profile profile;
|
public Profile profile;
|
||||||
|
|
||||||
public IMinecraftService(Profile profile) {
|
public IMinecraftService(Profile profile) {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class LibraryDownloadTask extends FileDownloadTask {
|
|||||||
|
|
||||||
@SuppressWarnings("UnusedAssignment")
|
@SuppressWarnings("UnusedAssignment")
|
||||||
public static void unpackLibrary(File output, File input)
|
public static void unpackLibrary(File output, File input)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
HMCLog.log("Unpacking " + input);
|
HMCLog.log("Unpacking " + input);
|
||||||
if (output.exists())
|
if (output.exists())
|
||||||
output.delete();
|
output.delete();
|
||||||
|
|||||||
@@ -33,21 +33,21 @@ public final class MCUtils {
|
|||||||
String userhome = System.getProperty("user.home", ".");
|
String userhome = System.getProperty("user.home", ".");
|
||||||
File file;
|
File file;
|
||||||
switch (OS.os()) {
|
switch (OS.os()) {
|
||||||
case LINUX:
|
case LINUX:
|
||||||
|
file = new File(userhome, '.' + baseName + '/');
|
||||||
|
break;
|
||||||
|
case WINDOWS:
|
||||||
|
String appdata = System.getenv("APPDATA");
|
||||||
|
if (appdata != null)
|
||||||
|
file = new File(appdata, "." + baseName + '/');
|
||||||
|
else
|
||||||
file = new File(userhome, '.' + baseName + '/');
|
file = new File(userhome, '.' + baseName + '/');
|
||||||
break;
|
break;
|
||||||
case WINDOWS:
|
case OSX:
|
||||||
String appdata = System.getenv("APPDATA");
|
file = new File(userhome, "Library/Application Support/" + baseName);
|
||||||
if (appdata != null)
|
break;
|
||||||
file = new File(appdata, "." + baseName + '/');
|
default:
|
||||||
else
|
file = new File(userhome, baseName + '/');
|
||||||
file = new File(userhome, '.' + baseName + '/');
|
|
||||||
break;
|
|
||||||
case OSX:
|
|
||||||
file = new File(userhome, "Library/Application Support/" + baseName);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
file = new File(userhome, baseName + '/');
|
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ public class ModInfo implements Comparable<ModInfo> {
|
|||||||
ModInfo i = new ModInfo();
|
ModInfo i = new ModInfo();
|
||||||
i.location = f;
|
i.location = f;
|
||||||
List<ModInfo> m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
List<ModInfo> m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
||||||
new TypeToken<List<ModInfo>>() {
|
new TypeToken<List<ModInfo>>() {
|
||||||
}.getType());
|
}.getType());
|
||||||
if (m != null && m.size() > 0) {
|
if (m != null && m.size() > 0) {
|
||||||
i = m.get(0);
|
i = m.get(0);
|
||||||
i.location = f;
|
i.location = f;
|
||||||
@@ -123,7 +123,7 @@ public class ModInfo implements Comparable<ModInfo> {
|
|||||||
|
|
||||||
private static ModInfo getLiteLoaderModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
|
private static ModInfo getLiteLoaderModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
|
||||||
ModInfo m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
ModInfo m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
||||||
ModInfo.class);
|
ModInfo.class);
|
||||||
if (m == null)
|
if (m == null)
|
||||||
m = new ModInfo();
|
m = new ModInfo();
|
||||||
m.location = f;
|
m.location = f;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hellominecraft.launcher.utils.assets;
|
package org.jackhuang.hellominecraft.launcher.utils.assets;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
|
|||||||
@@ -48,29 +48,29 @@ public final class BestLogin extends IAuthenticator {
|
|||||||
InputStream is = socket.getInputStream();
|
InputStream is = socket.getInputStream();
|
||||||
int code = is.read();
|
int code = is.read();
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case -1:
|
case -1:
|
||||||
throw new AuthenticationException("internet error.");
|
throw new AuthenticationException("internet error.");
|
||||||
case 200:
|
case 200:
|
||||||
throw new AuthenticationException("server restarting.");
|
throw new AuthenticationException("server restarting.");
|
||||||
case 255:
|
case 255:
|
||||||
throw new AuthenticationException("unknown error");
|
throw new AuthenticationException("unknown error");
|
||||||
case 3:
|
case 3:
|
||||||
throw new AuthenticationException("unregistered.");
|
throw new AuthenticationException("unregistered.");
|
||||||
case 50:
|
case 50:
|
||||||
throw new AuthenticationException("please update your launcher and act your account.");
|
throw new AuthenticationException("please update your launcher and act your account.");
|
||||||
case 2:
|
case 2:
|
||||||
throw new AuthenticationException("wrong password.");
|
throw new AuthenticationException("wrong password.");
|
||||||
case 100:
|
case 100:
|
||||||
throw new AuthenticationException("server reloading.");
|
throw new AuthenticationException("server reloading.");
|
||||||
case 0:
|
case 0:
|
||||||
byte[] b = new byte[64];
|
byte[] b = new byte[64];
|
||||||
is.read(b, 0, b.length);
|
is.read(b, 0, b.length);
|
||||||
String[] ss = new String(b).split(":");
|
String[] ss = new String(b).split(":");
|
||||||
lr.setUserName(info.username);
|
lr.setUserName(info.username);
|
||||||
lr.setUserId(ss[1]);
|
lr.setUserId(ss[1]);
|
||||||
lr.setSession(ss[0]);
|
lr.setSession(ss[0]);
|
||||||
lr.setAccessToken(ss[0]);
|
lr.setAccessToken(ss[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lr.setUserType("Legacy");
|
lr.setUserType("Legacy");
|
||||||
return lr;
|
return lr;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public abstract class IAuthenticator {
|
|||||||
* @param info username & password
|
* @param info username & password
|
||||||
*
|
*
|
||||||
* @return login result
|
* @return login result
|
||||||
|
*
|
||||||
* @throws
|
* @throws
|
||||||
* org.jackhuang.hellominecraft.launcher.utils.auth.AuthenticationException
|
* org.jackhuang.hellominecraft.launcher.utils.auth.AuthenticationException
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public class PropertyMap extends HashMap<String, Property> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class LegacySerializer
|
public static class LegacySerializer
|
||||||
implements JsonSerializer<PropertyMap> {
|
implements JsonSerializer<PropertyMap> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
|
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ import org.jackhuang.hellominecraft.utils.StrUtils;
|
|||||||
public class YggdrasilAuthentication {
|
public class YggdrasilAuthentication {
|
||||||
|
|
||||||
public static final Gson GSON = new GsonBuilder()
|
public static final Gson GSON = new GsonBuilder()
|
||||||
.registerTypeAdapter(GameProfile.class, new GameProfile.GameProfileSerializer())
|
.registerTypeAdapter(GameProfile.class, new GameProfile.GameProfileSerializer())
|
||||||
.registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer())
|
.registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer())
|
||||||
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
||||||
|
|
||||||
protected static final String BASE_URL = "https://authserver.mojang.com/";
|
protected static final String BASE_URL = "https://authserver.mojang.com/";
|
||||||
protected static final URL ROUTE_AUTHENTICATE = NetUtils.constantURL(BASE_URL + "authenticate");
|
protected static final URL ROUTE_AUTHENTICATE = NetUtils.constantURL(BASE_URL + "authenticate");
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import org.jackhuang.hellominecraft.launcher.utils.installers.InstallerVersionLi
|
|||||||
public abstract class IDownloadProvider {
|
public abstract class IDownloadProvider {
|
||||||
|
|
||||||
public InstallerVersionList getInstallerByType(InstallerType type) {
|
public InstallerVersionList getInstallerByType(InstallerType type) {
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case Forge:
|
case Forge:
|
||||||
return getForgeInstaller();
|
return getForgeInstaller();
|
||||||
case LiteLoader:
|
case LiteLoader:
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ public final class InstallerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Task download(InstallerVersion v, InstallerType type) {
|
public Task download(InstallerVersion v, InstallerType type) {
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case Forge:
|
case Forge:
|
||||||
return downloadForge(v);
|
return downloadForge(v);
|
||||||
case Optifine:
|
case Optifine:
|
||||||
return downloadOptifine(v);
|
return downloadOptifine(v);
|
||||||
case LiteLoader:
|
case LiteLoader:
|
||||||
return downloadLiteLoader(v);
|
return downloadLiteLoader(v);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,9 +63,9 @@ public final class InstallerService {
|
|||||||
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "forge-installer.jar");
|
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "forge-installer.jar");
|
||||||
if (v.installer != null)
|
if (v.installer != null)
|
||||||
TaskWindow.getInstance()
|
TaskWindow.getInstance()
|
||||||
.addTask(new FileDownloadTask(p.getDownloadType().getProvider().getParsedLibraryDownloadURL(v.installer), filepath).setTag("forge"))
|
.addTask(new FileDownloadTask(p.getDownloadType().getProvider().getParsedLibraryDownloadURL(v.installer), filepath).setTag("forge"))
|
||||||
.addTask(new ForgeInstaller(p.getMinecraftProvider(), filepath, v))
|
.addTask(new ForgeInstaller(p.getMinecraftProvider(), filepath, v))
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -78,9 +78,9 @@ public final class InstallerService {
|
|||||||
if (v.installer != null) {
|
if (v.installer != null) {
|
||||||
OptiFineDownloadFormatter task = new OptiFineDownloadFormatter(v.installer);
|
OptiFineDownloadFormatter task = new OptiFineDownloadFormatter(v.installer);
|
||||||
TaskWindow.getInstance().addTask(task)
|
TaskWindow.getInstance().addTask(task)
|
||||||
.addTask(new FileDownloadTask(filepath).registerPreviousResult(task).setTag("optifine"))
|
.addTask(new FileDownloadTask(filepath).registerPreviousResult(task).setTag("optifine"))
|
||||||
.addTask(new OptiFineInstaller(p, v.selfVersion, filepath))
|
.addTask(new OptiFineInstaller(p, v.selfVersion, filepath))
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -93,8 +93,8 @@ public final class InstallerService {
|
|||||||
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "liteloader-universal.jar");
|
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "liteloader-universal.jar");
|
||||||
FileDownloadTask task = (FileDownloadTask) new FileDownloadTask(v.universal, filepath).setTag("LiteLoader");
|
FileDownloadTask task = (FileDownloadTask) new FileDownloadTask(v.universal, filepath).setTag("LiteLoader");
|
||||||
TaskWindow.getInstance()
|
TaskWindow.getInstance()
|
||||||
.addTask(task).addTask(new LiteLoaderInstaller(p, (LiteLoaderVersionList.LiteLoaderInstallerVersion) v).registerPreviousResult(task))
|
.addTask(task).addTask(new LiteLoaderInstaller(p, (LiteLoaderVersionList.LiteLoaderInstallerVersion) v).registerPreviousResult(task))
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public enum InstallerType {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getLocalizedName() {
|
public String getLocalizedName() {
|
||||||
return this.name();
|
return this.name();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public abstract class InstallerVersionList implements Consumer<String[]> {
|
|||||||
* Get installers you want.
|
* Get installers you want.
|
||||||
*
|
*
|
||||||
* @param mcVersion the installers to this Minecraft version.
|
* @param mcVersion the installers to this Minecraft version.
|
||||||
|
*
|
||||||
* @return cached result.
|
* @return cached result.
|
||||||
*/
|
*/
|
||||||
protected abstract List<InstallerVersion> getVersionsImpl(String mcVersion);
|
protected abstract List<InstallerVersion> getVersionsImpl(String mcVersion);
|
||||||
@@ -56,8 +57,9 @@ public abstract class InstallerVersionList implements Consumer<String[]> {
|
|||||||
* Get installers you want, please cache this method's result to save time.
|
* Get installers you want, please cache this method's result to save time.
|
||||||
*
|
*
|
||||||
* @param mcVersion the installers to this Minecraft version.
|
* @param mcVersion the installers to this Minecraft version.
|
||||||
|
*
|
||||||
* @return a copy of the cached data to prevent
|
* @return a copy of the cached data to prevent
|
||||||
* ConcurrentModificationException.
|
* ConcurrentModificationException.
|
||||||
*/
|
*/
|
||||||
public List<InstallerVersion> getVersions(String mcVersion) {
|
public List<InstallerVersion> getVersions(String mcVersion) {
|
||||||
List<InstallerVersion> a = getVersionsImpl(mcVersion);
|
List<InstallerVersion> a = getVersionsImpl(mcVersion);
|
||||||
|
|||||||
@@ -76,9 +76,11 @@ public class ForgeInstaller extends Task {
|
|||||||
FileUtils.copyFile(new File(from, profile.install.minecraft + ".jar"),
|
FileUtils.copyFile(new File(from, profile.install.minecraft + ".jar"),
|
||||||
new File(to, profile.install.target + ".jar"));
|
new File(to, profile.install.target + ".jar"));
|
||||||
HMCLog.log("Creating new version profile..." + profile.install.target + ".json");
|
HMCLog.log("Creating new version profile..." + profile.install.target + ".json");
|
||||||
/*for (MinecraftLibrary library : profile.versionInfo.libraries)
|
/*
|
||||||
if (library.name.startsWith("net.minecraftforge:forge:"))
|
* for (MinecraftLibrary library : profile.versionInfo.libraries)
|
||||||
library.url = installerVersion.universal;*/
|
* if (library.name.startsWith("net.minecraftforge:forge:"))
|
||||||
|
* library.url = installerVersion.universal;
|
||||||
|
*/
|
||||||
FileUtils.write(new File(to, profile.install.target + ".json"), C.gsonPrettyPrinting.toJson(profile.versionInfo));
|
FileUtils.write(new File(to, profile.install.target + ".json"), C.gsonPrettyPrinting.toJson(profile.versionInfo));
|
||||||
|
|
||||||
HMCLog.log("Extracting universal forge pack..." + profile.install.filePath);
|
HMCLog.log("Extracting universal forge pack..." + profile.install.filePath);
|
||||||
|
|||||||
@@ -72,15 +72,15 @@ public class MinecraftForgeVersionList extends InstallerVersionList {
|
|||||||
String filename = root.artifact + "-" + ver + "-" + f[1] + "." + f[0];
|
String filename = root.artifact + "-" + ver + "-" + f[1] + "." + f[0];
|
||||||
String url = Settings.getInstance().getDownloadSource().getProvider().getParsedLibraryDownloadURL(root.webpath + ver + "/" + filename);
|
String url = Settings.getInstance().getDownloadSource().getProvider().getParsedLibraryDownloadURL(root.webpath + ver + "/" + filename);
|
||||||
switch (f[1]) {
|
switch (f[1]) {
|
||||||
case "installer":
|
case "installer":
|
||||||
iv.installer = url;
|
iv.installer = url;
|
||||||
break;
|
break;
|
||||||
case "universal":
|
case "universal":
|
||||||
iv.universal = url;
|
iv.universal = url;
|
||||||
break;
|
break;
|
||||||
case "changelog":
|
case "changelog":
|
||||||
iv.changelog = url;
|
iv.changelog = url;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StrUtils.isBlank(iv.installer) || StrUtils.isBlank(iv.universal))
|
if (StrUtils.isBlank(iv.installer) || StrUtils.isBlank(iv.universal))
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class OptiFineBMCLVersionList extends InstallerVersionList {
|
|||||||
if (s == null)
|
if (s == null)
|
||||||
return;
|
return;
|
||||||
root = C.gson.fromJson(s, new TypeToken<ArrayList<OptiFineVersion>>() {
|
root = C.gson.fromJson(s, new TypeToken<ArrayList<OptiFineVersion>>() {
|
||||||
}.getType());
|
}.getType());
|
||||||
for (OptiFineVersion v : root) {
|
for (OptiFineVersion v : root) {
|
||||||
v.mirror = v.mirror.replace("http://optifine.net/http://optifine.net/", "http://optifine.net/");
|
v.mirror = v.mirror.replace("http://optifine.net/http://optifine.net/", "http://optifine.net/");
|
||||||
|
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ public class AppDataUpgrader extends IUpgrader {
|
|||||||
if (mainClass != null) {
|
if (mainClass != null) {
|
||||||
ArrayList<String> al = new ArrayList<>(Arrays.asList(args));
|
ArrayList<String> al = new ArrayList<>(Arrays.asList(args));
|
||||||
al.add("notfound");
|
al.add("notfound");
|
||||||
new URLClassLoader(new URL[] {jar.toURI().toURL()},
|
new URLClassLoader(new URL[] { jar.toURI().toURL() },
|
||||||
URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass)
|
URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass)
|
||||||
.getMethod("main", String[].class).invoke(null, new Object[] {al.toArray(new String[0])});
|
.getMethod("main", String[].class).invoke(null, new Object[] { al.toArray(new String[0]) });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ public class AppDataUpgrader extends IUpgrader {
|
|||||||
if (map != null && map.containsKey("pack"))
|
if (map != null && map.containsKey("pack"))
|
||||||
try {
|
try {
|
||||||
if (TaskWindow.getInstance().addTask(new AppDataUpgraderTask(map.get("pack"), number.version)).start()) {
|
if (TaskWindow.getInstance().addTask(new AppDataUpgraderTask(map.get("pack"), number.version)).start()) {
|
||||||
new ProcessBuilder(new String[] {IOUtils.getJavaDir(), "-jar", AppDataUpgraderTask.getSelf(number.version).getAbsolutePath()}).directory(new File(".")).start();
|
new ProcessBuilder(new String[] { IOUtils.getJavaDir(), "-jar", AppDataUpgraderTask.getSelf(number.version).getAbsolutePath() }).directory(new File(".")).start();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public abstract class IUpgrader implements Event<VersionNumber> {
|
|||||||
*
|
*
|
||||||
* @param nowVersion now launcher version
|
* @param nowVersion now launcher version
|
||||||
* @param args Application CommandLine Arguments
|
* @param args Application CommandLine Arguments
|
||||||
|
*
|
||||||
* @return true if it is needed to break the main thread to shutdown this
|
* @return true if it is needed to break the main thread to shutdown this
|
||||||
* application.
|
* application.
|
||||||
*/
|
*/
|
||||||
@@ -45,6 +46,7 @@ public abstract class IUpgrader implements Event<VersionNumber> {
|
|||||||
*
|
*
|
||||||
* @param sender Should be VersionChecker
|
* @param sender Should be VersionChecker
|
||||||
* @param number the newest version
|
* @param number the newest version
|
||||||
|
*
|
||||||
* @return should return true
|
* @return should return true
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class NewFileUpgrader extends IUpgrader {
|
|||||||
File newf = new File(FileUtils.getName(str));
|
File newf = new File(FileUtils.getName(str));
|
||||||
if (TaskWindow.getInstance().addTask(new FileDownloadTask(str, newf)).start()) {
|
if (TaskWindow.getInstance().addTask(new FileDownloadTask(str, newf)).start()) {
|
||||||
try {
|
try {
|
||||||
new ProcessBuilder(new String[] {IOUtils.tryGetCanonicalFilePath(newf), "--removeOldLauncher", IOUtils.getRealPath()}).directory(new File(".")).start();
|
new ProcessBuilder(new String[] { IOUtils.tryGetCanonicalFilePath(newf), "--removeOldLauncher", IOUtils.getRealPath() }).directory(new File(".")).start();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
HMCLog.err("Failed to start new app", ex);
|
HMCLog.err("Failed to start new app", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import rx.Observable;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public class MinecraftDownloadService extends IMinecraftDownloadService {
|
public class MinecraftDownloadService extends IMinecraftDownloadService {
|
||||||
|
|
||||||
MinecraftVersionManager mgr;
|
MinecraftVersionManager mgr;
|
||||||
|
|
||||||
public MinecraftDownloadService(Profile p, MinecraftVersionManager mgr) {
|
public MinecraftDownloadService(Profile p, MinecraftVersionManager mgr) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import org.jackhuang.hellominecraft.utils.ArrayUtils;
|
|||||||
public class MinecraftVersion implements Cloneable, Comparable<MinecraftVersion> {
|
public class MinecraftVersion implements Cloneable, Comparable<MinecraftVersion> {
|
||||||
|
|
||||||
public String minecraftArguments, mainClass, time, id, type, processArguments,
|
public String minecraftArguments, mainClass, time, id, type, processArguments,
|
||||||
releaseTime, assets, jar, inheritsFrom;
|
releaseTime, assets, jar, inheritsFrom;
|
||||||
public int minimumLauncherVersion;
|
public int minimumLauncherVersion;
|
||||||
public boolean hidden;
|
public boolean hidden;
|
||||||
|
|
||||||
@@ -88,13 +88,13 @@ public class MinecraftVersion implements Cloneable, Comparable<MinecraftVersion>
|
|||||||
}
|
}
|
||||||
parent = parent.resolve(manager, resolvedSoFar);
|
parent = parent.resolve(manager, resolvedSoFar);
|
||||||
MinecraftVersion result = new MinecraftVersion(
|
MinecraftVersion result = new MinecraftVersion(
|
||||||
this.minecraftArguments != null ? this.minecraftArguments : parent.minecraftArguments,
|
this.minecraftArguments != null ? this.minecraftArguments : parent.minecraftArguments,
|
||||||
this.mainClass != null ? this.mainClass : parent.mainClass,
|
this.mainClass != null ? this.mainClass : parent.mainClass,
|
||||||
this.time, this.id, this.type, parent.processArguments, this.releaseTime,
|
this.time, this.id, this.type, parent.processArguments, this.releaseTime,
|
||||||
this.assets != null ? this.assets : parent.assets,
|
this.assets != null ? this.assets : parent.assets,
|
||||||
this.jar != null ? this.jar : parent.jar,
|
this.jar != null ? this.jar : parent.jar,
|
||||||
null, parent.minimumLauncherVersion,
|
null, parent.minimumLauncherVersion,
|
||||||
this.libraries != null ? ArrayUtils.merge(this.libraries, parent.libraries) : parent.libraries, this.hidden);
|
this.libraries != null ? ArrayUtils.merge(this.libraries, parent.libraries) : parent.libraries, this.hidden);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,10 +273,10 @@ public class MinecraftVersionManager extends IMinecraftProvider {
|
|||||||
for (MinecraftVersion s : getVersions()) {
|
for (MinecraftVersion s : getVersions()) {
|
||||||
FileUtils.deleteDirectoryQuietly(new File(profile.getGameDirFile(), "versions" + File.separator + s.id + File.separator + s.id + "-natives"));
|
FileUtils.deleteDirectoryQuietly(new File(profile.getGameDirFile(), "versions" + File.separator + s.id + File.separator + s.id + "-natives"));
|
||||||
File f = getRunDirectory(s.id);
|
File f = getRunDirectory(s.id);
|
||||||
String[] dir = {"logs", "asm", "NVIDIA", "crash-reports", "server-resource-packs", "natives", "native"};
|
String[] dir = { "logs", "asm", "NVIDIA", "crash-reports", "server-resource-packs", "natives", "native" };
|
||||||
for (String str : dir)
|
for (String str : dir)
|
||||||
FileUtils.deleteDirectoryQuietly(new File(f, str));
|
FileUtils.deleteDirectoryQuietly(new File(f, str));
|
||||||
String[] files = {"output-client.log", "usercache.json", "usernamecache.json", "hmclmc.log"};
|
String[] files = { "output-client.log", "usercache.json", "usernamecache.json", "hmclmc.log" };
|
||||||
for (String str : files)
|
for (String str : files)
|
||||||
new File(f, str).delete();
|
new File(f, str).delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import javax.swing.JFrame;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public class DraggableFrame extends JFrame
|
public class DraggableFrame extends JFrame
|
||||||
implements MouseListener, MouseMotionListener {
|
implements MouseListener, MouseMotionListener {
|
||||||
|
|
||||||
private int dragGripX;
|
private int dragGripX;
|
||||||
private int dragGripY;
|
private int dragGripY;
|
||||||
|
|||||||
@@ -42,10 +42,9 @@ public class GameDownloadPanel extends AnimatedPanel implements Selectable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to
|
* This method is called from within the constructor to initialize the form.
|
||||||
* initialize the form.
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
* WARNING: Do NOT modify this code. The content of this method is
|
* regenerated by the Form Editor.
|
||||||
* always regenerated by the Form Editor.
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
@@ -110,8 +109,8 @@ public class GameDownloadPanel extends AnimatedPanel implements Selectable {
|
|||||||
DefaultTableModel model = SwingUtils.clearDefaultTable(lstDownloads);
|
DefaultTableModel model = SwingUtils.clearDefaultTable(lstDownloads);
|
||||||
gsp.getProfile().getMinecraftProvider().getDownloadService().getRemoteVersions()
|
gsp.getProfile().getMinecraftProvider().getDownloadService().getRemoteVersions()
|
||||||
.observeOn(Schedulers.eventQueue()).subscribeOn(Schedulers.newThread())
|
.observeOn(Schedulers.eventQueue()).subscribeOn(Schedulers.newThread())
|
||||||
.subscribe((ver) -> model.addRow(new Object[] {ver.id, ver.time,
|
.subscribe((ver) -> model.addRow(new Object[] { ver.id, ver.time,
|
||||||
StrUtils.equalsOne(ver.type, "old_beta", "old_alpha", "release", "snapshot") ? C.i18n("versions." + ver.type) : ver.type}),
|
StrUtils.equalsOne(ver.type, "old_beta", "old_alpha", "release", "snapshot") ? C.i18n("versions." + ver.type) : ver.type }),
|
||||||
(e) -> {
|
(e) -> {
|
||||||
MessageBox.Show("Failed to refresh download: " + e.getLocalizedMessage());
|
MessageBox.Show("Failed to refresh download: " + e.getLocalizedMessage());
|
||||||
HMCLog.err("Failed to refresh download.", e);
|
HMCLog.err("Failed to refresh download.", e);
|
||||||
|
|||||||
@@ -1247,13 +1247,13 @@ public final class GameSettingsPanel extends AnimatedPanel implements DropTarget
|
|||||||
reloadingMods = true;
|
reloadingMods = true;
|
||||||
DefaultTableModel model = SwingUtils.clearDefaultTable(lstExternalMods);
|
DefaultTableModel model = SwingUtils.clearDefaultTable(lstExternalMods);
|
||||||
Observable.<List<ModInfo>>createWithEmptySubscription(
|
Observable.<List<ModInfo>>createWithEmptySubscription(
|
||||||
t -> t.onNext(getProfile().getMinecraftProvider().getModService().recacheMods()))
|
t -> t.onNext(getProfile().getMinecraftProvider().getModService().recacheMods()))
|
||||||
.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue())
|
.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue())
|
||||||
.subscribe(t -> {
|
.subscribe(t -> {
|
||||||
for (ModInfo x : t)
|
for (ModInfo x : t)
|
||||||
model.addRow(new Object[]{x.isActive(), x, x.version});
|
model.addRow(new Object[] { x.isActive(), x, x.version });
|
||||||
reloadingMods = false;
|
reloadingMods = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import javax.swing.JLabel;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public class HeaderTab extends JLabel
|
public class HeaderTab extends JLabel
|
||||||
implements MouseListener {
|
implements MouseListener {
|
||||||
|
|
||||||
private boolean isActive;
|
private boolean isActive;
|
||||||
private final DefaultButtonModel model;
|
private final DefaultButtonModel model;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class InstallerPanel extends AnimatedPanel implements Selectable {
|
|||||||
/**
|
/**
|
||||||
* Creates new form InstallerPanel
|
* Creates new form InstallerPanel
|
||||||
*
|
*
|
||||||
* @param gsp To get the minecraft version
|
* @param gsp To get the minecraft version
|
||||||
* @param installerType load which installer
|
* @param installerType load which installer
|
||||||
*/
|
*/
|
||||||
public InstallerPanel(GameSettingsPanel gsp, InstallerType installerType) {
|
public InstallerPanel(GameSettingsPanel gsp, InstallerType installerType) {
|
||||||
@@ -124,7 +124,7 @@ public class InstallerPanel extends AnimatedPanel implements Selectable {
|
|||||||
|
|
||||||
void refreshVersions() {
|
void refreshVersions() {
|
||||||
if (TaskWindow.getInstance().addTask(new TaskRunnableArg1<>(C.i18n("install." + id.id + ".get_list"), list)
|
if (TaskWindow.getInstance().addTask(new TaskRunnableArg1<>(C.i18n("install." + id.id + ".get_list"), list)
|
||||||
.registerPreviousResult(new DefaultPreviousResult<>(new String[]{gsp.getMinecraftVersionFormatted()})))
|
.registerPreviousResult(new DefaultPreviousResult<>(new String[] { gsp.getMinecraftVersionFormatted() })))
|
||||||
.start())
|
.start())
|
||||||
loadVersions();
|
loadVersions();
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ public class InstallerPanel extends AnimatedPanel implements Selectable {
|
|||||||
if (versions != null)
|
if (versions != null)
|
||||||
for (InstallerVersionList.InstallerVersion v : versions)
|
for (InstallerVersionList.InstallerVersion v : versions)
|
||||||
if (v != null)
|
if (v != null)
|
||||||
model.addRow(new Object[]{v.selfVersion == null ? "null" : v.selfVersion, v.mcVersion == null ? "null" : v.mcVersion});
|
model.addRow(new Object[] { v.selfVersion == null ? "null" : v.selfVersion, v.mcVersion == null ? "null" : v.mcVersion });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
|||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
Observable.from(DownloadType.values()).map(t -> t.getName()).toList()
|
Observable.from(DownloadType.values()).map(t -> t.getName()).toList()
|
||||||
.subscribe(t -> cboDownloadSource.setModel(new DefaultComboBoxModel(t.toArray(new String[0]))));
|
.subscribe(t -> cboDownloadSource.setModel(new DefaultComboBoxModel(t.toArray(new String[0]))));
|
||||||
|
|
||||||
txtBackgroundPath.setText(Settings.getInstance().getBgpath());
|
txtBackgroundPath.setText(Settings.getInstance().getBgpath());
|
||||||
txtProxyHost.setText(Settings.getInstance().getProxyHost());
|
txtProxyHost.setText(Settings.getInstance().getProxyHost());
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ public final class MainFrame extends DraggableFrame {
|
|||||||
int contentWidth = width - off - off;
|
int contentWidth = width - off - off;
|
||||||
int contentHeight = height - off - off;
|
int contentHeight = height - off - off;
|
||||||
BufferedImage contentImage = new BufferedImage(contentWidth,
|
BufferedImage contentImage = new BufferedImage(contentWidth,
|
||||||
contentHeight, Transparency.OPAQUE);
|
contentHeight, Transparency.OPAQUE);
|
||||||
Graphics2D contentG2d = contentImage.createGraphics();
|
Graphics2D contentG2d = contentImage.createGraphics();
|
||||||
contentG2d.translate(-off, -off);
|
contentG2d.translate(-off, -off);
|
||||||
paintImpl(g);
|
paintImpl(g);
|
||||||
|
|||||||
@@ -39,10 +39,9 @@ public class ServerListCellRenderer extends javax.swing.JPanel implements ListCe
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to
|
* This method is called from within the constructor to initialize the form.
|
||||||
* initialize the form.
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
* WARNING: Do NOT modify this code. The content of this method is
|
* regenerated by the Form Editor.
|
||||||
* always regenerated by the Form Editor.
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
|||||||
@@ -57,10 +57,9 @@ public class ServerListView extends javax.swing.JDialog {
|
|||||||
public static final int FAILED_TO_SELECT = -1;
|
public static final int FAILED_TO_SELECT = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to
|
* This method is called from within the constructor to initialize the form.
|
||||||
* initialize the form.
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
* WARNING: Do NOT modify this code. The content of this method is
|
* regenerated by the Form Editor.
|
||||||
* always regenerated by the Form Editor.
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class ConsoleAppender extends OutputStreamAppender {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len)
|
public void write(byte[] b, int off, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
System.out.write(b, off, len);
|
System.out.write(b, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ public class ConsoleAppender extends OutputStreamAppender {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len)
|
public void write(byte[] b, int off, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
System.err.write(b, off, len);
|
System.err.write(b, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ package org.jackhuang.hellominecraft.logging.message;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractMessageFactory
|
public abstract class AbstractMessageFactory
|
||||||
implements IMessageFactory {
|
implements IMessageFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IMessage newMessage(Object message) {
|
public IMessage newMessage(Object message) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package org.jackhuang.hellominecraft.logging.message;
|
package org.jackhuang.hellominecraft.logging.message;
|
||||||
|
|
||||||
public class ObjectMessage
|
public class ObjectMessage
|
||||||
implements IMessage {
|
implements IMessage {
|
||||||
|
|
||||||
private static final long serialVersionUID = -5903272448334166185L;
|
private static final long serialVersionUID = -5903272448334166185L;
|
||||||
private final transient Object obj;
|
private final transient Object obj;
|
||||||
@@ -41,7 +41,7 @@ implements IMessage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getParameters() {
|
public Object[] getParameters() {
|
||||||
return new Object[] {this.obj};
|
return new Object[] { this.obj };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ public class ParameterizedMessage
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ParameterizedMessage(String messagePattern, Object arg) {
|
public ParameterizedMessage(String messagePattern, Object arg) {
|
||||||
this(messagePattern, new Object[] {arg});
|
this(messagePattern, new Object[] { arg });
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParameterizedMessage(String messagePattern, Object arg1, Object arg2) {
|
public ParameterizedMessage(String messagePattern, Object arg1, Object arg2) {
|
||||||
this(messagePattern, new Object[] {arg1, arg2});
|
this(messagePattern, new Object[] { arg1, arg2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] parseArguments(Object[] arguments) {
|
private String[] parseArguments(Object[] arguments) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ package org.jackhuang.hellominecraft.logging.message;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public class SimpleMessage
|
public class SimpleMessage
|
||||||
implements IMessage {
|
implements IMessage {
|
||||||
|
|
||||||
private static final long serialVersionUID = -8398002534962715992L;
|
private static final long serialVersionUID = -8398002534962715992L;
|
||||||
private final String message;
|
private final String message;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import java.util.Arrays;
|
|||||||
import java.util.IllegalFormatException;
|
import java.util.IllegalFormatException;
|
||||||
|
|
||||||
public class StringFormattedMessage
|
public class StringFormattedMessage
|
||||||
implements IMessage {
|
implements IMessage {
|
||||||
|
|
||||||
private static final long serialVersionUID = -665975803997290697L;
|
private static final long serialVersionUID = -665975803997290697L;
|
||||||
private final String messagePattern;
|
private final String messagePattern;
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ public class DoubleTask extends Task {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeTask() throws Throwable {
|
public void executeTask() throws Throwable {
|
||||||
a.executeTask(); b.executeTask();
|
a.executeTask();
|
||||||
|
b.executeTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public abstract class Task {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
executeTask();
|
executeTask();
|
||||||
} catch(Throwable t) {
|
} catch (Throwable t) {
|
||||||
HMCLog.err("Failed to execute task", t);
|
HMCLog.err("Failed to execute task", t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ public class TaskObservable<T> extends TaskInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeTask() {
|
public void executeTask() {
|
||||||
r.subscribe(t->{});
|
r.subscribe(t -> {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,15 +113,13 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
|||||||
connection.connect();
|
connection.connect();
|
||||||
|
|
||||||
// Make sure response code is in the 200 range.
|
// Make sure response code is in the 200 range.
|
||||||
if (connection.getResponseCode() / 100 != 2) {
|
if (connection.getResponseCode() / 100 != 2)
|
||||||
throw new NetException(C.i18n("download.not_200") + " " + connection.getResponseCode());
|
throw new NetException(C.i18n("download.not_200") + " " + connection.getResponseCode());
|
||||||
}
|
|
||||||
|
|
||||||
// Check for valid content length.
|
// Check for valid content length.
|
||||||
int contentLength = connection.getContentLength();
|
int contentLength = connection.getContentLength();
|
||||||
if (contentLength < 1) {
|
if (contentLength < 1)
|
||||||
throw new NetException("The content length is invalid.");
|
throw new NetException("The content length is invalid.");
|
||||||
}
|
|
||||||
|
|
||||||
filePath.getParentFile().mkdirs();
|
filePath.getParentFile().mkdirs();
|
||||||
|
|
||||||
@@ -179,7 +177,8 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
|||||||
closeFiles();
|
closeFiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failReason != null) throw failReason;
|
if (failReason != null)
|
||||||
|
throw failReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void download(String url, String file, DownloadListener dl) throws Throwable {
|
public static void download(String url, String file, DownloadListener dl) throws Throwable {
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ public class HTTPGetTask extends TaskInfo implements PreviousResult<String> {
|
|||||||
t = new NetException("Failed to get " + url, ex);
|
t = new NetException("Failed to get " + url, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t != null) throw t;
|
if (t != null)
|
||||||
|
throw t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -32,22 +32,29 @@ public interface IUpdateChecker {
|
|||||||
void checkOutdate();
|
void checkOutdate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the <b>cached</b> newest version number, use "process" method to download!
|
* Get the <b>cached</b> newest version number, use "process" method to
|
||||||
|
* download!
|
||||||
|
*
|
||||||
* @return the newest version number
|
* @return the newest version number
|
||||||
|
*
|
||||||
* @see process
|
* @see process
|
||||||
*/
|
*/
|
||||||
VersionNumber getNewVersion();
|
VersionNumber getNewVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download the version number synchronously.
|
* Download the version number synchronously. When you execute this method
|
||||||
* When you execute this method first, should leave "showMessage" false.
|
* first, should leave "showMessage" false.
|
||||||
* @param showMessage If it is requested to warn the user that there is a new version.
|
*
|
||||||
|
* @param showMessage If it is requested to warn the user that there is a
|
||||||
|
* new version.
|
||||||
|
*
|
||||||
* @return the process observable.
|
* @return the process observable.
|
||||||
*/
|
*/
|
||||||
Observable process(boolean showMessage);
|
Observable process(boolean showMessage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the download links.
|
* Get the download links.
|
||||||
|
*
|
||||||
* @return a JSON, which contains the server response.
|
* @return a JSON, which contains the server response.
|
||||||
*/
|
*/
|
||||||
Observable<Map<String, String>> requestDownloadLink();
|
Observable<Map<String, String>> requestDownloadLink();
|
||||||
|
|||||||
@@ -52,8 +52,9 @@ public final class NetUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getStreamContent(InputStream is, String encoding)
|
public static String getStreamContent(InputStream is, String encoding)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (is == null) return null;
|
if (is == null)
|
||||||
|
return null;
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
try (InputStreamReader br = new InputStreamReader(is, encoding)) {
|
try (InputStreamReader br = new InputStreamReader(is, encoding)) {
|
||||||
int len;
|
int len;
|
||||||
@@ -162,7 +163,7 @@ public final class NetUtils {
|
|||||||
return Observable.createWithEmptySubscription(t1 -> {
|
return Observable.createWithEmptySubscription(t1 -> {
|
||||||
try {
|
try {
|
||||||
t1.onNext(get(url));
|
t1.onNext(get(url));
|
||||||
} catch(Exception e) {
|
} catch (Exception e) {
|
||||||
t1.onError(e);
|
t1.onError(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,10 +54,14 @@ public final class StrUtils {
|
|||||||
cmdbuf.append("\\");
|
cmdbuf.append("\\");
|
||||||
cmdbuf.append('"');
|
cmdbuf.append('"');
|
||||||
} else if (s.endsWith("\""))
|
} else if (s.endsWith("\""))
|
||||||
/* The argument has already been quoted. */
|
/*
|
||||||
|
* The argument has already been quoted.
|
||||||
|
*/
|
||||||
cmdbuf.append(s);
|
cmdbuf.append(s);
|
||||||
else
|
else
|
||||||
/* Unmatched quote for the argument. */
|
/*
|
||||||
|
* Unmatched quote for the argument.
|
||||||
|
*/
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
else
|
else
|
||||||
cmdbuf.append(s);
|
cmdbuf.append(s);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class Base64 {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
private static final char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
private static final char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||||
.toCharArray();
|
.toCharArray();
|
||||||
private static final byte[] codes = new byte[256];
|
private static final byte[] codes = new byte[256];
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class DigestUtils {
|
|||||||
private static final int STREAM_BUFFER_LENGTH = 1024;
|
private static final int STREAM_BUFFER_LENGTH = 1024;
|
||||||
|
|
||||||
private static byte[] digest(MessageDigest digest, InputStream data)
|
private static byte[] digest(MessageDigest digest, InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return updateDigest(digest, data).digest();
|
return updateDigest(digest, data).digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] md2(InputStream data)
|
public static byte[] md2(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return digest(getMd2Digest(), data);
|
return digest(getMd2Digest(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String md2Hex(InputStream data)
|
public static String md2Hex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Hex.encodeHexString(md2(data));
|
return Hex.encodeHexString(md2(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] md5(InputStream data)
|
public static byte[] md5(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return digest(getMd5Digest(), data);
|
return digest(getMd5Digest(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String md5Hex(InputStream data)
|
public static String md5Hex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Hex.encodeHexString(md5(data));
|
return Hex.encodeHexString(md5(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ public class DigestUtils {
|
|||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static byte[] sha(InputStream data)
|
public static byte[] sha(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return sha1(data);
|
return sha1(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] sha1(InputStream data)
|
public static byte[] sha1(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return digest(getSha1Digest(), data);
|
return digest(getSha1Digest(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String sha1Hex(InputStream data)
|
public static String sha1Hex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Hex.encodeHexString(sha1(data));
|
return Hex.encodeHexString(sha1(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] sha256(InputStream data)
|
public static byte[] sha256(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return digest(getSha256Digest(), data);
|
return digest(getSha256Digest(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String sha256Hex(InputStream data)
|
public static String sha256Hex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Hex.encodeHexString(sha256(data));
|
return Hex.encodeHexString(sha256(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] sha384(InputStream data)
|
public static byte[] sha384(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return digest(getSha384Digest(), data);
|
return digest(getSha384Digest(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String sha384Hex(InputStream data)
|
public static String sha384Hex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Hex.encodeHexString(sha384(data));
|
return Hex.encodeHexString(sha384(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] sha512(InputStream data)
|
public static byte[] sha512(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return digest(getSha512Digest(), data);
|
return digest(getSha512Digest(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String sha512Hex(InputStream data)
|
public static String sha512Hex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Hex.encodeHexString(sha512(data));
|
return Hex.encodeHexString(sha512(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ public class DigestUtils {
|
|||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static String shaHex(InputStream data)
|
public static String shaHex(InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return sha1Hex(data);
|
return sha1Hex(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ public class DigestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static MessageDigest updateDigest(MessageDigest digest, InputStream data)
|
public static MessageDigest updateDigest(MessageDigest digest, InputStream data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
|
byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
|
||||||
int read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
|
int read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class Hex {
|
|||||||
|
|
||||||
public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
|
public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
|
||||||
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
|
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
|
||||||
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||||
|
|
||||||
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||||
private final Charset charset;
|
private final Charset charset;
|
||||||
|
|
||||||
public static byte[] decodeHex(char[] data) throws Exception {
|
public static byte[] decodeHex(char[] data) throws Exception {
|
||||||
@@ -109,7 +109,7 @@ public class Hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object encode(Object object)
|
public Object encode(Object object)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
try {
|
try {
|
||||||
byte[] byteArray = (object instanceof String) ? ((String) object).getBytes(getCharset()) : (byte[]) (byte[]) object;
|
byte[] byteArray = (object instanceof String) ? ((String) object).getBytes(getCharset()) : (byte[]) (byte[]) object;
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import org.jackhuang.hellominecraft.utils.NetUtils;
|
|||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
||||||
public static void deleteDirectory(File directory)
|
public static void deleteDirectory(File directory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (!directory.exists())
|
if (!directory.exists())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void cleanDirectory(File directory)
|
public static void cleanDirectory(File directory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (!directory.exists()) {
|
if (!directory.exists()) {
|
||||||
//String message = directory + " does not exist";
|
//String message = directory + " does not exist";
|
||||||
//throw new IllegalArgumentException(message);
|
//throw new IllegalArgumentException(message);
|
||||||
@@ -102,7 +102,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void forceDelete(File file)
|
public static void forceDelete(File file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (file.isDirectory())
|
if (file.isDirectory())
|
||||||
deleteDirectory(file);
|
deleteDirectory(file);
|
||||||
else {
|
else {
|
||||||
@@ -118,7 +118,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSymlink(File file)
|
public static boolean isSymlink(File file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (file == null)
|
if (file == null)
|
||||||
throw new NullPointerException("File must not be null");
|
throw new NullPointerException("File must not be null");
|
||||||
if (File.separatorChar == '\\')
|
if (File.separatorChar == '\\')
|
||||||
@@ -135,22 +135,22 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void copyDirectory(File srcDir, File destDir)
|
public static void copyDirectory(File srcDir, File destDir)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
copyDirectory(srcDir, destDir, true);
|
copyDirectory(srcDir, destDir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyDirectory(File srcDir, File destDir, boolean preserveFileDate)
|
public static void copyDirectory(File srcDir, File destDir, boolean preserveFileDate)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
copyDirectory(srcDir, destDir, null, preserveFileDate);
|
copyDirectory(srcDir, destDir, null, preserveFileDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyDirectory(File srcDir, File destDir, FileFilter filter)
|
public static void copyDirectory(File srcDir, File destDir, FileFilter filter)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
copyDirectory(srcDir, destDir, filter, true);
|
copyDirectory(srcDir, destDir, filter, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate)
|
public static void copyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (srcDir == null)
|
if (srcDir == null)
|
||||||
throw new NullPointerException("Source must not be null");
|
throw new NullPointerException("Source must not be null");
|
||||||
if (destDir == null)
|
if (destDir == null)
|
||||||
@@ -177,7 +177,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate, List<String> exclusionList)
|
private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate, List<String> exclusionList)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
|
File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
|
||||||
if (srcFiles == null)
|
if (srcFiles == null)
|
||||||
throw new IOException("Failed to list contents of " + srcDir);
|
throw new IOException("Failed to list contents of " + srcDir);
|
||||||
@@ -204,7 +204,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String readFileToString(File file)
|
public static String readFileToString(File file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return NetUtils.getStreamContent(IOUtils.openInputStream(file));
|
return NetUtils.getStreamContent(IOUtils.openInputStream(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String readFileToString(File file, String charset)
|
public static String readFileToString(File file, String charset)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return NetUtils.getStreamContent(IOUtils.openInputStream(file), charset);
|
return NetUtils.getStreamContent(IOUtils.openInputStream(file), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,12 +239,12 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void copyFile(File srcFile, File destFile)
|
public static void copyFile(File srcFile, File destFile)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
copyFile(srcFile, destFile, true);
|
copyFile(srcFile, destFile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyFile(File srcFile, File destFile, boolean preserveFileDate)
|
public static void copyFile(File srcFile, File destFile, boolean preserveFileDate)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (srcFile == null)
|
if (srcFile == null)
|
||||||
throw new NullPointerException("Source must not be null");
|
throw new NullPointerException("Source must not be null");
|
||||||
if (destFile == null)
|
if (destFile == null)
|
||||||
@@ -266,7 +266,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate)
|
private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if ((destFile.exists()) && (destFile.isDirectory()))
|
if ((destFile.exists()) && (destFile.isDirectory()))
|
||||||
throw new IOException("Destination '" + destFile + "' exists but is a directory");
|
throw new IOException("Destination '" + destFile + "' exists but is a directory");
|
||||||
|
|
||||||
@@ -356,38 +356,38 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void write(File file, CharSequence data)
|
public static void write(File file, CharSequence data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
write(file, data, "UTF-8", false);
|
write(file, data, "UTF-8", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(File file, CharSequence data, boolean append)
|
public static void write(File file, CharSequence data, boolean append)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
write(file, data, "UTF-8", append);
|
write(file, data, "UTF-8", append);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(File file, CharSequence data, String encoding)
|
public static void write(File file, CharSequence data, String encoding)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
write(file, data, encoding, false);
|
write(file, data, encoding, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(File file, CharSequence data, String encoding, boolean append)
|
public static void write(File file, CharSequence data, String encoding, boolean append)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String str = data == null ? null : data.toString();
|
String str = data == null ? null : data.toString();
|
||||||
writeStringToFile(file, str, encoding, append);
|
writeStringToFile(file, str, encoding, append);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeStringToFile(File file, String data)
|
public static void writeStringToFile(File file, String data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
writeStringToFile(file, data, "UTF-8", false);
|
writeStringToFile(file, data, "UTF-8", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeStringToFile(File file, String data, String encoding)
|
public static void writeStringToFile(File file, String data, String encoding)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
writeStringToFile(file, data, encoding, false);
|
writeStringToFile(file, data, encoding, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeStringToFile(File file, String data, String encoding, boolean append)
|
public static void writeStringToFile(File file, String data, String encoding, boolean append)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
out = openOutputStream(file, append);
|
out = openOutputStream(file, append);
|
||||||
@@ -399,7 +399,7 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static FileInputStream openInputStream(File file)
|
public static FileInputStream openInputStream(File file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
if (file.isDirectory())
|
if (file.isDirectory())
|
||||||
throw new IOException("File '" + file + "' exists but is a directory");
|
throw new IOException("File '" + file + "' exists but is a directory");
|
||||||
@@ -411,12 +411,12 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static FileOutputStream openOutputStream(File file)
|
public static FileOutputStream openOutputStream(File file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return openOutputStream(file, false);
|
return openOutputStream(file, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileOutputStream openOutputStream(File file, boolean append)
|
public static FileOutputStream openOutputStream(File file, boolean append)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
if (file.isDirectory())
|
if (file.isDirectory())
|
||||||
throw new IOException("File '" + file + "' exists but is a directory");
|
throw new IOException("File '" + file + "' exists but is a directory");
|
||||||
|
|||||||
@@ -72,9 +72,9 @@ public class Java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-----------------------------------
|
* -----------------------------------
|
||||||
MAC OS X
|
* MAC OS X
|
||||||
-----------------------------------
|
* -----------------------------------
|
||||||
*/
|
*/
|
||||||
public static List<Java> queryAllJDKInMac() {
|
public static List<Java> queryAllJDKInMac() {
|
||||||
List<Java> ans = new ArrayList<>();
|
List<Java> ans = new ArrayList<>();
|
||||||
@@ -88,9 +88,9 @@ public class Java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-----------------------------------
|
* -----------------------------------
|
||||||
WINDOWS
|
* WINDOWS
|
||||||
-----------------------------------
|
* -----------------------------------
|
||||||
*/
|
*/
|
||||||
public static List<Java> queryAllJavaHomeInWindowsByReg() {
|
public static List<Java> queryAllJavaHomeInWindowsByReg() {
|
||||||
List<Java> ans = new ArrayList<>();
|
List<Java> ans = new ArrayList<>();
|
||||||
@@ -126,7 +126,7 @@ public class Java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> queryRegSubFolders(String location) throws IOException, InterruptedException {
|
private static List<String> queryRegSubFolders(String location) throws IOException, InterruptedException {
|
||||||
String[] cmd = new String[] {"cmd", "/c", "reg", "query", location};
|
String[] cmd = new String[] { "cmd", "/c", "reg", "query", location };
|
||||||
List<String> l = IOUtils.readProcessByInputStream(cmd);
|
List<String> l = IOUtils.readProcessByInputStream(cmd);
|
||||||
List<String> ans = new ArrayList<>();
|
List<String> ans = new ArrayList<>();
|
||||||
for (String line : l)
|
for (String line : l)
|
||||||
@@ -136,7 +136,7 @@ public class Java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String queryRegValue(String location, String name) throws IOException, InterruptedException {
|
private static String queryRegValue(String location, String name) throws IOException, InterruptedException {
|
||||||
String[] cmd = new String[] {"cmd", "/c", "reg", "query", location, "/v", name};
|
String[] cmd = new String[] { "cmd", "/c", "reg", "query", location, "/v", name };
|
||||||
List<String> l = IOUtils.readProcessByInputStream(cmd);
|
List<String> l = IOUtils.readProcessByInputStream(cmd);
|
||||||
boolean last = false;
|
boolean last = false;
|
||||||
for (String s : l) {
|
for (String s : l) {
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public final class JdkVersion {
|
|||||||
private static final Pattern p = Pattern.compile("java version \"[1-9]*\\.[1-9]*\\.[0-9]*(.*?)\"");
|
private static final Pattern p = Pattern.compile("java version \"[1-9]*\\.[1-9]*\\.[0-9]*(.*?)\"");
|
||||||
|
|
||||||
public static JdkVersion getJavaVersionFromExecutable(String file) throws IOException {
|
public static JdkVersion getJavaVersionFromExecutable(String file) throws IOException {
|
||||||
String[] str = new String[] {file, "-version"};
|
String[] str = new String[] { file, "-version" };
|
||||||
Platform platform = Platform.BIT_32;
|
Platform platform = Platform.BIT_32;
|
||||||
String ver = null;
|
String ver = null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -32,37 +32,37 @@ import org.jackhuang.hellominecraft.utils.NetUtils;
|
|||||||
public class MinecraftVersionRequest {
|
public class MinecraftVersionRequest {
|
||||||
|
|
||||||
public static final int UNKOWN = 0, INVALID = 1, INVALID_JAR = 2,
|
public static final int UNKOWN = 0, INVALID = 1, INVALID_JAR = 2,
|
||||||
MODIFIED = 3, OK = 4, NOT_FOUND = 5, UNREADABLE = 6, NOT_FILE = 7;
|
MODIFIED = 3, OK = 4, NOT_FOUND = 5, UNREADABLE = 6, NOT_FILE = 7;
|
||||||
public int type;
|
public int type;
|
||||||
public String version;
|
public String version;
|
||||||
|
|
||||||
public static String getResponse(MinecraftVersionRequest minecraftVersion) {
|
public static String getResponse(MinecraftVersionRequest minecraftVersion) {
|
||||||
String text = "";
|
String text = "";
|
||||||
switch (minecraftVersion.type) {
|
switch (minecraftVersion.type) {
|
||||||
case MinecraftVersionRequest.INVALID:
|
case MinecraftVersionRequest.INVALID:
|
||||||
text = C.i18n("minecraft.invalid");
|
text = C.i18n("minecraft.invalid");
|
||||||
break;
|
break;
|
||||||
case MinecraftVersionRequest.INVALID_JAR:
|
case MinecraftVersionRequest.INVALID_JAR:
|
||||||
text = C.i18n("minecraft.invalid_jar");
|
text = C.i18n("minecraft.invalid_jar");
|
||||||
break;
|
break;
|
||||||
case MinecraftVersionRequest.NOT_FILE:
|
case MinecraftVersionRequest.NOT_FILE:
|
||||||
text = C.i18n("minecraft.not_a_file");
|
text = C.i18n("minecraft.not_a_file");
|
||||||
break;
|
break;
|
||||||
case MinecraftVersionRequest.NOT_FOUND:
|
case MinecraftVersionRequest.NOT_FOUND:
|
||||||
text = C.i18n("minecraft.not_found");
|
text = C.i18n("minecraft.not_found");
|
||||||
break;
|
break;
|
||||||
case MinecraftVersionRequest.UNREADABLE:
|
case MinecraftVersionRequest.UNREADABLE:
|
||||||
text = C.i18n("minecraft.not_readable");
|
text = C.i18n("minecraft.not_readable");
|
||||||
break;
|
break;
|
||||||
case MinecraftVersionRequest.MODIFIED:
|
case MinecraftVersionRequest.MODIFIED:
|
||||||
text = C.i18n("minecraft.modified") + " ";
|
text = C.i18n("minecraft.modified") + " ";
|
||||||
case MinecraftVersionRequest.OK:
|
case MinecraftVersionRequest.OK:
|
||||||
text += minecraftVersion.version;
|
text += minecraftVersion.version;
|
||||||
break;
|
break;
|
||||||
case MinecraftVersionRequest.UNKOWN:
|
case MinecraftVersionRequest.UNKOWN:
|
||||||
default:
|
default:
|
||||||
text = "???";
|
text = "???";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ public class MinecraftVersionRequest {
|
|||||||
try {
|
try {
|
||||||
localZipFile = new ZipFile(file);
|
localZipFile = new ZipFile(file);
|
||||||
ZipEntry minecraft = localZipFile
|
ZipEntry minecraft = localZipFile
|
||||||
.getEntry("net/minecraft/client/Minecraft.class");
|
.getEntry("net/minecraft/client/Minecraft.class");
|
||||||
if (minecraft != null)
|
if (minecraft != null)
|
||||||
return getVersionOfOldMinecraft(localZipFile, minecraft);
|
return getVersionOfOldMinecraft(localZipFile, minecraft);
|
||||||
ZipEntry main = localZipFile.getEntry("net/minecraft/client/main/Main.class");
|
ZipEntry main = localZipFile.getEntry("net/minecraft/client/main/Main.class");
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import java.awt.image.Raster;
|
|||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
|
|
||||||
public abstract class AbstractFilter
|
public abstract class AbstractFilter
|
||||||
implements BufferedImageOp {
|
implements BufferedImageOp {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract BufferedImage filter(BufferedImage paramBufferedImage1, BufferedImage paramBufferedImage2);
|
public abstract BufferedImage filter(BufferedImage paramBufferedImage1, BufferedImage paramBufferedImage2);
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ public class BasicColors {
|
|||||||
|
|
||||||
private static Color getWebColor(String c) {
|
private static Color getWebColor(String c) {
|
||||||
return new Color(
|
return new Color(
|
||||||
Integer.parseInt(c.substring(0, 2), 16),
|
Integer.parseInt(c.substring(0, 2), 16),
|
||||||
Integer.parseInt(c.substring(2, 4), 16),
|
Integer.parseInt(c.substring(2, 4), 16),
|
||||||
Integer.parseInt(c.substring(4, 6), 16)
|
Integer.parseInt(c.substring(4, 6), 16)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,31 +33,32 @@ public class LogWindowOutputStream extends OutputStream {
|
|||||||
|
|
||||||
private final LogWindow txt;
|
private final LogWindow txt;
|
||||||
private final Level sas;
|
private final Level sas;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private final CacheTask t = new CacheTask();
|
* private final CacheTask t = new CacheTask();
|
||||||
private class CacheTask extends TimerTask {
|
* private class CacheTask extends TimerTask {
|
||||||
private final Object lock = new Object();
|
* private final Object lock = new Object();
|
||||||
private StringBuilder cachedString = new StringBuilder();
|
* private StringBuilder cachedString = new StringBuilder();
|
||||||
|
*
|
||||||
@Override
|
* @Override
|
||||||
public void run() {
|
* public void run() {
|
||||||
synchronized(lock) {
|
* synchronized(lock) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
* SwingUtilities.invokeLater(() -> {
|
||||||
String t = txt.getText() + cachedString.toString().replace("\t", " ");
|
* String t = txt.getText() + cachedString.toString().replace("\t", " ");
|
||||||
txt.setText(t);
|
* txt.setText(t);
|
||||||
txt.setCaretPosition(t.length());
|
* txt.setCaretPosition(t.length());
|
||||||
cachedString = new StringBuilder();
|
* cachedString = new StringBuilder();
|
||||||
});
|
* });
|
||||||
}
|
* }
|
||||||
}
|
* }
|
||||||
|
*
|
||||||
void cache(String s) {
|
* void cache(String s) {
|
||||||
synchronized(lock) {
|
* synchronized(lock) {
|
||||||
cachedString.append(s);
|
* cachedString.append(s);
|
||||||
}
|
* }
|
||||||
}
|
* }
|
||||||
}*/
|
* }
|
||||||
|
*/
|
||||||
public LogWindowOutputStream(LogWindow logWindow, Level l) {
|
public LogWindowOutputStream(LogWindow logWindow, Level l) {
|
||||||
txt = logWindow;
|
txt = logWindow;
|
||||||
this.sas = l;
|
this.sas = l;
|
||||||
@@ -85,7 +86,7 @@ public class LogWindowOutputStream extends OutputStream {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void write(int paramInt) {
|
public final void write(int paramInt) {
|
||||||
append(new String(new byte[] {(byte) paramInt}));
|
append(new String(new byte[] { (byte) paramInt }));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dispose() {
|
public static void dispose() {
|
||||||
|
|||||||
@@ -50,15 +50,15 @@ public class SwingUtils {
|
|||||||
* Make DefaultTableModel by overriding getColumnClass and isCellEditable of
|
* Make DefaultTableModel by overriding getColumnClass and isCellEditable of
|
||||||
* DefaultTableModel.
|
* DefaultTableModel.
|
||||||
*
|
*
|
||||||
* @param titleA The title of each column.
|
* @param titleA The title of each column.
|
||||||
* @param typesA The type of each column value.
|
* @param typesA The type of each column value.
|
||||||
* @param canEditA Is column editable?
|
* @param canEditA Is column editable?
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static DefaultTableModel makeDefaultTableModel(String[] titleA, final Class[] typesA, final boolean[] canEditA) {
|
public static DefaultTableModel makeDefaultTableModel(String[] titleA, final Class[] typesA, final boolean[] canEditA) {
|
||||||
return new DefaultTableModel(
|
return new DefaultTableModel(
|
||||||
new Object[][]{},
|
new Object[][] {},
|
||||||
titleA) {
|
titleA) {
|
||||||
Class[] types = typesA;
|
Class[] types = typesA;
|
||||||
boolean[] canEdit = canEditA;
|
boolean[] canEdit = canEditA;
|
||||||
@@ -81,7 +81,7 @@ public class SwingUtils {
|
|||||||
switch (OS.os()) {
|
switch (OS.os()) {
|
||||||
case OSX:
|
case OSX:
|
||||||
try {
|
try {
|
||||||
Runtime.getRuntime().exec(new String[]{"/usr/bin/open", path});
|
Runtime.getRuntime().exec(new String[] { "/usr/bin/open", path });
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
HMCLog.err("Failed to open " + path + " through /usr/bin/open", ex);
|
HMCLog.err("Failed to open " + path + " through /usr/bin/open", ex);
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ public class SwingUtils {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (OS.os() == OS.OSX)
|
if (OS.os() == OS.OSX)
|
||||||
try {
|
try {
|
||||||
Runtime.getRuntime().exec(new String[]{"/usr/bin/open", link});
|
Runtime.getRuntime().exec(new String[] { "/usr/bin/open", link });
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
HMCLog.warn("Failed to open link: " + link, ex);
|
HMCLog.warn("Failed to open link: " + link, ex);
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ public class SwingUtils {
|
|||||||
/**
|
/**
|
||||||
* Append new element to JList
|
* Append new element to JList
|
||||||
*
|
*
|
||||||
* @param list the JList
|
* @param list the JList
|
||||||
* @param element the Element
|
* @param element the Element
|
||||||
*/
|
*/
|
||||||
public static void appendLast(JList list, Object element) {
|
public static void appendLast(JList list, Object element) {
|
||||||
|
|||||||
@@ -21,14 +21,17 @@ abstract class BCJCoder implements FilterCoder {
|
|||||||
return filterID >= 0x04 && filterID <= 0x09;
|
return filterID >= 0x04 && filterID <= 0x09;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean changesSize() {
|
public boolean changesSize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean nonLastOK() {
|
public boolean nonLastOK() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean lastOK() {
|
public boolean lastOK() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,27 +17,32 @@ class BCJDecoder extends BCJCoder implements FilterDecoder {
|
|||||||
private final int startOffset;
|
private final int startOffset;
|
||||||
|
|
||||||
BCJDecoder(long filterID, byte[] props)
|
BCJDecoder(long filterID, byte[] props)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
assert isBCJFilterID(filterID);
|
assert isBCJFilterID(filterID);
|
||||||
this.filterID = filterID;
|
this.filterID = filterID;
|
||||||
|
|
||||||
if (props.length == 0)
|
switch (props.length) {
|
||||||
|
case 0:
|
||||||
startOffset = 0;
|
startOffset = 0;
|
||||||
else if (props.length == 4) {
|
break;
|
||||||
|
case 4:
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
n |= (props[i] & 0xFF) << (i * 8);
|
n |= (props[i] & 0xFF) << (i * 8);
|
||||||
|
|
||||||
startOffset = n;
|
startOffset = n;
|
||||||
} else
|
break;
|
||||||
|
default:
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported BCJ filter properties");
|
"Unsupported BCJ filter properties");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMemoryUsage() {
|
public int getMemoryUsage() {
|
||||||
return SimpleInputStream.getMemoryUsage();
|
return SimpleInputStream.getMemoryUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public InputStream getInputStream(InputStream in) {
|
public InputStream getInputStream(InputStream in) {
|
||||||
SimpleFilter simpleFilter = null;
|
SimpleFilter simpleFilter = null;
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,15 @@ abstract class BCJOptions extends FilterOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the start offset for the address conversions.
|
* Sets the start offset for the address conversions. Normally this is
|
||||||
* Normally this is useless so you shouldn't use this function.
|
* useless so you shouldn't use this function. The default value is
|
||||||
* The default value is <code>0</code>.
|
* <code>0</code>.
|
||||||
*/
|
*/
|
||||||
public void setStartOffset(int startOffset)
|
public void setStartOffset(int startOffset)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
if ((startOffset & (alignment - 1)) != 0)
|
if ((startOffset & (alignment - 1)) != 0)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Start offset must be a multiple of " + alignment);
|
"Start offset must be a multiple of " + alignment);
|
||||||
|
|
||||||
this.startOffset = startOffset;
|
this.startOffset = startOffset;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class BlockInputStream extends InputStream {
|
|||||||
public BlockInputStream(InputStream in, Check check, int memoryLimit,
|
public BlockInputStream(InputStream in, Check check, int memoryLimit,
|
||||||
long unpaddedSizeInIndex,
|
long unpaddedSizeInIndex,
|
||||||
long uncompressedSizeInIndex)
|
long uncompressedSizeInIndex)
|
||||||
throws IOException, IndexIndicatorException {
|
throws IOException, IndexIndicatorException {
|
||||||
this.check = check;
|
this.check = check;
|
||||||
inData = new DataInputStream(in);
|
inData = new DataInputStream(in);
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ class BlockInputStream extends InputStream {
|
|||||||
// Check for reserved bits in Block Flags.
|
// Check for reserved bits in Block Flags.
|
||||||
if ((buf[1] & 0x3C) != 0)
|
if ((buf[1] & 0x3C) != 0)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported options in XZ Block Header");
|
"Unsupported options in XZ Block Header");
|
||||||
|
|
||||||
// Memory for the Filter Flags field
|
// Memory for the Filter Flags field
|
||||||
int filterCount = (buf[1] & 0x03) + 1;
|
int filterCount = (buf[1] & 0x03) + 1;
|
||||||
@@ -69,7 +69,7 @@ class BlockInputStream extends InputStream {
|
|||||||
// Use a stream to parse the fields after the Block Flags field.
|
// Use a stream to parse the fields after the Block Flags field.
|
||||||
// Exclude the CRC32 field at the end.
|
// Exclude the CRC32 field at the end.
|
||||||
ByteArrayInputStream bufStream = new ByteArrayInputStream(
|
ByteArrayInputStream bufStream = new ByteArrayInputStream(
|
||||||
buf, 2, headerSize - 6);
|
buf, 2, headerSize - 6);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Set the maximum valid compressed size. This is overriden
|
// Set the maximum valid compressed size. This is overriden
|
||||||
@@ -114,7 +114,7 @@ class BlockInputStream extends InputStream {
|
|||||||
for (int i = bufStream.available(); i > 0; --i)
|
for (int i = bufStream.available(); i > 0; --i)
|
||||||
if (bufStream.read() != 0x00)
|
if (bufStream.read() != 0x00)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported options in XZ Block Header");
|
"Unsupported options in XZ Block Header");
|
||||||
|
|
||||||
// Validate the Blcok Header against the Index when doing
|
// Validate the Blcok Header against the Index when doing
|
||||||
// random access reading.
|
// random access reading.
|
||||||
@@ -125,7 +125,7 @@ class BlockInputStream extends InputStream {
|
|||||||
int headerAndCheckSize = headerSize + check.getSize();
|
int headerAndCheckSize = headerSize + check.getSize();
|
||||||
if (headerAndCheckSize >= unpaddedSizeInIndex)
|
if (headerAndCheckSize >= unpaddedSizeInIndex)
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"XZ Index does not match a Block Header");
|
"XZ Index does not match a Block Header");
|
||||||
|
|
||||||
// The compressed size calculated from Unpadded Size must
|
// The compressed size calculated from Unpadded Size must
|
||||||
// match the value stored in the Compressed Size field in
|
// match the value stored in the Compressed Size field in
|
||||||
@@ -136,7 +136,7 @@ class BlockInputStream extends InputStream {
|
|||||||
|| (compressedSizeInHeader != -1
|
|| (compressedSizeInHeader != -1
|
||||||
&& compressedSizeInHeader != compressedSizeFromIndex))
|
&& compressedSizeInHeader != compressedSizeFromIndex))
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"XZ Index does not match a Block Header");
|
"XZ Index does not match a Block Header");
|
||||||
|
|
||||||
// The uncompressed size stored in the Index must match
|
// The uncompressed size stored in the Index must match
|
||||||
// the value stored in the Uncompressed Size field in
|
// the value stored in the Uncompressed Size field in
|
||||||
@@ -144,7 +144,7 @@ class BlockInputStream extends InputStream {
|
|||||||
if (uncompressedSizeInHeader != -1
|
if (uncompressedSizeInHeader != -1
|
||||||
&& uncompressedSizeInHeader != uncompressedSizeInIndex)
|
&& uncompressedSizeInHeader != uncompressedSizeInIndex)
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"XZ Index does not match a Block Header");
|
"XZ Index does not match a Block Header");
|
||||||
|
|
||||||
// For further validation, pretend that the values from the Index
|
// For further validation, pretend that the values from the Index
|
||||||
// were stored in the Block Header.
|
// were stored in the Block Header.
|
||||||
@@ -170,7 +170,7 @@ class BlockInputStream extends InputStream {
|
|||||||
|
|
||||||
else
|
else
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unknown Filter ID " + filterIDs[i]);
|
"Unknown Filter ID " + filterIDs[i]);
|
||||||
|
|
||||||
RawCoder.validate(filters);
|
RawCoder.validate(filters);
|
||||||
|
|
||||||
|
|||||||
@@ -9,25 +9,25 @@
|
|||||||
package org.tukaani.xz;
|
package org.tukaani.xz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when the compressed input data is corrupt.
|
* Thrown when the compressed input data is corrupt. However, it is possible
|
||||||
* However, it is possible that some or all of the data
|
* that some or all of the data already read from the input stream was corrupt
|
||||||
* already read from the input stream was corrupt too.
|
* too.
|
||||||
*/
|
*/
|
||||||
public class CorruptedInputException extends XZIOException {
|
public class CorruptedInputException extends XZIOException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 3L;
|
private static final long serialVersionUID = 3L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new CorruptedInputException with
|
* Creates a new CorruptedInputException with the default error detail
|
||||||
* the default error detail message.
|
* message.
|
||||||
*/
|
*/
|
||||||
public CorruptedInputException() {
|
public CorruptedInputException() {
|
||||||
super("Compressed data is corrupt");
|
super("Compressed data is corrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new CorruptedInputException with
|
* Creates a new CorruptedInputException with the specified error detail
|
||||||
* the specified error detail message.
|
* message.
|
||||||
*
|
*
|
||||||
* @param s error detail message
|
* @param s error detail message
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,15 +17,17 @@ class DeltaDecoder extends DeltaCoder implements FilterDecoder {
|
|||||||
DeltaDecoder(byte[] props) throws UnsupportedOptionsException {
|
DeltaDecoder(byte[] props) throws UnsupportedOptionsException {
|
||||||
if (props.length != 1)
|
if (props.length != 1)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported Delta filter properties");
|
"Unsupported Delta filter properties");
|
||||||
|
|
||||||
distance = (props[0] & 0xFF) + 1;
|
distance = (props[0] & 0xFF) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMemoryUsage() {
|
public int getMemoryUsage() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public InputStream getInputStream(InputStream in) {
|
public InputStream getInputStream(InputStream in) {
|
||||||
return new DeltaInputStream(in, distance);
|
return new DeltaInputStream(in, distance);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import org.tukaani.xz.delta.DeltaDecoder;
|
|||||||
/**
|
/**
|
||||||
* Decodes raw Delta-filtered data (no XZ headers).
|
* Decodes raw Delta-filtered data (no XZ headers).
|
||||||
* <p>
|
* <p>
|
||||||
* The delta filter doesn't change the size of the data and thus it
|
* The delta filter doesn't change the size of the data and thus it cannot have
|
||||||
* cannot have an end-of-payload marker. It will simply decode until
|
* an end-of-payload marker. It will simply decode until its input stream
|
||||||
* its input stream indicates end of input.
|
* indicates end of input.
|
||||||
*/
|
*/
|
||||||
public class DeltaInputStream extends InputStream {
|
public class DeltaInputStream extends InputStream {
|
||||||
|
|
||||||
@@ -41,12 +41,10 @@ public class DeltaInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Creates a new Delta decoder with the given delta calculation distance.
|
* Creates a new Delta decoder with the given delta calculation distance.
|
||||||
*
|
*
|
||||||
* @param in input stream from which Delta filtered data
|
* @param in input stream from which Delta filtered data is read
|
||||||
* is read
|
|
||||||
*
|
*
|
||||||
* @param distance delta calculation distance, must be in the
|
* @param distance delta calculation distance, must be in the range
|
||||||
* range [<code>DISTANCE_MIN</code>,
|
* [<code>DISTANCE_MIN</code>, <code>DISTANCE_MAX</code>]
|
||||||
* <code>DISTANCE_MAX</code>]
|
|
||||||
*/
|
*/
|
||||||
public DeltaInputStream(InputStream in, int distance) {
|
public DeltaInputStream(InputStream in, int distance) {
|
||||||
// Check for null because otherwise null isn't detect
|
// Check for null because otherwise null isn't detect
|
||||||
@@ -61,11 +59,12 @@ public class DeltaInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decode the next byte from this input stream.
|
* Decode the next byte from this input stream.
|
||||||
*
|
*
|
||||||
* @return the next decoded byte, or <code>-1</code> to indicate
|
* @return the next decoded byte, or <code>-1</code> to indicate the end of
|
||||||
* the end of input on the input stream <code>in</code>
|
* input on the input stream <code>in</code>
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
|
return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
|
||||||
}
|
}
|
||||||
@@ -73,21 +72,22 @@ public class DeltaInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decode into an array of bytes.
|
* Decode into an array of bytes.
|
||||||
* <p>
|
* <p>
|
||||||
* This calls <code>in.read(buf, off, len)</code> and defilters the
|
* This calls <code>in.read(buf, off, len)</code> and defilters the returned
|
||||||
* returned data.
|
* data.
|
||||||
*
|
*
|
||||||
* @param buf target buffer for decoded data
|
* @param buf target buffer for decoded data
|
||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len maximum number of bytes to read
|
* @param len maximum number of bytes to read
|
||||||
*
|
*
|
||||||
* @return number of bytes read, or <code>-1</code> to indicate
|
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||||
* the end of the input stream <code>in</code>
|
* the input stream <code>in</code>
|
||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by underlaying input
|
* @throws IOException may be thrown by underlaying input stream
|
||||||
* stream <code>in</code>
|
* <code>in</code>
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int read(byte[] buf, int off, int len) throws IOException {
|
public int read(byte[] buf, int off, int len) throws IOException {
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -118,6 +118,7 @@ public class DeltaInputStream extends InputStream {
|
|||||||
*
|
*
|
||||||
* @return the value returned by <code>in.available()</code>
|
* @return the value returned by <code>in.available()</code>
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
if (in == null)
|
if (in == null)
|
||||||
throw new XZIOException("Stream closed");
|
throw new XZIOException("Stream closed");
|
||||||
@@ -129,11 +130,12 @@ public class DeltaInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream and calls <code>in.close()</code>.
|
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||||
* If the stream was already closed, this does nothing.
|
* already closed, this does nothing.
|
||||||
*
|
*
|
||||||
* @throws IOException if thrown by <code>in.close()</code>
|
* @throws IOException if thrown by <code>in.close()</code>
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (in != null)
|
if (in != null)
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ package org.tukaani.xz;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delta filter options. The Delta filter can be used only as a non-last
|
* Delta filter options. The Delta filter can be used only as a non-last filter
|
||||||
* filter in the chain, for example Delta + LZMA2.
|
* in the chain, for example Delta + LZMA2.
|
||||||
* <p>
|
* <p>
|
||||||
* Currently only simple byte-wise delta is supported. The only option
|
* Currently only simple byte-wise delta is supported. The only option is the
|
||||||
* is the delta distance, which you should set to match your data.
|
* delta distance, which you should set to match your data. It's not possible to
|
||||||
* It's not possible to provide a generic default value for it.
|
* provide a generic default value for it.
|
||||||
* <p>
|
* <p>
|
||||||
* For example, with distance = 2 and eight-byte input
|
* For example, with distance = 2 and eight-byte input A1 B1 A2 B3 A3 B5 A4 B7,
|
||||||
* A1 B1 A2 B3 A3 B5 A4 B7, the output will be A1 B1 01 02 01 02 01 02.
|
* the output will be A1 B1 01 02 01 02 01 02.
|
||||||
* <p>
|
* <p>
|
||||||
* The Delta filter can be good with uncompressed bitmap images. It can
|
* The Delta filter can be good with uncompressed bitmap images. It can also
|
||||||
* also help with PCM audio, although special-purpose compressors like
|
* help with PCM audio, although special-purpose compressors like FLAC will give
|
||||||
* FLAC will give much smaller result at much better compression speed.
|
* much smaller result at much better compression speed.
|
||||||
*/
|
*/
|
||||||
public class DeltaOptions extends FilterOptions {
|
public class DeltaOptions extends FilterOptions {
|
||||||
|
|
||||||
@@ -53,14 +53,14 @@ public class DeltaOptions extends FilterOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the delta distance in bytes. The new distance must be in
|
* Sets the delta distance in bytes. The new distance must be in the range
|
||||||
* the range [DISTANCE_MIN, DISTANCE_MAX].
|
* [DISTANCE_MIN, DISTANCE_MAX].
|
||||||
*/
|
*/
|
||||||
public void setDistance(int distance) throws UnsupportedOptionsException {
|
public void setDistance(int distance) throws UnsupportedOptionsException {
|
||||||
if (distance < DISTANCE_MIN || distance > DISTANCE_MAX)
|
if (distance < DISTANCE_MIN || distance > DISTANCE_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Delta distance must be in the range [" + DISTANCE_MIN
|
"Delta distance must be in the range [" + DISTANCE_MIN
|
||||||
+ ", " + DISTANCE_MAX + "]: " + distance);
|
+ ", " + DISTANCE_MAX + "]: " + distance);
|
||||||
|
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
}
|
}
|
||||||
@@ -72,26 +72,32 @@ public class DeltaOptions extends FilterOptions {
|
|||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getEncoderMemoryUsage() {
|
public int getEncoderMemoryUsage() {
|
||||||
return DeltaOutputStream.getMemoryUsage();
|
return DeltaOutputStream.getMemoryUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
|
public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
|
||||||
return new DeltaOutputStream(out, this);
|
return new DeltaOutputStream(out, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getDecoderMemoryUsage() {
|
public int getDecoderMemoryUsage() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public InputStream getInputStream(InputStream in) {
|
public InputStream getInputStream(InputStream in) {
|
||||||
return new DeltaInputStream(in, distance);
|
return new DeltaInputStream(in, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
FilterEncoder getFilterEncoder() {
|
FilterEncoder getFilterEncoder() {
|
||||||
return new DeltaEncoder(this);
|
return new DeltaEncoder(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
try {
|
try {
|
||||||
return super.clone();
|
return super.clone();
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ import java.io.IOException;
|
|||||||
public abstract class FilterOptions implements Cloneable {
|
public abstract class FilterOptions implements Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets how much memory the encoder will need with
|
* Gets how much memory the encoder will need with the given filter chain.
|
||||||
* the given filter chain. This function simply calls
|
* This function simply calls <code>getEncoderMemoryUsage()</code> for every
|
||||||
* <code>getEncoderMemoryUsage()</code> for every filter
|
* filter in the array and returns the sum of the returned values.
|
||||||
* in the array and returns the sum of the returned values.
|
|
||||||
*/
|
*/
|
||||||
public static int getEncoderMemoryUsage(FilterOptions[] options) {
|
public static int getEncoderMemoryUsage(FilterOptions[] options) {
|
||||||
int m = 0;
|
int m = 0;
|
||||||
@@ -33,10 +32,9 @@ public abstract class FilterOptions implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets how much memory the decoder will need with
|
* Gets how much memory the decoder will need with the given filter chain.
|
||||||
* the given filter chain. This function simply calls
|
* This function simply calls <code>getDecoderMemoryUsage()</code> for every
|
||||||
* <code>getDecoderMemoryUsage()</code> for every filter
|
* filter in the array and returns the sum of the returned values.
|
||||||
* in the array and returns the sum of the returned values.
|
|
||||||
*/
|
*/
|
||||||
public static int getDecoderMemoryUsage(FilterOptions[] options) {
|
public static int getDecoderMemoryUsage(FilterOptions[] options) {
|
||||||
int m = 0;
|
int m = 0;
|
||||||
@@ -53,18 +51,18 @@ public abstract class FilterOptions implements Cloneable {
|
|||||||
public abstract int getEncoderMemoryUsage();
|
public abstract int getEncoderMemoryUsage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a raw (no XZ headers) encoder output stream using these options.
|
* Gets a raw (no XZ headers) encoder output stream using these options. Raw
|
||||||
* Raw streams are an advanced feature. In most cases you want to store
|
* streams are an advanced feature. In most cases you want to store the
|
||||||
* the compressed data in the .xz container format instead of using
|
* compressed data in the .xz container format instead of using a raw
|
||||||
* a raw stream. To use this filter in a .xz file, pass this object
|
* stream. To use this filter in a .xz file, pass this object to
|
||||||
* to XZOutputStream.
|
* XZOutputStream.
|
||||||
*/
|
*/
|
||||||
public abstract FinishableOutputStream getOutputStream(
|
public abstract FinishableOutputStream getOutputStream(
|
||||||
FinishableOutputStream out);
|
FinishableOutputStream out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets how much memory the decoder will need to decompress the data
|
* Gets how much memory the decoder will need to decompress the data that
|
||||||
* that was encoded with these options.
|
* was encoded with these options.
|
||||||
*/
|
*/
|
||||||
public abstract int getDecoderMemoryUsage();
|
public abstract int getDecoderMemoryUsage();
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ public abstract class FilterOptions implements Cloneable {
|
|||||||
* Gets a raw (no XZ headers) decoder input stream using these options.
|
* Gets a raw (no XZ headers) decoder input stream using these options.
|
||||||
*/
|
*/
|
||||||
public abstract InputStream getInputStream(InputStream in)
|
public abstract InputStream getInputStream(InputStream in)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
abstract FilterEncoder getFilterEncoder();
|
abstract FilterEncoder getFilterEncoder();
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
|||||||
/**
|
/**
|
||||||
* Calls {@link java.io.OutputStream#write(int) out.write(b)}.
|
* Calls {@link java.io.OutputStream#write(int) out.write(b)}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void write(int b) throws IOException {
|
public void write(int b) throws IOException {
|
||||||
out.write(b);
|
out.write(b);
|
||||||
}
|
}
|
||||||
@@ -42,6 +43,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
|||||||
/**
|
/**
|
||||||
* Calls {@link java.io.OutputStream#write(byte[]) out.write(buf)}.
|
* Calls {@link java.io.OutputStream#write(byte[]) out.write(buf)}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void write(byte[] buf) throws IOException {
|
public void write(byte[] buf) throws IOException {
|
||||||
out.write(buf);
|
out.write(buf);
|
||||||
}
|
}
|
||||||
@@ -50,6 +52,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
|||||||
* Calls {@link java.io.OutputStream#write(byte[],int,int)
|
* Calls {@link java.io.OutputStream#write(byte[],int,int)
|
||||||
* out.write(buf, off, len)}.
|
* out.write(buf, off, len)}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void write(byte[] buf, int off, int len) throws IOException {
|
public void write(byte[] buf, int off, int len) throws IOException {
|
||||||
out.write(buf, off, len);
|
out.write(buf, off, len);
|
||||||
}
|
}
|
||||||
@@ -57,6 +60,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
|||||||
/**
|
/**
|
||||||
* Calls {@link java.io.OutputStream#flush() out.flush()}.
|
* Calls {@link java.io.OutputStream#flush() out.flush()}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
@@ -64,6 +68,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
|||||||
/**
|
/**
|
||||||
* Calls {@link java.io.OutputStream#close() out.close()}.
|
* Calls {@link java.io.OutputStream#close() out.close()}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,18 @@ class LZMA2Decoder extends LZMA2Coder implements FilterDecoder {
|
|||||||
// are too big for int.
|
// are too big for int.
|
||||||
if (props.length != 1 || (props[0] & 0xFF) > 37)
|
if (props.length != 1 || (props[0] & 0xFF) > 37)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported LZMA2 properties");
|
"Unsupported LZMA2 properties");
|
||||||
|
|
||||||
dictSize = 2 | (props[0] & 1);
|
dictSize = 2 | (props[0] & 1);
|
||||||
dictSize <<= (props[0] >>> 1) + 11;
|
dictSize <<= (props[0] >>> 1) + 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMemoryUsage() {
|
public int getMemoryUsage() {
|
||||||
return LZMA2InputStream.getMemoryUsage(dictSize);
|
return LZMA2InputStream.getMemoryUsage(dictSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public InputStream getInputStream(InputStream in) {
|
public InputStream getInputStream(InputStream in) {
|
||||||
return new LZMA2InputStream(in, dictSize);
|
return new LZMA2InputStream(in, dictSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class LZMA2Encoder extends LZMA2Coder implements FilterEncoder {
|
|||||||
LZMA2Encoder(LZMA2Options options) {
|
LZMA2Encoder(LZMA2Options options) {
|
||||||
if (options.getPresetDict() != null)
|
if (options.getPresetDict() != null)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"XZ doesn't support a preset dictionary for now");
|
"XZ doesn't support a preset dictionary for now");
|
||||||
|
|
||||||
if (options.getMode() == LZMA2Options.MODE_UNCOMPRESSED)
|
if (options.getMode() == LZMA2Options.MODE_UNCOMPRESSED)
|
||||||
props[0] = (byte) 0;
|
props[0] = (byte) 0;
|
||||||
@@ -32,18 +32,22 @@ class LZMA2Encoder extends LZMA2Coder implements FilterEncoder {
|
|||||||
this.options = (LZMA2Options) options.clone();
|
this.options = (LZMA2Options) options.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public long getFilterID() {
|
public long getFilterID() {
|
||||||
return FILTER_ID;
|
return FILTER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte[] getFilterProps() {
|
public byte[] getFilterProps() {
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsFlushing() {
|
public boolean supportsFlushing() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
|
public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
|
||||||
return options.getOutputStream(out);
|
return options.getOutputStream(out);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Smallest valid LZMA2 dictionary size.
|
* Smallest valid LZMA2 dictionary size.
|
||||||
* <p>
|
* <p>
|
||||||
* Very tiny dictionaries would be a performance problem, so
|
* Very tiny dictionaries would be a performance problem, so the minimum is
|
||||||
* the minimum is 4 KiB.
|
* 4 KiB.
|
||||||
*/
|
*/
|
||||||
public static final int DICT_SIZE_MIN = 4096;
|
public static final int DICT_SIZE_MIN = 4096;
|
||||||
|
|
||||||
@@ -33,11 +33,11 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
* Largest dictionary size supported by this implementation.
|
* Largest dictionary size supported by this implementation.
|
||||||
* <p>
|
* <p>
|
||||||
* The LZMA2 algorithm allows dictionaries up to one byte less than 4 GiB.
|
* The LZMA2 algorithm allows dictionaries up to one byte less than 4 GiB.
|
||||||
* This implementation supports only 16 bytes less than 2 GiB for raw
|
* This implementation supports only 16 bytes less than 2 GiB for raw LZMA2
|
||||||
* LZMA2 streams, and for .xz files the maximum is 1.5 GiB. This
|
* streams, and for .xz files the maximum is 1.5 GiB. This limitation is due
|
||||||
* limitation is due to Java using signed 32-bit integers for array
|
* to Java using signed 32-bit integers for array indexing. The limitation
|
||||||
* indexing. The limitation shouldn't matter much in practice since so
|
* shouldn't matter much in practice since so huge dictionaries are not
|
||||||
* huge dictionaries are not normally used.
|
* normally used.
|
||||||
*/
|
*/
|
||||||
public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
|
public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
|
||||||
|
|
||||||
@@ -62,12 +62,11 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
private final byte[] tempBuf = new byte[1];
|
private final byte[] tempBuf = new byte[1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets approximate decompressor memory requirements as kibibytes for
|
* Gets approximate decompressor memory requirements as kibibytes for the
|
||||||
* the given dictionary size.
|
* given dictionary size.
|
||||||
*
|
*
|
||||||
* @param dictSize LZMA2 dictionary size as bytes, must be
|
* @param dictSize LZMA2 dictionary size as bytes, must be in the range
|
||||||
* in the range [<code>DICT_SIZE_MIN</code>,
|
* [<code>DICT_SIZE_MIN</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
* <code>DICT_SIZE_MAX</code>]
|
|
||||||
*
|
*
|
||||||
* @return approximate memory requirements as kibibytes (KiB)
|
* @return approximate memory requirements as kibibytes (KiB)
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +80,7 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
private static int getDictSize(int dictSize) {
|
private static int getDictSize(int dictSize) {
|
||||||
if (dictSize < DICT_SIZE_MIN || dictSize > DICT_SIZE_MAX)
|
if (dictSize < DICT_SIZE_MIN || dictSize > DICT_SIZE_MAX)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Unsupported dictionary size " + dictSize);
|
"Unsupported dictionary size " + dictSize);
|
||||||
|
|
||||||
// Round dictionary size upward to a multiple of 16. This way LZMA
|
// Round dictionary size upward to a multiple of 16. This way LZMA
|
||||||
// can use LZDecoder.getPos() for calculating LZMA's posMask.
|
// can use LZDecoder.getPos() for calculating LZMA's posMask.
|
||||||
@@ -91,27 +90,25 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new input stream that decompresses raw LZMA2 data
|
* Creates a new input stream that decompresses raw LZMA2 data from
|
||||||
* from <code>in</code>.
|
* <code>in</code>.
|
||||||
* <p>
|
* <p>
|
||||||
* The caller needs to know the dictionary size used when compressing;
|
* The caller needs to know the dictionary size used when compressing; the
|
||||||
* the dictionary size isn't stored as part of a raw LZMA2 stream.
|
* dictionary size isn't stored as part of a raw LZMA2 stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Specifying a too small dictionary size will prevent decompressing
|
* Specifying a too small dictionary size will prevent decompressing the
|
||||||
* the stream. Specifying a too big dictionary is waste of memory but
|
* stream. Specifying a too big dictionary is waste of memory but
|
||||||
* decompression will work.
|
* decompression will work.
|
||||||
* <p>
|
* <p>
|
||||||
* There is no need to specify a dictionary bigger than
|
* There is no need to specify a dictionary bigger than the uncompressed
|
||||||
* the uncompressed size of the data even if a bigger dictionary
|
* size of the data even if a bigger dictionary was used when compressing.
|
||||||
* was used when compressing. If you know the uncompressed size
|
* If you know the uncompressed size of the data, this might allow saving
|
||||||
* of the data, this might allow saving some memory.
|
* some memory.
|
||||||
*
|
*
|
||||||
* @param in input stream from which LZMA2-compressed
|
* @param in input stream from which LZMA2-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param dictSize LZMA2 dictionary size as bytes, must be
|
* @param dictSize LZMA2 dictionary size as bytes, must be in the range
|
||||||
* in the range [<code>DICT_SIZE_MIN</code>,
|
* [<code>DICT_SIZE_MIN</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
* <code>DICT_SIZE_MAX</code>]
|
|
||||||
*/
|
*/
|
||||||
public LZMA2InputStream(InputStream in, int dictSize) {
|
public LZMA2InputStream(InputStream in, int dictSize) {
|
||||||
this(in, dictSize, null);
|
this(in, dictSize, null);
|
||||||
@@ -120,20 +117,18 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Creates a new LZMA2 decompressor using a preset dictionary.
|
* Creates a new LZMA2 decompressor using a preset dictionary.
|
||||||
* <p>
|
* <p>
|
||||||
* This is like <code>LZMA2InputStream(InputStream, int)</code> except
|
* This is like <code>LZMA2InputStream(InputStream, int)</code> except that
|
||||||
* that the dictionary may be initialized using a preset dictionary.
|
* the dictionary may be initialized using a preset dictionary. If a preset
|
||||||
* If a preset dictionary was used when compressing the data, the
|
* dictionary was used when compressing the data, the same preset dictionary
|
||||||
* same preset dictionary must be provided when decompressing.
|
* must be provided when decompressing.
|
||||||
*
|
*
|
||||||
* @param in input stream from which LZMA2-compressed
|
* @param in input stream from which LZMA2-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param dictSize LZMA2 dictionary size as bytes, must be
|
* @param dictSize LZMA2 dictionary size as bytes, must be in the range
|
||||||
* in the range [<code>DICT_SIZE_MIN</code>,
|
* [<code>DICT_SIZE_MIN</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
* <code>DICT_SIZE_MAX</code>]
|
|
||||||
*
|
*
|
||||||
* @param presetDict preset dictionary or <code>null</code>
|
* @param presetDict preset dictionary or <code>null</code> to use no preset
|
||||||
* to use no preset dictionary
|
* dictionary
|
||||||
*/
|
*/
|
||||||
public LZMA2InputStream(InputStream in, int dictSize, byte[] presetDict) {
|
public LZMA2InputStream(InputStream in, int dictSize, byte[] presetDict) {
|
||||||
// Check for null because otherwise null isn't detect
|
// Check for null because otherwise null isn't detect
|
||||||
@@ -151,19 +146,18 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses the next byte from this input stream.
|
* Decompresses the next byte from this input stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Reading lots of data with <code>read()</code> from this input stream
|
* Reading lots of data with <code>read()</code> from this input stream may
|
||||||
* may be inefficient. Wrap it in <code>java.io.BufferedInputStream</code>
|
* be inefficient. Wrap it in <code>java.io.BufferedInputStream</code> if
|
||||||
* if you need to read lots of data one byte at a time.
|
* you need to read lots of data one byte at a time.
|
||||||
*
|
*
|
||||||
* @return the next decompressed byte, or <code>-1</code>
|
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||||
* to indicate the end of the compressed stream
|
* end of the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or corrupt
|
||||||
* compressed input is truncated or corrupt
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -174,24 +168,23 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses into an array of bytes.
|
* Decompresses into an array of bytes.
|
||||||
* <p>
|
* <p>
|
||||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||||
* is returned. Otherwise this will block until <code>len</code>
|
* returned. Otherwise this will block until <code>len</code> bytes have
|
||||||
* bytes have been decompressed, the end of the LZMA2 stream is reached,
|
* been decompressed, the end of the LZMA2 stream is reached, or an
|
||||||
* or an exception is thrown.
|
* exception is thrown.
|
||||||
*
|
*
|
||||||
* @param buf target buffer for uncompressed data
|
* @param buf target buffer for uncompressed data
|
||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len maximum number of uncompressed bytes to read
|
* @param len maximum number of uncompressed bytes to read
|
||||||
*
|
*
|
||||||
* @return number of bytes read, or <code>-1</code> to indicate
|
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||||
* the end of the compressed stream
|
* the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or corrupt
|
||||||
* compressed input is truncated or corrupt
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -311,20 +304,18 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of uncompressed bytes that can be read
|
* Returns the number of uncompressed bytes that can be read without
|
||||||
* without blocking. The value is returned with an assumption
|
* blocking. The value is returned with an assumption that the compressed
|
||||||
* that the compressed input data will be valid. If the compressed
|
* input data will be valid. If the compressed data is corrupt,
|
||||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||||
* thrown before the number of bytes claimed to be available have
|
* bytes claimed to be available have been read from this input stream.
|
||||||
* been read from this input stream.
|
|
||||||
* <p>
|
* <p>
|
||||||
* In LZMA2InputStream, the return value will be non-zero when the
|
* In LZMA2InputStream, the return value will be non-zero when the
|
||||||
* decompressor is in the middle of an LZMA2 chunk. The return value
|
* decompressor is in the middle of an LZMA2 chunk. The return value will
|
||||||
* will then be the number of uncompressed bytes remaining from that
|
* then be the number of uncompressed bytes remaining from that chunk.
|
||||||
* chunk.
|
|
||||||
*
|
*
|
||||||
* @return the number of uncompressed bytes that can be read
|
* @return the number of uncompressed bytes that can be read without
|
||||||
* without blocking
|
* blocking
|
||||||
*/
|
*/
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
if (in == null)
|
if (in == null)
|
||||||
@@ -337,8 +328,8 @@ public class LZMA2InputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream and calls <code>in.close()</code>.
|
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||||
* If the stream was already closed, this does nothing.
|
* already closed, this does nothing.
|
||||||
*
|
*
|
||||||
* @throws IOException if thrown by <code>in.close()</code>
|
* @throws IOException if thrown by <code>in.close()</code>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ import org.tukaani.xz.lzma.LZMAEncoder;
|
|||||||
/**
|
/**
|
||||||
* LZMA2 compression options.
|
* LZMA2 compression options.
|
||||||
* <p>
|
* <p>
|
||||||
* While this allows setting the LZMA2 compression options in detail,
|
* While this allows setting the LZMA2 compression options in detail, often you
|
||||||
* often you only need <code>LZMA2Options()</code> or
|
* only need <code>LZMA2Options()</code> or <code>LZMA2Options(int)</code>.
|
||||||
* <code>LZMA2Options(int)</code>.
|
|
||||||
*/
|
*/
|
||||||
public class LZMA2Options extends FilterOptions {
|
public class LZMA2Options extends FilterOptions {
|
||||||
|
|
||||||
@@ -45,13 +44,13 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Maximum dictionary size for compression is 768 MiB.
|
* Maximum dictionary size for compression is 768 MiB.
|
||||||
* <p>
|
* <p>
|
||||||
* The decompressor supports bigger dictionaries, up to almost 2 GiB.
|
* The decompressor supports bigger dictionaries, up to almost 2 GiB. With
|
||||||
* With HC4 the encoder would support dictionaries bigger than 768 MiB.
|
* HC4 the encoder would support dictionaries bigger than 768 MiB. The 768
|
||||||
* The 768 MiB limit comes from the current implementation of BT4 where
|
* MiB limit comes from the current implementation of BT4 where we would
|
||||||
* we would otherwise hit the limits of signed ints in array indexing.
|
* otherwise hit the limits of signed ints in array indexing.
|
||||||
* <p>
|
* <p>
|
||||||
* If you really need bigger dictionary for decompression,
|
* If you really need bigger dictionary for decompression, use
|
||||||
* use {@link LZMA2InputStream} directly.
|
* {@link LZMA2InputStream} directly.
|
||||||
*/
|
*/
|
||||||
public static final int DICT_SIZE_MAX = 768 << 20;
|
public static final int DICT_SIZE_MAX = 768 << 20;
|
||||||
|
|
||||||
@@ -86,20 +85,20 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
public static final int PB_DEFAULT = 2;
|
public static final int PB_DEFAULT = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compression mode: uncompressed.
|
* Compression mode: uncompressed. The data is wrapped into a LZMA2 stream
|
||||||
* The data is wrapped into a LZMA2 stream without compression.
|
* without compression.
|
||||||
*/
|
*/
|
||||||
public static final int MODE_UNCOMPRESSED = 0;
|
public static final int MODE_UNCOMPRESSED = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compression mode: fast.
|
* Compression mode: fast. This is usually combined with a hash chain match
|
||||||
* This is usually combined with a hash chain match finder.
|
* finder.
|
||||||
*/
|
*/
|
||||||
public static final int MODE_FAST = LZMAEncoder.MODE_FAST;
|
public static final int MODE_FAST = LZMAEncoder.MODE_FAST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compression mode: normal.
|
* Compression mode: normal. This is usually combined with a binary tree
|
||||||
* This is usually combined with a binary tree match finder.
|
* match finder.
|
||||||
*/
|
*/
|
||||||
public static final int MODE_NORMAL = LZMAEncoder.MODE_NORMAL;
|
public static final int MODE_NORMAL = LZMAEncoder.MODE_NORMAL;
|
||||||
|
|
||||||
@@ -125,9 +124,9 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
|
|
||||||
private static final int[] presetToDictSize = {
|
private static final int[] presetToDictSize = {
|
||||||
1 << 18, 1 << 20, 1 << 21, 1 << 22, 1 << 22,
|
1 << 18, 1 << 20, 1 << 21, 1 << 22, 1 << 22,
|
||||||
1 << 23, 1 << 23, 1 << 24, 1 << 25, 1 << 26};
|
1 << 23, 1 << 23, 1 << 24, 1 << 25, 1 << 26 };
|
||||||
|
|
||||||
private static final int[] presetToDepthLimit = {4, 8, 24, 48};
|
private static final int[] presetToDepthLimit = { 4, 8, 24, 48 };
|
||||||
|
|
||||||
private int dictSize;
|
private int dictSize;
|
||||||
private byte[] presetDict = null;
|
private byte[] presetDict = null;
|
||||||
@@ -140,8 +139,8 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
private int depthLimit;
|
private int depthLimit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new LZMA2 options and sets them to the default values.
|
* Creates new LZMA2 options and sets them to the default values. This is
|
||||||
* This is equivalent to <code>LZMA2Options(PRESET_DEFAULT)</code>.
|
* equivalent to <code>LZMA2Options(PRESET_DEFAULT)</code>.
|
||||||
*/
|
*/
|
||||||
public LZMA2Options() {
|
public LZMA2Options() {
|
||||||
try {
|
try {
|
||||||
@@ -155,8 +154,7 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Creates new LZMA2 options and sets them to the given preset.
|
* Creates new LZMA2 options and sets them to the given preset.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>preset</code> is not supported
|
||||||
* <code>preset</code> is not supported
|
|
||||||
*/
|
*/
|
||||||
public LZMA2Options(int preset) throws UnsupportedOptionsException {
|
public LZMA2Options(int preset) throws UnsupportedOptionsException {
|
||||||
setPreset(preset);
|
setPreset(preset);
|
||||||
@@ -165,12 +163,11 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Creates new LZMA2 options and sets them to the given custom values.
|
* Creates new LZMA2 options and sets them to the given custom values.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException unsupported options were specified
|
||||||
* unsupported options were specified
|
|
||||||
*/
|
*/
|
||||||
public LZMA2Options(int dictSize, int lc, int lp, int pb, int mode,
|
public LZMA2Options(int dictSize, int lc, int lp, int pb, int mode,
|
||||||
int niceLen, int mf, int depthLimit)
|
int niceLen, int mf, int depthLimit)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
setDictSize(dictSize);
|
setDictSize(dictSize);
|
||||||
setLcLp(lc, lp);
|
setLcLp(lc, lp);
|
||||||
setPb(pb);
|
setPb(pb);
|
||||||
@@ -183,23 +180,22 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the compression options to the given preset.
|
* Sets the compression options to the given preset.
|
||||||
* <p>
|
* <p>
|
||||||
* The presets 0-3 are fast presets with medium compression.
|
* The presets 0-3 are fast presets with medium compression. The presets 4-6
|
||||||
* The presets 4-6 are fairly slow presets with high compression.
|
* are fairly slow presets with high compression. The default preset
|
||||||
* The default preset (<code>PRESET_DEFAULT</code>) is 6.
|
* (<code>PRESET_DEFAULT</code>) is 6.
|
||||||
* <p>
|
* <p>
|
||||||
* The presets 7-9 are like the preset 6 but use bigger dictionaries
|
* The presets 7-9 are like the preset 6 but use bigger dictionaries and
|
||||||
* and have higher compressor and decompressor memory requirements.
|
* have higher compressor and decompressor memory requirements. Unless the
|
||||||
* Unless the uncompressed size of the file exceeds 8 MiB,
|
* uncompressed size of the file exceeds 8 MiB, 16 MiB, or
|
||||||
* 16 MiB, or 32 MiB, it is waste of memory to use the
|
* 32 MiB, it is waste of memory to use the presets 7, 8, or 9,
|
||||||
* presets 7, 8, or 9, respectively.
|
* respectively.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>preset</code> is not supported
|
||||||
* <code>preset</code> is not supported
|
|
||||||
*/
|
*/
|
||||||
public void setPreset(int preset) throws UnsupportedOptionsException {
|
public void setPreset(int preset) throws UnsupportedOptionsException {
|
||||||
if (preset < 0 || preset > 9)
|
if (preset < 0 || preset > 9)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported preset: " + preset);
|
"Unsupported preset: " + preset);
|
||||||
|
|
||||||
lc = LC_DEFAULT;
|
lc = LC_DEFAULT;
|
||||||
lp = LP_DEFAULT;
|
lp = LP_DEFAULT;
|
||||||
@@ -227,23 +223,22 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
* However, using a dictioanary bigger than the size of the uncompressed
|
* However, using a dictioanary bigger than the size of the uncompressed
|
||||||
* data is waste of memory.
|
* data is waste of memory.
|
||||||
* <p>
|
* <p>
|
||||||
* Any value in the range [DICT_SIZE_MIN, DICT_SIZE_MAX] is valid,
|
* Any value in the range [DICT_SIZE_MIN, DICT_SIZE_MAX] is valid, but sizes
|
||||||
* but sizes of 2^n and 2^n + 2^(n-1) bytes are somewhat
|
* of 2^n and 2^n + 2^(n-1) bytes are somewhat recommended.
|
||||||
* recommended.
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>dictSize</code> is not
|
||||||
* <code>dictSize</code> is not supported
|
* supported
|
||||||
*/
|
*/
|
||||||
public void setDictSize(int dictSize) throws UnsupportedOptionsException {
|
public void setDictSize(int dictSize) throws UnsupportedOptionsException {
|
||||||
if (dictSize < DICT_SIZE_MIN)
|
if (dictSize < DICT_SIZE_MIN)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"LZMA2 dictionary size must be at least 4 KiB: "
|
"LZMA2 dictionary size must be at least 4 KiB: "
|
||||||
+ dictSize + " B");
|
+ dictSize + " B");
|
||||||
|
|
||||||
if (dictSize > DICT_SIZE_MAX)
|
if (dictSize > DICT_SIZE_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"LZMA2 dictionary size must not exceed "
|
"LZMA2 dictionary size must not exceed "
|
||||||
+ (DICT_SIZE_MAX >> 20) + " MiB: " + dictSize + " B");
|
+ (DICT_SIZE_MAX >> 20) + " MiB: " + dictSize + " B");
|
||||||
|
|
||||||
this.dictSize = dictSize;
|
this.dictSize = dictSize;
|
||||||
}
|
}
|
||||||
@@ -256,18 +251,18 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a preset dictionary. Use null to disable the use of
|
* Sets a preset dictionary. Use null to disable the use of a preset
|
||||||
* a preset dictionary. By default there is no preset dictionary.
|
* dictionary. By default there is no preset dictionary.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>The .xz format doesn't support a preset dictionary for now.
|
* <b>The .xz format doesn't support a preset dictionary for now. Do not set
|
||||||
* Do not set a preset dictionary unless you use raw LZMA2.</b>
|
* a preset dictionary unless you use raw LZMA2.</b>
|
||||||
* <p>
|
* <p>
|
||||||
* Preset dictionary can be useful when compressing many similar,
|
* Preset dictionary can be useful when compressing many similar, relatively
|
||||||
* relatively small chunks of data independently from each other.
|
* small chunks of data independently from each other. A preset dictionary
|
||||||
* A preset dictionary should contain typical strings that occur in
|
* should contain typical strings that occur in the files being compressed.
|
||||||
* the files being compressed. The most probable strings should be
|
* The most probable strings should be near the end of the preset
|
||||||
* near the end of the preset dictionary. The preset dictionary used
|
* dictionary. The preset dictionary used for compression is also needed for
|
||||||
* for compression is also needed for decompression.
|
* decompression.
|
||||||
*/
|
*/
|
||||||
public void setPresetDict(byte[] presetDict) {
|
public void setPresetDict(byte[] presetDict) {
|
||||||
this.presetDict = presetDict;
|
this.presetDict = presetDict;
|
||||||
@@ -283,20 +278,19 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the number of literal context bits and literal position bits.
|
* Sets the number of literal context bits and literal position bits.
|
||||||
* <p>
|
* <p>
|
||||||
* The sum of <code>lc</code> and <code>lp</code> is limited to 4.
|
* The sum of <code>lc</code> and <code>lp</code> is limited to 4. Trying to
|
||||||
* Trying to exceed it will throw an exception. This function lets
|
* exceed it will throw an exception. This function lets you change both at
|
||||||
* you change both at the same time.
|
* the same time.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>lc</code> and <code>lp</code>
|
||||||
* <code>lc</code> and <code>lp</code>
|
|
||||||
* are invalid
|
* are invalid
|
||||||
*/
|
*/
|
||||||
public void setLcLp(int lc, int lp) throws UnsupportedOptionsException {
|
public void setLcLp(int lc, int lp) throws UnsupportedOptionsException {
|
||||||
if (lc < 0 || lp < 0 || lc > LC_LP_MAX || lp > LC_LP_MAX
|
if (lc < 0 || lp < 0 || lc > LC_LP_MAX || lp > LC_LP_MAX
|
||||||
|| lc + lp > LC_LP_MAX)
|
|| lc + lp > LC_LP_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"lc + lp must not exceed " + LC_LP_MAX + ": "
|
"lc + lp must not exceed " + LC_LP_MAX + ": "
|
||||||
+ lc + " + " + lp);
|
+ lc + " + " + lp);
|
||||||
|
|
||||||
this.lc = lc;
|
this.lc = lc;
|
||||||
this.lp = lp;
|
this.lp = lp;
|
||||||
@@ -305,28 +299,25 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the number of literal context bits.
|
* Sets the number of literal context bits.
|
||||||
* <p>
|
* <p>
|
||||||
* All bytes that cannot be encoded as matches are encoded as literals.
|
* All bytes that cannot be encoded as matches are encoded as literals. That
|
||||||
* That is, literals are simply 8-bit bytes that are encoded one at
|
* is, literals are simply 8-bit bytes that are encoded one at a time.
|
||||||
* a time.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The literal coding makes an assumption that the highest <code>lc</code>
|
* The literal coding makes an assumption that the highest <code>lc</code>
|
||||||
* bits of the previous uncompressed byte correlate with the next byte.
|
* bits of the previous uncompressed byte correlate with the next byte. For
|
||||||
* For example, in typical English text, an upper-case letter is often
|
* example, in typical English text, an upper-case letter is often followed
|
||||||
* followed by a lower-case letter, and a lower-case letter is usually
|
* by a lower-case letter, and a lower-case letter is usually followed by
|
||||||
* followed by another lower-case letter. In the US-ASCII character set,
|
* another lower-case letter. In the US-ASCII character set, the highest
|
||||||
* the highest three bits are 010 for upper-case letters and 011 for
|
* three bits are 010 for upper-case letters and 011 for lower-case letters.
|
||||||
* lower-case letters. When <code>lc</code> is at least 3, the literal
|
* When <code>lc</code> is at least 3, the literal coding can take advantage
|
||||||
* coding can take advantage of this property in the uncompressed data.
|
* of this property in the uncompressed data.
|
||||||
* <p>
|
* <p>
|
||||||
* The default value (3) is usually good. If you want maximum compression,
|
* The default value (3) is usually good. If you want maximum compression,
|
||||||
* try <code>setLc(4)</code>. Sometimes it helps a little, and sometimes it
|
* try <code>setLc(4)</code>. Sometimes it helps a little, and sometimes it
|
||||||
* makes compression worse. If it makes it worse, test for example
|
* makes compression worse. If it makes it worse, test for example
|
||||||
* <code>setLc(2)</code> too.
|
* <code>setLc(2)</code> too.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>lc</code> is invalid, or the
|
||||||
* <code>lc</code> is invalid, or the sum
|
* sum of <code>lc</code> and <code>lp</code> exceed LC_LP_MAX
|
||||||
* of <code>lc</code> and <code>lp</code>
|
|
||||||
* exceed LC_LP_MAX
|
|
||||||
*/
|
*/
|
||||||
public void setLc(int lc) throws UnsupportedOptionsException {
|
public void setLc(int lc) throws UnsupportedOptionsException {
|
||||||
setLcLp(lc, lp);
|
setLcLp(lc, lp);
|
||||||
@@ -335,14 +326,12 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the number of literal position bits.
|
* Sets the number of literal position bits.
|
||||||
* <p>
|
* <p>
|
||||||
* This affets what kind of alignment in the uncompressed data is
|
* This affets what kind of alignment in the uncompressed data is assumed
|
||||||
* assumed when encoding literals. See {@link #setPb(int) setPb} for
|
* when encoding literals. See {@link #setPb(int) setPb} for more
|
||||||
* more information about alignment.
|
* information about alignment.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>lp</code> is invalid, or the
|
||||||
* <code>lp</code> is invalid, or the sum
|
* sum of <code>lc</code> and <code>lp</code> exceed LC_LP_MAX
|
||||||
* of <code>lc</code> and <code>lp</code>
|
|
||||||
* exceed LC_LP_MAX
|
|
||||||
*/
|
*/
|
||||||
public void setLp(int lp) throws UnsupportedOptionsException {
|
public void setLp(int lp) throws UnsupportedOptionsException {
|
||||||
setLcLp(lc, lp);
|
setLcLp(lc, lp);
|
||||||
@@ -365,31 +354,28 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the number of position bits.
|
* Sets the number of position bits.
|
||||||
* <p>
|
* <p>
|
||||||
* This affects what kind of alignment in the uncompressed data is
|
* This affects what kind of alignment in the uncompressed data is assumed
|
||||||
* assumed in general. The default (2) means four-byte alignment
|
* in general. The default (2) means four-byte alignment (2^<code>pb</code>
|
||||||
* (2^<code>pb</code> = 2^2 = 4), which is often a good choice when
|
* = 2^2 = 4), which is often a good choice when there's no better guess.
|
||||||
* there's no better guess.
|
|
||||||
* <p>
|
* <p>
|
||||||
* When the alignment is known, setting the number of position bits
|
* When the alignment is known, setting the number of position bits
|
||||||
* accordingly may reduce the file size a little. For example with text
|
* accordingly may reduce the file size a little. For example with text
|
||||||
* files having one-byte alignment (US-ASCII, ISO-8859-*, UTF-8), using
|
* files having one-byte alignment (US-ASCII, ISO-8859-*, UTF-8), using
|
||||||
* <code>setPb(0)</code> can improve compression slightly. For UTF-16
|
* <code>setPb(0)</code> can improve compression slightly. For UTF-16 text,
|
||||||
* text, <code>setPb(1)</code> is a good choice. If the alignment is
|
* <code>setPb(1)</code> is a good choice. If the alignment is an odd number
|
||||||
* an odd number like 3 bytes, <code>setPb(0)</code> might be the best
|
* like 3 bytes, <code>setPb(0)</code> might be the best choice.
|
||||||
* choice.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Even though the assumed alignment can be adjusted with
|
* Even though the assumed alignment can be adjusted with <code>setPb</code>
|
||||||
* <code>setPb</code> and <code>setLp</code>, LZMA2 still slightly favors
|
* and <code>setLp</code>, LZMA2 still slightly favors 16-byte alignment. It
|
||||||
* 16-byte alignment. It might be worth taking into account when designing
|
* might be worth taking into account when designing file formats that are
|
||||||
* file formats that are likely to be often compressed with LZMA2.
|
* likely to be often compressed with LZMA2.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>pb</code> is invalid
|
||||||
* <code>pb</code> is invalid
|
|
||||||
*/
|
*/
|
||||||
public void setPb(int pb) throws UnsupportedOptionsException {
|
public void setPb(int pb) throws UnsupportedOptionsException {
|
||||||
if (pb < 0 || pb > PB_MAX)
|
if (pb < 0 || pb > PB_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"pb must not exceed " + PB_MAX + ": " + pb);
|
"pb must not exceed " + PB_MAX + ": " + pb);
|
||||||
|
|
||||||
this.pb = pb;
|
this.pb = pb;
|
||||||
}
|
}
|
||||||
@@ -404,25 +390,24 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the compression mode.
|
* Sets the compression mode.
|
||||||
* <p>
|
* <p>
|
||||||
* This specifies the method to analyze the data produced by
|
* This specifies the method to analyze the data produced by a match finder.
|
||||||
* a match finder. The default is <code>MODE_FAST</code> for presets
|
* The default is <code>MODE_FAST</code> for presets 0-3 and
|
||||||
* 0-3 and <code>MODE_NORMAL</code> for presets 4-9.
|
* <code>MODE_NORMAL</code> for presets 4-9.
|
||||||
* <p>
|
* <p>
|
||||||
* Usually <code>MODE_FAST</code> is used with Hash Chain match finders
|
* Usually <code>MODE_FAST</code> is used with Hash Chain match finders and
|
||||||
* and <code>MODE_NORMAL</code> with Binary Tree match finders. This is
|
* <code>MODE_NORMAL</code> with Binary Tree match finders. This is also
|
||||||
* also what the presets do.
|
* what the presets do.
|
||||||
* <p>
|
* <p>
|
||||||
* The special mode <code>MODE_UNCOMPRESSED</code> doesn't try to
|
* The special mode <code>MODE_UNCOMPRESSED</code> doesn't try to compress
|
||||||
* compress the data at all (and doesn't use a match finder) and will
|
* the data at all (and doesn't use a match finder) and will simply wrap it
|
||||||
* simply wrap it in uncompressed LZMA2 chunks.
|
* in uncompressed LZMA2 chunks.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>mode</code> is not supported
|
||||||
* <code>mode</code> is not supported
|
|
||||||
*/
|
*/
|
||||||
public void setMode(int mode) throws UnsupportedOptionsException {
|
public void setMode(int mode) throws UnsupportedOptionsException {
|
||||||
if (mode < MODE_UNCOMPRESSED || mode > MODE_NORMAL)
|
if (mode < MODE_UNCOMPRESSED || mode > MODE_NORMAL)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported compression mode: " + mode);
|
"Unsupported compression mode: " + mode);
|
||||||
|
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
@@ -435,25 +420,23 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the nice length of matches.
|
* Sets the nice length of matches. Once a match of at least
|
||||||
* Once a match of at least <code>niceLen</code> bytes is found,
|
* <code>niceLen</code> bytes is found, the algorithm stops looking for
|
||||||
* the algorithm stops looking for better matches. Higher values tend
|
* better matches. Higher values tend to give better compression at the
|
||||||
* to give better compression at the expense of speed. The default
|
* expense of speed. The default depends on the preset.
|
||||||
* depends on the preset.
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>niceLen</code> is invalid
|
||||||
* <code>niceLen</code> is invalid
|
|
||||||
*/
|
*/
|
||||||
public void setNiceLen(int niceLen) throws UnsupportedOptionsException {
|
public void setNiceLen(int niceLen) throws UnsupportedOptionsException {
|
||||||
if (niceLen < NICE_LEN_MIN)
|
if (niceLen < NICE_LEN_MIN)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Minimum nice length of matches is "
|
"Minimum nice length of matches is "
|
||||||
+ NICE_LEN_MIN + " bytes: " + niceLen);
|
+ NICE_LEN_MIN + " bytes: " + niceLen);
|
||||||
|
|
||||||
if (niceLen > NICE_LEN_MAX)
|
if (niceLen > NICE_LEN_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Maximum nice length of matches is " + NICE_LEN_MAX
|
"Maximum nice length of matches is " + NICE_LEN_MAX
|
||||||
+ ": " + niceLen);
|
+ ": " + niceLen);
|
||||||
|
|
||||||
this.niceLen = niceLen;
|
this.niceLen = niceLen;
|
||||||
}
|
}
|
||||||
@@ -468,18 +451,17 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the match finder type.
|
* Sets the match finder type.
|
||||||
* <p>
|
* <p>
|
||||||
* Match finder has a major effect on compression speed, memory usage,
|
* Match finder has a major effect on compression speed, memory usage, and
|
||||||
* and compression ratio. Usually Hash Chain match finders are faster
|
* compression ratio. Usually Hash Chain match finders are faster than
|
||||||
* than Binary Tree match finders. The default depends on the preset:
|
* Binary Tree match finders. The default depends on the preset: 0-3 use
|
||||||
* 0-3 use <code>MF_HC4</code> and 4-9 use <code>MF_BT4</code>.
|
* <code>MF_HC4</code> and 4-9 use <code>MF_BT4</code>.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>mf</code> is not supported
|
||||||
* <code>mf</code> is not supported
|
|
||||||
*/
|
*/
|
||||||
public void setMatchFinder(int mf) throws UnsupportedOptionsException {
|
public void setMatchFinder(int mf) throws UnsupportedOptionsException {
|
||||||
if (mf != MF_HC4 && mf != MF_BT4)
|
if (mf != MF_HC4 && mf != MF_BT4)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported match finder: " + mf);
|
"Unsupported match finder: " + mf);
|
||||||
|
|
||||||
this.mf = mf;
|
this.mf = mf;
|
||||||
}
|
}
|
||||||
@@ -494,24 +476,23 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
/**
|
/**
|
||||||
* Sets the match finder search depth limit.
|
* Sets the match finder search depth limit.
|
||||||
* <p>
|
* <p>
|
||||||
* The default is a special value of <code>0</code> which indicates that
|
* The default is a special value of <code>0</code> which indicates that the
|
||||||
* the depth limit should be automatically calculated by the selected
|
* depth limit should be automatically calculated by the selected match
|
||||||
* match finder from the nice length of matches.
|
* finder from the nice length of matches.
|
||||||
* <p>
|
* <p>
|
||||||
* Reasonable depth limit for Hash Chain match finders is 4-100 and
|
* Reasonable depth limit for Hash Chain match finders is 4-100 and 16-1000
|
||||||
* 16-1000 for Binary Tree match finders. Using very high values can
|
* for Binary Tree match finders. Using very high values can make the
|
||||||
* make the compressor extremely slow with some files. Avoid settings
|
* compressor extremely slow with some files. Avoid settings higher than
|
||||||
* higher than 1000 unless you are prepared to interrupt the compression
|
* 1000 unless you are prepared to interrupt the compression in case it is
|
||||||
* in case it is taking far too long.
|
* taking far too long.
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException <code>depthLimit</code> is invalid
|
||||||
* <code>depthLimit</code> is invalid
|
|
||||||
*/
|
*/
|
||||||
public void setDepthLimit(int depthLimit)
|
public void setDepthLimit(int depthLimit)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
if (depthLimit < 0)
|
if (depthLimit < 0)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Depth limit cannot be negative: " + depthLimit);
|
"Depth limit cannot be negative: " + depthLimit);
|
||||||
|
|
||||||
this.depthLimit = depthLimit;
|
this.depthLimit = depthLimit;
|
||||||
}
|
}
|
||||||
@@ -540,12 +521,12 @@ public class LZMA2Options extends FilterOptions {
|
|||||||
* Gets how much memory the LZMA2 decoder will need to decompress the data
|
* Gets how much memory the LZMA2 decoder will need to decompress the data
|
||||||
* that was encoded with these options and stored in a .xz file.
|
* that was encoded with these options and stored in a .xz file.
|
||||||
* <p>
|
* <p>
|
||||||
* The returned value may bigger than the value returned by a direct call
|
* The returned value may bigger than the value returned by a direct call to
|
||||||
* to {@link LZMA2InputStream#getMemoryUsage(int)} if the dictionary size
|
* {@link LZMA2InputStream#getMemoryUsage(int)} if the dictionary size is
|
||||||
* is not 2^n or 2^n + 2^(n-1) bytes. This is because the .xz
|
* not 2^n or 2^n + 2^(n-1) bytes. This is because the .xz headers
|
||||||
* headers store the dictionary size in such a format and other values
|
* store the dictionary size in such a format and other values are rounded
|
||||||
* are rounded up to the next such value. Such rounding is harmess except
|
* up to the next such value. Such rounding is harmess except it might waste
|
||||||
* it might waste some memory if an unsual dictionary size is used.
|
* some memory if an unsual dictionary size is used.
|
||||||
* <p>
|
* <p>
|
||||||
* If you use raw LZMA2 streams and unusual dictioanary size, call
|
* If you use raw LZMA2 streams and unusual dictioanary size, call
|
||||||
* {@link LZMA2InputStream#getMemoryUsage} directly to get raw decoder
|
* {@link LZMA2InputStream#getMemoryUsage} directly to get raw decoder
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class LZMA2OutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeLZMA(int uncompressedSize, int compressedSize)
|
private void writeLZMA(int uncompressedSize, int compressedSize)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int control;
|
int control;
|
||||||
|
|
||||||
if (propsNeeded)
|
if (propsNeeded)
|
||||||
|
|||||||
@@ -20,16 +20,16 @@ import org.tukaani.xz.lzma.LZMADecoder;
|
|||||||
* Decompresses legacy .lzma files and raw LZMA streams (no .lzma header).
|
* Decompresses legacy .lzma files and raw LZMA streams (no .lzma header).
|
||||||
* <p>
|
* <p>
|
||||||
* <b>IMPORTANT:</b> In contrast to other classes in this package, this class
|
* <b>IMPORTANT:</b> In contrast to other classes in this package, this class
|
||||||
* reads data from its input stream one byte at a time. If the input stream
|
* reads data from its input stream one byte at a time. If the input stream is
|
||||||
* is for example {@link java.io.FileInputStream}, wrapping it into
|
* for example {@link java.io.FileInputStream}, wrapping it into
|
||||||
* {@link java.io.BufferedInputStream} tends to improve performance a lot.
|
* {@link java.io.BufferedInputStream} tends to improve performance a lot. This
|
||||||
* This is not automatically done by this class because there may be use
|
* is not automatically done by this class because there may be use cases where
|
||||||
* cases where it is desired that this class won't read any bytes past
|
* it is desired that this class won't read any bytes past the end of the LZMA
|
||||||
* the end of the LZMA stream.
|
* stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Even when using <code>BufferedInputStream</code>, the performance tends
|
* Even when using <code>BufferedInputStream</code>, the performance tends to be
|
||||||
* to be worse (maybe 10-20 % slower) than with {@link LZMA2InputStream}
|
* worse (maybe 10-20 % slower) than with {@link LZMA2InputStream} or
|
||||||
* or {@link XZInputStream} (when the .xz file contains LZMA2-compressed data).
|
* {@link XZInputStream} (when the .xz file contains LZMA2-compressed data).
|
||||||
*
|
*
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
@@ -39,10 +39,10 @@ public class LZMAInputStream extends InputStream {
|
|||||||
* Largest dictionary size supported by this implementation.
|
* Largest dictionary size supported by this implementation.
|
||||||
* <p>
|
* <p>
|
||||||
* LZMA allows dictionaries up to one byte less than 4 GiB. This
|
* LZMA allows dictionaries up to one byte less than 4 GiB. This
|
||||||
* implementation supports only 16 bytes less than 2 GiB. This
|
* implementation supports only 16 bytes less than 2 GiB. This limitation is
|
||||||
* limitation is due to Java using signed 32-bit integers for array
|
* due to Java using signed 32-bit integers for array indexing. The
|
||||||
* indexing. The limitation shouldn't matter much in practice since so
|
* limitation shouldn't matter much in practice since so huge dictionaries
|
||||||
* huge dictionaries are not normally used.
|
* are not normally used.
|
||||||
*/
|
*/
|
||||||
public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
|
public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
|
||||||
|
|
||||||
@@ -56,39 +56,35 @@ public class LZMAInputStream extends InputStream {
|
|||||||
private final byte[] tempBuf = new byte[1];
|
private final byte[] tempBuf = new byte[1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of uncompressed bytes left to be decompressed, or -1 if
|
* Number of uncompressed bytes left to be decompressed, or -1 if the end
|
||||||
* the end marker is used.
|
* marker is used.
|
||||||
*/
|
*/
|
||||||
private long remainingSize;
|
private long remainingSize;
|
||||||
|
|
||||||
private IOException exception = null;
|
private IOException exception = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets approximate decompressor memory requirements as kibibytes for
|
* Gets approximate decompressor memory requirements as kibibytes for the
|
||||||
* the given dictionary size and LZMA properties byte (lc, lp, and pb).
|
* given dictionary size and LZMA properties byte (lc, lp, and pb).
|
||||||
*
|
*
|
||||||
* @param dictSize LZMA dictionary size as bytes, should be
|
* @param dictSize LZMA dictionary size as bytes, should be in the range
|
||||||
* in the range [<code>0</code>,
|
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
* <code>DICT_SIZE_MAX</code>]
|
|
||||||
*
|
*
|
||||||
* @param propsByte LZMA properties byte that encodes the values
|
* @param propsByte LZMA properties byte that encodes the values of lc, lp,
|
||||||
* of lc, lp, and pb
|
* and pb
|
||||||
*
|
*
|
||||||
* @return approximate memory requirements as kibibytes (KiB)
|
* @return approximate memory requirements as kibibytes (KiB)
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException if <code>dictSize</code> is outside
|
||||||
* if <code>dictSize</code> is outside
|
* the range [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
* the range [<code>0</code>,
|
|
||||||
* <code>DICT_SIZE_MAX</code>]
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException if <code>propsByte</code> is invalid
|
||||||
* if <code>propsByte</code> is invalid
|
|
||||||
*/
|
*/
|
||||||
public static int getMemoryUsage(int dictSize, byte propsByte)
|
public static int getMemoryUsage(int dictSize, byte propsByte)
|
||||||
throws UnsupportedOptionsException, CorruptedInputException {
|
throws UnsupportedOptionsException, CorruptedInputException {
|
||||||
if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
|
if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"LZMA dictionary is too big for this implementation");
|
"LZMA dictionary is too big for this implementation");
|
||||||
|
|
||||||
int props = propsByte & 0xFF;
|
int props = propsByte & 0xFF;
|
||||||
if (props > (4 * 5 + 4) * 9 + 8)
|
if (props > (4 * 5 + 4) * 9 + 8)
|
||||||
@@ -102,18 +98,17 @@ public class LZMAInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets approximate decompressor memory requirements as kibibytes for
|
* Gets approximate decompressor memory requirements as kibibytes for the
|
||||||
* the given dictionary size, lc, and lp. Note that pb isn't needed.
|
* given dictionary size, lc, and lp. Note that pb isn't needed.
|
||||||
*
|
*
|
||||||
* @param dictSize LZMA dictionary size as bytes, must be
|
* @param dictSize LZMA dictionary size as bytes, must be in the range
|
||||||
* in the range [<code>0</code>,
|
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
* <code>DICT_SIZE_MAX</code>]
|
|
||||||
*
|
*
|
||||||
* @param lc number of literal context bits, must be
|
* @param lc number of literal context bits, must be in the range [0,
|
||||||
* in the range [0, 8]
|
* 8]
|
||||||
*
|
*
|
||||||
* @param lp number of literal position bits, must be
|
* @param lp number of literal position bits, must be in the range [0,
|
||||||
* in the range [0, 4]
|
* 4]
|
||||||
*
|
*
|
||||||
* @return approximate memory requirements as kibibytes (KiB)
|
* @return approximate memory requirements as kibibytes (KiB)
|
||||||
*/
|
*/
|
||||||
@@ -135,7 +130,7 @@ public class LZMAInputStream extends InputStream {
|
|||||||
private static int getDictSize(int dictSize) {
|
private static int getDictSize(int dictSize) {
|
||||||
if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
|
if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"LZMA dictionary is too big for this implementation");
|
"LZMA dictionary is too big for this implementation");
|
||||||
|
|
||||||
// For performance reasons, use a 4 KiB dictionary if something
|
// For performance reasons, use a 4 KiB dictionary if something
|
||||||
// smaller was requested. It's a rare situation and the performance
|
// smaller was requested. It's a rare situation and the performance
|
||||||
@@ -156,25 +151,22 @@ public class LZMAInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new .lzma file format decompressor without
|
* Creates a new .lzma file format decompressor without a memory usage
|
||||||
* a memory usage limit.
|
* limit.
|
||||||
*
|
*
|
||||||
* @param in input stream from which .lzma data is read;
|
* @param in input stream from which .lzma data is read; it might be a good
|
||||||
* it might be a good idea to wrap it in
|
* idea to wrap it in <code>BufferedInputStream</code>, see the note at the
|
||||||
* <code>BufferedInputStream</code>, see the
|
* top of this page
|
||||||
* note at the top of this page
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException file is corrupt or perhaps not in the
|
||||||
* file is corrupt or perhaps not in
|
* .lzma format at all
|
||||||
* the .lzma format at all
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||||
* dictionary size or uncompressed size is too
|
* is too big for this implementation
|
||||||
* big for this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException file is truncated or perhaps not in
|
||||||
* file is truncated or perhaps not in
|
* the .lzma format
|
||||||
* the .lzma format at all
|
* at all
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -183,37 +175,33 @@ public class LZMAInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new .lzma file format decompressor with an optional
|
* Creates a new .lzma file format decompressor with an optional memory
|
||||||
* memory usage limit.
|
* usage limit.
|
||||||
*
|
*
|
||||||
* @param in input stream from which .lzma data is read;
|
* @param in input stream from which .lzma data is read; it might
|
||||||
* it might be a good idea to wrap it in
|
* be a good
|
||||||
* <code>BufferedInputStream</code>, see the
|
* idea to wrap it in <code>BufferedInputStream</code>, see the note at the
|
||||||
* note at the top of this page
|
* top of this page
|
||||||
*
|
*
|
||||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||||
* or <code>-1</code> to impose no
|
* <code>-1</code> to impose no memory usage limit
|
||||||
* memory usage limit
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException file is corrupt or perhaps not in the
|
||||||
* file is corrupt or perhaps not in
|
* .lzma format at all
|
||||||
* the .lzma format at all
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||||
* dictionary size or uncompressed size is too
|
* is too big for this implementation
|
||||||
* big for this implementation
|
|
||||||
*
|
*
|
||||||
* @throws MemoryLimitException
|
* @throws MemoryLimitException memory usage limit was exceeded
|
||||||
* memory usage limit was exceeded
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException file is truncated or perhaps not in
|
||||||
* file is truncated or perhaps not in
|
* the .lzma format
|
||||||
* the .lzma format at all
|
* at all
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
public LZMAInputStream(InputStream in, int memoryLimit)
|
public LZMAInputStream(InputStream in, int memoryLimit)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
DataInputStream inData = new DataInputStream(in);
|
DataInputStream inData = new DataInputStream(in);
|
||||||
|
|
||||||
// Properties byte (lc, lp, and pb)
|
// Properties byte (lc, lp, and pb)
|
||||||
@@ -244,45 +232,43 @@ public class LZMAInputStream extends InputStream {
|
|||||||
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
||||||
* header) from <code>in</code>.
|
* header) from <code>in</code>.
|
||||||
* <p>
|
* <p>
|
||||||
* The caller needs to know if the "end of payload marker (EOPM)" alias
|
* The caller needs to know if the "end of payload marker (EOPM)" alias "end
|
||||||
* "end of stream marker (EOS marker)" alias "end marker" present.
|
* of stream marker (EOS marker)" alias "end marker" present. If the end
|
||||||
* If the end marker isn't used, the caller must know the exact
|
* marker isn't used, the caller must know the exact uncompressed size of
|
||||||
* uncompressed size of the stream.
|
* the stream.
|
||||||
* <p>
|
* <p>
|
||||||
* The caller also needs to provide the LZMA properties byte that encodes
|
* The caller also needs to provide the LZMA properties byte that encodes
|
||||||
* the number of literal context bits (lc), literal position bits (lp),
|
* the number of literal context bits (lc), literal position bits (lp), and
|
||||||
* and position bits (pb).
|
* position bits (pb).
|
||||||
* <p>
|
* <p>
|
||||||
* The dictionary size used when compressing is also needed. Specifying
|
* The dictionary size used when compressing is also needed. Specifying a
|
||||||
* a too small dictionary size will prevent decompressing the stream.
|
* too small dictionary size will prevent decompressing the stream.
|
||||||
* Specifying a too big dictionary is waste of memory but decompression
|
* Specifying a too big dictionary is waste of memory but decompression will
|
||||||
* will work.
|
* work.
|
||||||
* <p>
|
* <p>
|
||||||
* There is no need to specify a dictionary bigger than
|
* There is no need to specify a dictionary bigger than the uncompressed
|
||||||
* the uncompressed size of the data even if a bigger dictionary
|
* size of the data even if a bigger dictionary was used when compressing.
|
||||||
* was used when compressing. If you know the uncompressed size
|
* If you know the uncompressed size of the data, this might allow saving
|
||||||
* of the data, this might allow saving some memory.
|
* some memory.
|
||||||
*
|
*
|
||||||
* @param in input stream from which compressed
|
* @param in input stream from which compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param uncompSize uncompressed size of the LZMA stream or -1
|
* @param uncompSize uncompressed size of the LZMA stream or -1 if the end
|
||||||
* if the end marker is used in the LZMA stream
|
* marker is used in the LZMA stream
|
||||||
*
|
*
|
||||||
* @param propsByte LZMA properties byte that has the encoded
|
* @param propsByte LZMA properties byte that has the encoded values for
|
||||||
* values for literal context bits (lc), literal
|
* literal context bits (lc), literal position bits (lp), and position bits
|
||||||
* position bits (lp), and position bits (pb)
|
* (pb)
|
||||||
*
|
*
|
||||||
* @param dictSize dictionary size as bytes, must be in the range
|
* @param dictSize dictionary size as bytes, must be in the range
|
||||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException if <code>propsByte</code> is invalid
|
||||||
* if <code>propsByte</code> is invalid or
|
* or
|
||||||
* the first input byte is not 0x00
|
* the first input byte is not 0x00
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||||
* dictionary size or uncompressed size is too
|
* is too big for this implementation
|
||||||
* big for this implementation
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -295,29 +281,27 @@ public class LZMAInputStream extends InputStream {
|
|||||||
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
||||||
* header) from <code>in</code> optionally with a preset dictionary.
|
* header) from <code>in</code> optionally with a preset dictionary.
|
||||||
*
|
*
|
||||||
* @param in input stream from which LZMA-compressed
|
* @param in input stream from which LZMA-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param uncompSize uncompressed size of the LZMA stream or -1
|
* @param uncompSize uncompressed size of the LZMA stream or -1 if the end
|
||||||
* if the end marker is used in the LZMA stream
|
* marker is used in the LZMA stream
|
||||||
*
|
*
|
||||||
* @param propsByte LZMA properties byte that has the encoded
|
* @param propsByte LZMA properties byte that has the encoded values for
|
||||||
* values for literal context bits (lc), literal
|
* literal context bits (lc), literal position bits (lp), and position bits
|
||||||
* position bits (lp), and position bits (pb)
|
* (pb)
|
||||||
*
|
*
|
||||||
* @param dictSize dictionary size as bytes, must be in the range
|
* @param dictSize dictionary size as bytes, must be in the range
|
||||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
*
|
*
|
||||||
* @param presetDict preset dictionary or <code>null</code>
|
* @param presetDict preset dictionary or <code>null</code> to use no preset
|
||||||
* to use no preset dictionary
|
* dictionary
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException if <code>propsByte</code> is invalid
|
||||||
* if <code>propsByte</code> is invalid or
|
* or
|
||||||
* the first input byte is not 0x00
|
* the first input byte is not 0x00
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||||
* dictionary size or uncompressed size is too
|
* is too big for this implementation
|
||||||
* big for this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException file is truncated or corrupt
|
* @throws EOFException file is truncated or corrupt
|
||||||
*
|
*
|
||||||
@@ -325,7 +309,7 @@ public class LZMAInputStream extends InputStream {
|
|||||||
*/
|
*/
|
||||||
public LZMAInputStream(InputStream in, long uncompSize, byte propsByte,
|
public LZMAInputStream(InputStream in, long uncompSize, byte propsByte,
|
||||||
int dictSize, byte[] presetDict)
|
int dictSize, byte[] presetDict)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
initialize(in, uncompSize, propsByte, dictSize, presetDict);
|
initialize(in, uncompSize, propsByte, dictSize, presetDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,29 +317,26 @@ public class LZMAInputStream extends InputStream {
|
|||||||
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
||||||
* header) from <code>in</code> optionally with a preset dictionary.
|
* header) from <code>in</code> optionally with a preset dictionary.
|
||||||
*
|
*
|
||||||
* @param in input stream from which LZMA-compressed
|
* @param in input stream from which LZMA-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param uncompSize uncompressed size of the LZMA stream or -1
|
* @param uncompSize uncompressed size of the LZMA stream or -1 if the end
|
||||||
* if the end marker is used in the LZMA stream
|
* marker is used in the LZMA stream
|
||||||
*
|
*
|
||||||
* @param lc number of literal context bits, must be
|
* @param lc number of literal context bits, must be in the range
|
||||||
* in the range [0, 8]
|
* [0, 8]
|
||||||
*
|
*
|
||||||
* @param lp number of literal position bits, must be
|
* @param lp number of literal position bits, must be in the range
|
||||||
* in the range [0, 4]
|
* [0, 4]
|
||||||
*
|
*
|
||||||
* @param pb number position bits, must be
|
* @param pb number position bits, must be in the range [0, 4]
|
||||||
* in the range [0, 4]
|
|
||||||
*
|
*
|
||||||
* @param dictSize dictionary size as bytes, must be in the range
|
* @param dictSize dictionary size as bytes, must be in the range
|
||||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||||
*
|
*
|
||||||
* @param presetDict preset dictionary or <code>null</code>
|
* @param presetDict preset dictionary or <code>null</code> to use no preset
|
||||||
* to use no preset dictionary
|
* dictionary
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException if the first input byte is not 0x00
|
||||||
* if the first input byte is not 0x00
|
|
||||||
*
|
*
|
||||||
* @throws EOFException file is truncated or corrupt
|
* @throws EOFException file is truncated or corrupt
|
||||||
*
|
*
|
||||||
@@ -364,18 +345,18 @@ public class LZMAInputStream extends InputStream {
|
|||||||
public LZMAInputStream(InputStream in, long uncompSize,
|
public LZMAInputStream(InputStream in, long uncompSize,
|
||||||
int lc, int lp, int pb,
|
int lc, int lp, int pb,
|
||||||
int dictSize, byte[] presetDict)
|
int dictSize, byte[] presetDict)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
initialize(in, uncompSize, lc, lp, pb, dictSize, presetDict);
|
initialize(in, uncompSize, lc, lp, pb, dictSize, presetDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize(InputStream in, long uncompSize, byte propsByte,
|
private void initialize(InputStream in, long uncompSize, byte propsByte,
|
||||||
int dictSize, byte[] presetDict)
|
int dictSize, byte[] presetDict)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Validate the uncompressed size since the other "initialize" throws
|
// Validate the uncompressed size since the other "initialize" throws
|
||||||
// IllegalArgumentException if uncompSize < -1.
|
// IllegalArgumentException if uncompSize < -1.
|
||||||
if (uncompSize < -1)
|
if (uncompSize < -1)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Uncompressed size is too big");
|
"Uncompressed size is too big");
|
||||||
|
|
||||||
// Decode the properties byte. In contrast to LZMA2, there is no
|
// Decode the properties byte. In contrast to LZMA2, there is no
|
||||||
// limit of lc + lp <= 4.
|
// limit of lc + lp <= 4.
|
||||||
@@ -392,7 +373,7 @@ public class LZMAInputStream extends InputStream {
|
|||||||
// IllegalArgumentException if dictSize is not supported.
|
// IllegalArgumentException if dictSize is not supported.
|
||||||
if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
|
if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"LZMA dictionary is too big for this implementation");
|
"LZMA dictionary is too big for this implementation");
|
||||||
|
|
||||||
initialize(in, uncompSize, lc, lp, pb, dictSize, presetDict);
|
initialize(in, uncompSize, lc, lp, pb, dictSize, presetDict);
|
||||||
}
|
}
|
||||||
@@ -400,7 +381,7 @@ public class LZMAInputStream extends InputStream {
|
|||||||
private void initialize(InputStream in, long uncompSize,
|
private void initialize(InputStream in, long uncompSize,
|
||||||
int lc, int lp, int pb,
|
int lc, int lp, int pb,
|
||||||
int dictSize, byte[] presetDict)
|
int dictSize, byte[] presetDict)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// getDictSize validates dictSize and gives a message in
|
// getDictSize validates dictSize and gives a message in
|
||||||
// the exception too, so skip validating dictSize here.
|
// the exception too, so skip validating dictSize here.
|
||||||
if (uncompSize < -1 || lc < 0 || lc > 8 || lp < 0 || lp > 4
|
if (uncompSize < -1 || lc < 0 || lc > 8 || lp < 0 || lp > 4
|
||||||
@@ -424,19 +405,18 @@ public class LZMAInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses the next byte from this input stream.
|
* Decompresses the next byte from this input stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Reading lots of data with <code>read()</code> from this input stream
|
* Reading lots of data with <code>read()</code> from this input stream may
|
||||||
* may be inefficient. Wrap it in <code>java.io.BufferedInputStream</code>
|
* be inefficient. Wrap it in <code>java.io.BufferedInputStream</code> if
|
||||||
* if you need to read lots of data one byte at a time.
|
* you need to read lots of data one byte at a time.
|
||||||
*
|
*
|
||||||
* @return the next decompressed byte, or <code>-1</code>
|
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||||
* to indicate the end of the compressed stream
|
* end of the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or corrupt
|
||||||
* compressed input is truncated or corrupt
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -447,17 +427,17 @@ public class LZMAInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses into an array of bytes.
|
* Decompresses into an array of bytes.
|
||||||
* <p>
|
* <p>
|
||||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||||
* is returned. Otherwise this will block until <code>len</code>
|
* returned. Otherwise this will block until <code>len</code> bytes have
|
||||||
* bytes have been decompressed, the end of the LZMA stream is reached,
|
* been decompressed, the end of the LZMA stream is reached, or an exception
|
||||||
* or an exception is thrown.
|
* is thrown.
|
||||||
*
|
*
|
||||||
* @param buf target buffer for uncompressed data
|
* @param buf target buffer for uncompressed data
|
||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len maximum number of uncompressed bytes to read
|
* @param len maximum number of uncompressed bytes to read
|
||||||
*
|
*
|
||||||
* @return number of bytes read, or <code>-1</code> to indicate
|
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||||
* the end of the compressed stream
|
* the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
*
|
*
|
||||||
@@ -552,8 +532,8 @@ public class LZMAInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream and calls <code>in.close()</code>.
|
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||||
* If the stream was already closed, this does nothing.
|
* already closed, this does nothing.
|
||||||
*
|
*
|
||||||
* @throws IOException if thrown by <code>in.close()</code>
|
* @throws IOException if thrown by <code>in.close()</code>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
package org.tukaani.xz;
|
package org.tukaani.xz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when the memory usage limit given to the XZ decompressor
|
* Thrown when the memory usage limit given to the XZ decompressor would be
|
||||||
* would be exceeded.
|
* exceeded.
|
||||||
* <p>
|
* <p>
|
||||||
* The amount of memory required and the memory usage limit are
|
* The amount of memory required and the memory usage limit are included in the
|
||||||
* included in the error detail message in human readable format.
|
* error detail message in human readable format.
|
||||||
*/
|
*/
|
||||||
public class MemoryLimitException extends XZIOException {
|
public class MemoryLimitException extends XZIOException {
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ public class MemoryLimitException extends XZIOException {
|
|||||||
/**
|
/**
|
||||||
* Creates a new MemoryLimitException.
|
* Creates a new MemoryLimitException.
|
||||||
* <p>
|
* <p>
|
||||||
* The amount of memory needed and the memory usage limit are
|
* The amount of memory needed and the memory usage limit are included in
|
||||||
* included in the error detail message.
|
* the error detail message.
|
||||||
*
|
*
|
||||||
* @param memoryNeeded amount of memory needed as kibibytes (KiB)
|
* @param memoryNeeded amount of memory needed as kibibytes (KiB)
|
||||||
* @param memoryLimit specified memory usage limit as kibibytes (KiB)
|
* @param memoryLimit specified memory usage limit as kibibytes (KiB)
|
||||||
@@ -49,8 +49,8 @@ public class MemoryLimitException extends XZIOException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets what the memory usage limit was at the time the exception
|
* Gets what the memory usage limit was at the time the exception was
|
||||||
* was created.
|
* created.
|
||||||
*
|
*
|
||||||
* @return memory usage limit as kibibytes (KiB)
|
* @return memory usage limit as kibibytes (KiB)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ package org.tukaani.xz;
|
|||||||
class RawCoder {
|
class RawCoder {
|
||||||
|
|
||||||
static void validate(FilterCoder[] filters)
|
static void validate(FilterCoder[] filters)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
for (int i = 0; i < filters.length - 1; ++i)
|
for (int i = 0; i < filters.length - 1; ++i)
|
||||||
if (!filters[i].nonLastOK())
|
if (!filters[i].nonLastOK())
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported XZ filter chain");
|
"Unsupported XZ filter chain");
|
||||||
|
|
||||||
if (!filters[filters.length - 1].lastOK())
|
if (!filters[filters.length - 1].lastOK())
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported XZ filter chain");
|
"Unsupported XZ filter chain");
|
||||||
|
|
||||||
int changesSizeCount = 0;
|
int changesSizeCount = 0;
|
||||||
for (int i = 0; i < filters.length; ++i)
|
for (int i = 0; i < filters.length; ++i)
|
||||||
@@ -28,6 +28,6 @@ class RawCoder {
|
|||||||
|
|
||||||
if (changesSizeCount > 3)
|
if (changesSizeCount > 3)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported XZ filter chain");
|
"Unsupported XZ filter chain");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ import java.io.IOException;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a {@link java.io.RandomAccessFile RandomAccessFile}
|
* Wraps a {@link java.io.RandomAccessFile RandomAccessFile} in a
|
||||||
* in a SeekableInputStream.
|
* SeekableInputStream.
|
||||||
*/
|
*/
|
||||||
public class SeekableFileInputStream extends SeekableInputStream {
|
public class SeekableFileInputStream extends SeekableInputStream {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The RandomAccessFile that has been wrapped
|
* The RandomAccessFile that has been wrapped into a
|
||||||
* into a SeekableFileInputStream.
|
* SeekableFileInputStream.
|
||||||
*/
|
*/
|
||||||
protected RandomAccessFile randomAccessFile;
|
protected RandomAccessFile randomAccessFile;
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ public class SeekableFileInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new seekable input stream that reads from a file with
|
* Creates a new seekable input stream that reads from a file with the
|
||||||
* the specified name.
|
* specified name.
|
||||||
*/
|
*/
|
||||||
public SeekableFileInputStream(String name) throws FileNotFoundException {
|
public SeekableFileInputStream(String name) throws FileNotFoundException {
|
||||||
randomAccessFile = new RandomAccessFile(name, "r");
|
randomAccessFile = new RandomAccessFile(name, "r");
|
||||||
@@ -63,8 +63,7 @@ public class SeekableFileInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls
|
* Calls null null null null null null null null null null null {@link RandomAccessFile#read(byte[],int,int)
|
||||||
* {@link RandomAccessFile#read(byte[],int,int)
|
|
||||||
* randomAccessFile.read(buf, off, len)}.
|
* randomAccessFile.read(buf, off, len)}.
|
||||||
*/
|
*/
|
||||||
public int read(byte[] buf, int off, int len) throws IOException {
|
public int read(byte[] buf, int off, int len) throws IOException {
|
||||||
|
|||||||
@@ -19,22 +19,21 @@ public abstract class SeekableInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Seeks <code>n</code> bytes forward in this stream.
|
* Seeks <code>n</code> bytes forward in this stream.
|
||||||
* <p>
|
* <p>
|
||||||
* This will not seek past the end of the file. If the current position
|
* This will not seek past the end of the file. If the current position is
|
||||||
* is already at or past the end of the file, this doesn't seek at all
|
* already at or past the end of the file, this doesn't seek at all and
|
||||||
* and returns <code>0</code>. Otherwise, if skipping <code>n</code> bytes
|
* returns <code>0</code>. Otherwise, if skipping <code>n</code> bytes would
|
||||||
* would cause the position to exceed the stream size, this will do
|
* cause the position to exceed the stream size, this will do equivalent of
|
||||||
* equivalent of <code>seek(length())</code> and the return value will
|
* <code>seek(length())</code> and the return value will be adjusted
|
||||||
* be adjusted accordingly.
|
* accordingly.
|
||||||
* <p>
|
* <p>
|
||||||
* If <code>n</code> is negative, the position isn't changed and
|
* If <code>n</code> is negative, the position isn't changed and the return
|
||||||
* the return value is <code>0</code>. It doesn't seek backward
|
* value is <code>0</code>. It doesn't seek backward because it would
|
||||||
* because it would conflict with the specification of
|
* conflict with the specification of
|
||||||
* {@link java.io.InputStream#skip(long) InputStream.skip}.
|
* {@link java.io.InputStream#skip(long) InputStream.skip}.
|
||||||
*
|
*
|
||||||
* @return <code>0</code> if <code>n</code> is negative,
|
* @return <code>0</code> if <code>n</code> is negative, less than
|
||||||
* less than <code>n</code> if skipping <code>n</code>
|
* <code>n</code> if skipping <code>n</code> bytes would seek past the end
|
||||||
* bytes would seek past the end of the file,
|
* of the file, <code>n</code> otherwise
|
||||||
* <code>n</code> otherwise
|
|
||||||
*
|
*
|
||||||
* @throws IOException might be thrown by {@link #seek(long)}
|
* @throws IOException might be thrown by {@link #seek(long)}
|
||||||
*/
|
*/
|
||||||
@@ -68,14 +67,14 @@ public abstract class SeekableInputStream extends InputStream {
|
|||||||
* Seeks to the specified absolute position in the stream.
|
* Seeks to the specified absolute position in the stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Seeking past the end of the file should be supported by the subclasses
|
* Seeking past the end of the file should be supported by the subclasses
|
||||||
* unless there is a good reason to do otherwise. If one has seeked
|
* unless there is a good reason to do otherwise. If one has seeked past the
|
||||||
* past the end of the stream, <code>read</code> will return
|
* end of the stream, <code>read</code> will return <code>-1</code> to
|
||||||
* <code>-1</code> to indicate end of stream.
|
* indicate end of stream.
|
||||||
*
|
*
|
||||||
* @param pos new read position in the stream
|
* @param pos new read position in the stream
|
||||||
*
|
*
|
||||||
* @throws IOException if <code>pos</code> is negative or if
|
* @throws IOException if <code>pos</code> is negative or if a
|
||||||
* a stream-specific I/O error occurs
|
* stream-specific I/O error occurs
|
||||||
*/
|
*/
|
||||||
public abstract void seek(long pos) throws IOException;
|
public abstract void seek(long pos) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,53 +20,52 @@ import org.tukaani.xz.index.IndexDecoder;
|
|||||||
import org.tukaani.xz.index.BlockInfo;
|
import org.tukaani.xz.index.BlockInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompresses a .xz file in random access mode.
|
* Decompresses a .xz file in random access mode. This supports decompressing
|
||||||
* This supports decompressing concatenated .xz files.
|
* concatenated .xz files.
|
||||||
* <p>
|
* <p>
|
||||||
* Each .xz file consist of one or more Streams. Each Stream consist of zero
|
* Each .xz file consist of one or more Streams. Each Stream consist of zero or
|
||||||
* or more Blocks. Each Stream contains an Index of Streams' Blocks.
|
* more Blocks. Each Stream contains an Index of Streams' Blocks. The Indexes
|
||||||
* The Indexes from all Streams are loaded in RAM by a constructor of this
|
* from all Streams are loaded in RAM by a constructor of this class. A typical
|
||||||
* class. A typical .xz file has only one Stream, and parsing its Index will
|
* .xz file has only one Stream, and parsing its Index will need only three or
|
||||||
* need only three or four seeks.
|
* four seeks.
|
||||||
* <p>
|
* <p>
|
||||||
* To make random access possible, the data in a .xz file must be splitted
|
* To make random access possible, the data in a .xz file must be splitted into
|
||||||
* into multiple Blocks of reasonable size. Decompression can only start at
|
* multiple Blocks of reasonable size. Decompression can only start at a Block
|
||||||
* a Block boundary. When seeking to an uncompressed position that is not at
|
* boundary. When seeking to an uncompressed position that is not at a Block
|
||||||
* a Block boundary, decompression starts at the beginning of the Block and
|
* boundary, decompression starts at the beginning of the Block and throws away
|
||||||
* throws away data until the target position is reached. Thus, smaller Blocks
|
* data until the target position is reached. Thus, smaller Blocks mean faster
|
||||||
* mean faster seeks to arbitrary uncompressed positions. On the other hand,
|
* seeks to arbitrary uncompressed positions. On the other hand, smaller Blocks
|
||||||
* smaller Blocks mean worse compression. So one has to make a compromise
|
* mean worse compression. So one has to make a compromise between random access
|
||||||
* between random access speed and compression ratio.
|
* speed and compression ratio.
|
||||||
* <p>
|
* <p>
|
||||||
* Implementation note: This class uses linear search to locate the correct
|
* Implementation note: This class uses linear search to locate the correct
|
||||||
* Stream from the data structures in RAM. It was the simplest to implement
|
* Stream from the data structures in RAM. It was the simplest to implement and
|
||||||
* and should be fine as long as there aren't too many Streams. The correct
|
* should be fine as long as there aren't too many Streams. The correct Block
|
||||||
* Block inside a Stream is located using binary search and thus is fast
|
* inside a Stream is located using binary search and thus is fast even with a
|
||||||
* even with a huge number of Blocks.
|
* huge number of Blocks.
|
||||||
*
|
*
|
||||||
* <h4>Memory usage</h4>
|
* <h4>Memory usage</h4>
|
||||||
* <p>
|
* <p>
|
||||||
* The amount of memory needed for the Indexes is taken into account when
|
* The amount of memory needed for the Indexes is taken into account when
|
||||||
* checking the memory usage limit. Each Stream is calculated to need at
|
* checking the memory usage limit. Each Stream is calculated to need at least
|
||||||
* least 1 KiB of memory and each Block 16 bytes of memory, rounded up
|
* 1 KiB of memory and each Block 16 bytes of memory, rounded up to the
|
||||||
* to the next kibibyte. So unless the file has a huge number of Streams or
|
* next kibibyte. So unless the file has a huge number of Streams or Blocks,
|
||||||
* Blocks, these don't take significant amount of memory.
|
* these don't take significant amount of memory.
|
||||||
*
|
*
|
||||||
* <h4>Creating random-accessible .xz files</h4>
|
* <h4>Creating random-accessible .xz files</h4>
|
||||||
* <p>
|
* <p>
|
||||||
* When using {@link XZOutputStream}, a new Block can be started by calling
|
* When using {@link XZOutputStream}, a new Block can be started by calling its
|
||||||
* its {@link XZOutputStream#endBlock() endBlock} method. If you know
|
* {@link XZOutputStream#endBlock() endBlock} method. If you know that the
|
||||||
* that the decompressor will only need to seek to certain uncompressed
|
* decompressor will only need to seek to certain uncompressed positions, it can
|
||||||
* positions, it can be a good idea to start a new Block at (some of) these
|
* be a good idea to start a new Block at (some of) these positions (and only at
|
||||||
* positions (and only at these positions to get better compression ratio).
|
* these positions to get better compression ratio).
|
||||||
* <p>
|
* <p>
|
||||||
* liblzma in XZ Utils supports starting a new Block with
|
* liblzma in XZ Utils supports starting a new Block with
|
||||||
* <code>LZMA_FULL_FLUSH</code>. XZ Utils 5.1.1alpha added threaded
|
* <code>LZMA_FULL_FLUSH</code>. XZ Utils 5.1.1alpha added threaded compression
|
||||||
* compression which creates multi-Block .xz files. XZ Utils 5.1.1alpha
|
* which creates multi-Block .xz files. XZ Utils 5.1.1alpha also added the
|
||||||
* also added the option <code>--block-size=SIZE</code> to the xz command
|
* option <code>--block-size=SIZE</code> to the xz command line tool. XZ Utils
|
||||||
* line tool. XZ Utils 5.1.2alpha added a partial implementation of
|
* 5.1.2alpha added a partial implementation of <code>--block-list=SIZES</code>
|
||||||
* <code>--block-list=SIZES</code> which allows specifying sizes of
|
* which allows specifying sizes of individual Blocks.
|
||||||
* individual Blocks.
|
|
||||||
*
|
*
|
||||||
* @see SeekableFileInputStream
|
* @see SeekableFileInputStream
|
||||||
* @see XZInputStream
|
* @see XZInputStream
|
||||||
@@ -80,22 +79,21 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
private SeekableInputStream in;
|
private SeekableInputStream in;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory usage limit after the memory usage of the IndexDecoders have
|
* Memory usage limit after the memory usage of the IndexDecoders have been
|
||||||
* been substracted.
|
* substracted.
|
||||||
*/
|
*/
|
||||||
private final int memoryLimit;
|
private final int memoryLimit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory usage of the IndexDecoders.
|
* Memory usage of the IndexDecoders.
|
||||||
* <code>memoryLimit + indexMemoryUsage</code> equals the original
|
* <code>memoryLimit + indexMemoryUsage</code> equals the original memory
|
||||||
* memory usage limit that was passed to the constructor.
|
* usage limit that was passed to the constructor.
|
||||||
*/
|
*/
|
||||||
private int indexMemoryUsage = 0;
|
private int indexMemoryUsage = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of IndexDecoders, one for each Stream in the file.
|
* List of IndexDecoders, one for each Stream in the file. The list is in
|
||||||
* The list is in reverse order: The first element is
|
* reverse order: The first element is the last Stream in the file.
|
||||||
* the last Stream in the file.
|
|
||||||
*/
|
*/
|
||||||
private final ArrayList streams = new ArrayList();
|
private final ArrayList streams = new ArrayList();
|
||||||
|
|
||||||
@@ -120,20 +118,20 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
private int blockCount = 0;
|
private int blockCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size and position information about the current Block.
|
* Size and position information about the current Block. If there are no
|
||||||
* If there are no Blocks, all values will be <code>-1</code>.
|
* Blocks, all values will be <code>-1</code>.
|
||||||
*/
|
*/
|
||||||
private final BlockInfo curBlockInfo;
|
private final BlockInfo curBlockInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary (and cached) information about the Block whose information
|
* Temporary (and cached) information about the Block whose information is
|
||||||
* is queried via <code>getBlockPos</code> and related functions.
|
* queried via <code>getBlockPos</code> and related functions.
|
||||||
*/
|
*/
|
||||||
private final BlockInfo queriedBlockInfo;
|
private final BlockInfo queriedBlockInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integrity Check in the current XZ Stream. The constructor leaves
|
* Integrity Check in the current XZ Stream. The constructor leaves this to
|
||||||
* this to point to the Check of the first Stream.
|
* point to the Check of the first Stream.
|
||||||
*/
|
*/
|
||||||
private Check check;
|
private Check check;
|
||||||
|
|
||||||
@@ -153,14 +151,14 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
private long seekPos;
|
private long seekPos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True when <code>seek(long)</code> has been called but the actual
|
* True when <code>seek(long)</code> has been called but the actual seeking
|
||||||
* seeking hasn't been done yet.
|
* hasn't been done yet.
|
||||||
*/
|
*/
|
||||||
private boolean seekNeeded = false;
|
private boolean seekNeeded = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True when end of the file was reached. This can be cleared by
|
* True when end of the file was reached. This can be cleared by calling
|
||||||
* calling <code>seek(long)</code>.
|
* <code>seek(long)</code>.
|
||||||
*/
|
*/
|
||||||
private boolean endReached = false;
|
private boolean endReached = false;
|
||||||
|
|
||||||
@@ -170,75 +168,67 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
private IOException exception = null;
|
private IOException exception = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary buffer for read(). This avoids reallocating memory
|
* Temporary buffer for read(). This avoids reallocating memory on every
|
||||||
* on every read() call.
|
* read() call.
|
||||||
*/
|
*/
|
||||||
private final byte[] tempBuf = new byte[1];
|
private final byte[] tempBuf = new byte[1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new seekable XZ decompressor without a memory usage limit.
|
* Creates a new seekable XZ decompressor without a memory usage limit.
|
||||||
*
|
*
|
||||||
* @param in seekable input stream containing one or more
|
* @param in seekable input stream containing one or more XZ Streams; the
|
||||||
* XZ Streams; the whole input stream is used
|
* whole input stream is used
|
||||||
*
|
*
|
||||||
* @throws XZFormatException
|
* @throws XZFormatException input is not in the XZ format
|
||||||
* input is not in the XZ format
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException XZ data is corrupt or truncated
|
||||||
* XZ data is corrupt or truncated
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException XZ headers seem valid but they
|
||||||
* XZ headers seem valid but they specify
|
* specify options not supported by this implementation
|
||||||
* options not supported by this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException less than 6 bytes of input was
|
||||||
* less than 6 bytes of input was available
|
* available from
|
||||||
* from <code>in</code>, or (unlikely) the size
|
* <code>in</code>, or (unlikely) the size of the underlying stream got
|
||||||
* of the underlying stream got smaller while
|
* smaller while this was reading from it
|
||||||
* this was reading from it
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
public SeekableXZInputStream(SeekableInputStream in)
|
public SeekableXZInputStream(SeekableInputStream in)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this(in, -1);
|
this(in, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new seekable XZ decomporessor with an optional
|
* Creates a new seekable XZ decomporessor with an optional memory usage
|
||||||
* memory usage limit.
|
* limit.
|
||||||
*
|
*
|
||||||
* @param in seekable input stream containing one or more
|
* @param in seekable input stream containing one or more XZ
|
||||||
* XZ Streams; the whole input stream is used
|
* Streams; the
|
||||||
|
* whole input stream is used
|
||||||
*
|
*
|
||||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||||
* or <code>-1</code> to impose no
|
* <code>-1</code> to impose no memory usage limit
|
||||||
* memory usage limit
|
|
||||||
*
|
*
|
||||||
* @throws XZFormatException
|
* @throws XZFormatException input is not in the XZ format
|
||||||
* input is not in the XZ format
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException XZ data is corrupt or truncated
|
||||||
* XZ data is corrupt or truncated
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException XZ headers seem valid but they
|
||||||
* XZ headers seem valid but they specify
|
* specify options not supported by this implementation
|
||||||
* options not supported by this implementation
|
|
||||||
*
|
*
|
||||||
* @throws MemoryLimitException
|
* @throws MemoryLimitException decoded XZ Indexes would need more
|
||||||
* decoded XZ Indexes would need more memory
|
* memory
|
||||||
* than allowed by the memory usage limit
|
* than allowed by the memory usage limit
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException less than 6 bytes of input was
|
||||||
* less than 6 bytes of input was available
|
* available from
|
||||||
* from <code>in</code>, or (unlikely) the size
|
* <code>in</code>, or (unlikely) the size of the underlying stream got
|
||||||
* of the underlying stream got smaller while
|
* smaller while this was reading from it
|
||||||
* this was reading from it
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
public SeekableXZInputStream(SeekableInputStream in, int memoryLimit)
|
public SeekableXZInputStream(SeekableInputStream in, int memoryLimit)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
DataInputStream inData = new DataInputStream(in);
|
DataInputStream inData = new DataInputStream(in);
|
||||||
|
|
||||||
@@ -255,7 +245,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
long pos = in.length();
|
long pos = in.length();
|
||||||
if ((pos & 3) != 0)
|
if ((pos & 3) != 0)
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"XZ file size is not a multiple of 4 bytes");
|
"XZ file size is not a multiple of 4 bytes");
|
||||||
|
|
||||||
// Parse the headers starting from the end of the file.
|
// Parse the headers starting from the end of the file.
|
||||||
byte[] buf = new byte[DecoderUtil.STREAM_HEADER_SIZE];
|
byte[] buf = new byte[DecoderUtil.STREAM_HEADER_SIZE];
|
||||||
@@ -287,7 +277,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
StreamFlags streamFooter = DecoderUtil.decodeStreamFooter(buf);
|
StreamFlags streamFooter = DecoderUtil.decodeStreamFooter(buf);
|
||||||
if (streamFooter.backwardSize >= pos)
|
if (streamFooter.backwardSize >= pos)
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"Backward Size in XZ Stream Footer is too big");
|
"Backward Size in XZ Stream Footer is too big");
|
||||||
|
|
||||||
// Check that the Check ID is supported. Store it in case this
|
// Check that the Check ID is supported. Store it in case this
|
||||||
// is the first Stream in the file.
|
// is the first Stream in the file.
|
||||||
@@ -309,8 +299,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
// already needed so we need to recreate the exception.
|
// already needed so we need to recreate the exception.
|
||||||
assert memoryLimit >= 0;
|
assert memoryLimit >= 0;
|
||||||
throw new MemoryLimitException(
|
throw new MemoryLimitException(
|
||||||
e.getMemoryNeeded() + indexMemoryUsage,
|
e.getMemoryNeeded() + indexMemoryUsage,
|
||||||
memoryLimit + indexMemoryUsage);
|
memoryLimit + indexMemoryUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the memory usage and limit counters.
|
// Update the memory usage and limit counters.
|
||||||
@@ -342,7 +332,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
// Verify that the Stream Header matches the Stream Footer.
|
// Verify that the Stream Header matches the Stream Footer.
|
||||||
if (!DecoderUtil.areStreamFlagsEqual(streamHeader, streamFooter))
|
if (!DecoderUtil.areStreamFlagsEqual(streamHeader, streamFooter))
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"XZ Stream Footer does not match Stream Header");
|
"XZ Stream Footer does not match Stream Header");
|
||||||
|
|
||||||
// Update the total uncompressed size of the file and check that
|
// Update the total uncompressed size of the file and check that
|
||||||
// it doesn't overflow.
|
// it doesn't overflow.
|
||||||
@@ -354,7 +344,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
blockCount += index.getRecordCount();
|
blockCount += index.getRecordCount();
|
||||||
if (blockCount < 0)
|
if (blockCount < 0)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"XZ file has over " + Integer.MAX_VALUE + " Blocks");
|
"XZ file has over " + Integer.MAX_VALUE + " Blocks");
|
||||||
|
|
||||||
// Add this Stream to the list of Streams.
|
// Add this Stream to the list of Streams.
|
||||||
streams.add(index);
|
streams.add(index);
|
||||||
@@ -391,13 +381,11 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the types of integrity checks used in the .xz file.
|
* Gets the types of integrity checks used in the .xz file. Multiple checks
|
||||||
* Multiple checks are possible only if there are multiple
|
* are possible only if there are multiple concatenated XZ Streams.
|
||||||
* concatenated XZ Streams.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The returned value has a bit set for every check type that is present.
|
* The returned value has a bit set for every check type that is present.
|
||||||
* For example, if CRC64 and SHA-256 were used, the return value is
|
* For example, if CRC64 and SHA-256 were used, the return value is <code>(1 << XZ.CHECK_CRC64)
|
||||||
* <code>(1 << XZ.CHECK_CRC64)
|
|
||||||
* | (1 << XZ.CHECK_SHA256)</code>.
|
* | (1 << XZ.CHECK_SHA256)</code>.
|
||||||
*/
|
*/
|
||||||
public int getCheckTypes() {
|
public int getCheckTypes() {
|
||||||
@@ -405,22 +393,21 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the amount of memory in kibibytes (KiB) used by
|
* Gets the amount of memory in kibibytes (KiB) used by the data structures
|
||||||
* the data structures needed to locate the XZ Blocks.
|
* needed to locate the XZ Blocks. This is usually useless information but
|
||||||
* This is usually useless information but since it is calculated
|
* since it is calculated for memory usage limit anyway, it is nice to make
|
||||||
* for memory usage limit anyway, it is nice to make it available to too.
|
* it available to too.
|
||||||
*/
|
*/
|
||||||
public int getIndexMemoryUsage() {
|
public int getIndexMemoryUsage() {
|
||||||
return indexMemoryUsage;
|
return indexMemoryUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the uncompressed size of the largest XZ Block in bytes.
|
* Gets the uncompressed size of the largest XZ Block in bytes. This can be
|
||||||
* This can be useful if you want to check that the file doesn't
|
* useful if you want to check that the file doesn't have huge XZ Blocks
|
||||||
* have huge XZ Blocks which could make seeking to arbitrary offsets
|
* which could make seeking to arbitrary offsets very slow. Note that huge
|
||||||
* very slow. Note that huge Blocks don't automatically mean that
|
* Blocks don't automatically mean that seeking would be slow, for example,
|
||||||
* seeking would be slow, for example, seeking to the beginning of
|
* seeking to the beginning of any Block is always fast.
|
||||||
* any Block is always fast.
|
|
||||||
*/
|
*/
|
||||||
public long getLargestBlockSize() {
|
public long getLargestBlockSize() {
|
||||||
return largestBlockSize;
|
return largestBlockSize;
|
||||||
@@ -473,9 +460,9 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the position where the given compressed Block starts in
|
* Gets the position where the given compressed Block starts in the
|
||||||
* the underlying .xz file.
|
* underlying .xz file. This information is rarely useful to the users of
|
||||||
* This information is rarely useful to the users of this class.
|
* this class.
|
||||||
*
|
*
|
||||||
* @throws IndexOutOfBoundsException if
|
* @throws IndexOutOfBoundsException if
|
||||||
* <code>blockNumber < 0</code> or
|
* <code>blockNumber < 0</code> or
|
||||||
@@ -489,9 +476,9 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the compressed size of the given Block.
|
* Gets the compressed size of the given Block. This together with the
|
||||||
* This together with the uncompressed size can be used to calculate
|
* uncompressed size can be used to calculate the compression ratio of the
|
||||||
* the compression ratio of the specific Block.
|
* specific Block.
|
||||||
*
|
*
|
||||||
* @throws IndexOutOfBoundsException if
|
* @throws IndexOutOfBoundsException if
|
||||||
* <code>blockNumber < 0</code> or
|
* <code>blockNumber < 0</code> or
|
||||||
@@ -524,8 +511,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
* Gets the number of the Block that contains the byte at the given
|
* Gets the number of the Block that contains the byte at the given
|
||||||
* uncompressed position.
|
* uncompressed position.
|
||||||
*
|
*
|
||||||
* @throws IndexOutOfBoundsException if
|
* @throws IndexOutOfBoundsException if <code>pos < 0</code> or
|
||||||
* <code>pos < 0</code> or
|
|
||||||
* <code>pos >= length()</code>.
|
* <code>pos >= length()</code>.
|
||||||
*
|
*
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
@@ -538,8 +524,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses the next byte from this input stream.
|
* Decompresses the next byte from this input stream.
|
||||||
*
|
*
|
||||||
* @return the next decompressed byte, or <code>-1</code>
|
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||||
* to indicate the end of the compressed stream
|
* end of the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException
|
||||||
@@ -556,16 +542,16 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses into an array of bytes.
|
* Decompresses into an array of bytes.
|
||||||
* <p>
|
* <p>
|
||||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||||
* is returned. Otherwise this will try to decompress <code>len</code>
|
* returned. Otherwise this will try to decompress <code>len</code> bytes of
|
||||||
* bytes of uncompressed data. Less than <code>len</code> bytes may
|
* uncompressed data. Less than <code>len</code> bytes may be read only in
|
||||||
* be read only in the following situations:
|
* the following situations:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The end of the compressed data was reached successfully.</li>
|
* <li>The end of the compressed data was reached successfully.</li>
|
||||||
* <li>An error is detected after at least one but less than
|
* <li>An error is detected after at least one but less than
|
||||||
* <code>len</code> bytes have already been successfully
|
* <code>len</code> bytes have already been successfully decompressed. The
|
||||||
* decompressed. The next call with non-zero <code>len</code>
|
* next call with non-zero <code>len</code> will immediately throw the
|
||||||
* will immediately throw the pending exception.</li>
|
* pending exception.</li>
|
||||||
* <li>An exception is thrown.</li>
|
* <li>An exception is thrown.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@@ -573,8 +559,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len maximum number of uncompressed bytes to read
|
* @param len maximum number of uncompressed bytes to read
|
||||||
*
|
*
|
||||||
* @return number of bytes read, or <code>-1</code> to indicate
|
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||||
* the end of the compressed stream
|
* the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException
|
||||||
@@ -639,15 +625,14 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of uncompressed bytes that can be read
|
* Returns the number of uncompressed bytes that can be read without
|
||||||
* without blocking. The value is returned with an assumption
|
* blocking. The value is returned with an assumption that the compressed
|
||||||
* that the compressed input data will be valid. If the compressed
|
* input data will be valid. If the compressed data is corrupt,
|
||||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||||
* thrown before the number of bytes claimed to be available have
|
* bytes claimed to be available have been read from this input stream.
|
||||||
* been read from this input stream.
|
|
||||||
*
|
*
|
||||||
* @return the number of uncompressed bytes that can be read
|
* @return the number of uncompressed bytes that can be read without
|
||||||
* without blocking
|
* blocking
|
||||||
*/
|
*/
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
if (in == null)
|
if (in == null)
|
||||||
@@ -663,8 +648,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream and calls <code>in.close()</code>.
|
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||||
* If the stream was already closed, this does nothing.
|
* already closed, this does nothing.
|
||||||
*
|
*
|
||||||
* @throws IOException if thrown by <code>in.close()</code>
|
* @throws IOException if thrown by <code>in.close()</code>
|
||||||
*/
|
*/
|
||||||
@@ -678,8 +663,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the uncompressed size of this input stream. If there are multiple
|
* Gets the uncompressed size of this input stream. If there are multiple XZ
|
||||||
* XZ Streams, the total uncompressed size of all XZ Streams is returned.
|
* Streams, the total uncompressed size of all XZ Streams is returned.
|
||||||
*/
|
*/
|
||||||
public long length() {
|
public long length() {
|
||||||
return uncompressedSize;
|
return uncompressedSize;
|
||||||
@@ -698,20 +683,19 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seeks to the specified absolute uncompressed position in the stream.
|
* Seeks to the specified absolute uncompressed position in the stream. This
|
||||||
* This only stores the new position, so this function itself is always
|
* only stores the new position, so this function itself is always very
|
||||||
* very fast. The actual seek is done when <code>read</code> is called
|
* fast. The actual seek is done when <code>read</code> is called to read at
|
||||||
* to read at least one byte.
|
* least one byte.
|
||||||
* <p>
|
* <p>
|
||||||
* Seeking past the end of the stream is possible. In that case
|
* Seeking past the end of the stream is possible. In that case
|
||||||
* <code>read</code> will return <code>-1</code> to indicate
|
* <code>read</code> will return <code>-1</code> to indicate the end of the
|
||||||
* the end of the stream.
|
* stream.
|
||||||
*
|
*
|
||||||
* @param pos new uncompressed read position
|
* @param pos new uncompressed read position
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException if <code>pos</code> is negative, or if stream has
|
||||||
* if <code>pos</code> is negative, or
|
* been closed
|
||||||
* if stream has been closed
|
|
||||||
*/
|
*/
|
||||||
public void seek(long pos) throws IOException {
|
public void seek(long pos) throws IOException {
|
||||||
if (in == null)
|
if (in == null)
|
||||||
@@ -727,10 +711,9 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
/**
|
/**
|
||||||
* Seeks to the beginning of the given XZ Block.
|
* Seeks to the beginning of the given XZ Block.
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException if <code>blockNumber < 0</code> or
|
||||||
* if <code>blockNumber < 0</code> or
|
* <code>blockNumber >= getBlockCount()</code>, or if stream
|
||||||
* <code>blockNumber >= getBlockCount()</code>,
|
* has been closed
|
||||||
* or if stream has been closed
|
|
||||||
*
|
*
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
@@ -749,8 +732,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the actual seeking. This is also called when <code>read</code>
|
* Does the actual seeking. This is also called when <code>read</code> needs
|
||||||
* needs a new Block to decode.
|
* a new Block to decode.
|
||||||
*/
|
*/
|
||||||
private void seek() throws IOException {
|
private void seek() throws IOException {
|
||||||
// If seek(long) wasn't called, we simply need to get the next Block
|
// If seek(long) wasn't called, we simply need to get the next Block
|
||||||
@@ -824,7 +807,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
private void locateBlockByPos(BlockInfo info, long pos) {
|
private void locateBlockByPos(BlockInfo info, long pos) {
|
||||||
if (pos < 0 || pos >= uncompressedSize)
|
if (pos < 0 || pos >= uncompressedSize)
|
||||||
throw new IndexOutOfBoundsException(
|
throw new IndexOutOfBoundsException(
|
||||||
"Invalid uncompressed position: " + pos);
|
"Invalid uncompressed position: " + pos);
|
||||||
|
|
||||||
// Locate the Stream that contains the target position.
|
// Locate the Stream that contains the target position.
|
||||||
IndexDecoder index;
|
IndexDecoder index;
|
||||||
@@ -844,14 +827,14 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locates the given Block and stores information about it
|
* Locates the given Block and stores information about it to
|
||||||
* to <code>info</code>.
|
* <code>info</code>.
|
||||||
*/
|
*/
|
||||||
private void locateBlockByNumber(BlockInfo info, int blockNumber) {
|
private void locateBlockByNumber(BlockInfo info, int blockNumber) {
|
||||||
// Validate.
|
// Validate.
|
||||||
if (blockNumber < 0 || blockNumber >= blockCount)
|
if (blockNumber < 0 || blockNumber >= blockCount)
|
||||||
throw new IndexOutOfBoundsException(
|
throw new IndexOutOfBoundsException(
|
||||||
"Invalid XZ Block number: " + blockNumber);
|
"Invalid XZ Block number: " + blockNumber);
|
||||||
|
|
||||||
// Skip the search if info already points to the correct Block.
|
// Skip the search if info already points to the correct Block.
|
||||||
if (info.blockNumber == blockNumber)
|
if (info.blockNumber == blockNumber)
|
||||||
@@ -884,8 +867,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
|||||||
// already needed so we need to recreate the exception.
|
// already needed so we need to recreate the exception.
|
||||||
assert memoryLimit >= 0;
|
assert memoryLimit >= 0;
|
||||||
throw new MemoryLimitException(
|
throw new MemoryLimitException(
|
||||||
e.getMemoryNeeded() + indexMemoryUsage,
|
e.getMemoryNeeded() + indexMemoryUsage,
|
||||||
memoryLimit + indexMemoryUsage);
|
memoryLimit + indexMemoryUsage);
|
||||||
} catch (IndexIndicatorException e) {
|
} catch (IndexIndicatorException e) {
|
||||||
// It cannot be Index so the file must be corrupt.
|
// It cannot be Index so the file must be corrupt.
|
||||||
throw new CorruptedInputException();
|
throw new CorruptedInputException();
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ import org.tukaani.xz.index.IndexHash;
|
|||||||
import org.tukaani.xz.check.Check;
|
import org.tukaani.xz.check.Check;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompresses exactly one XZ Stream in streamed mode (no seeking).
|
* Decompresses exactly one XZ Stream in streamed mode (no seeking). The
|
||||||
* The decompression stops after the first XZ Stream has been decompressed,
|
* decompression stops after the first XZ Stream has been decompressed, and the
|
||||||
* and the read position in the input stream is left at the first byte
|
* read position in the input stream is left at the first byte after the end of
|
||||||
* after the end of the XZ Stream. This can be useful when XZ data has
|
* the XZ Stream. This can be useful when XZ data has been stored inside some
|
||||||
* been stored inside some other file format or protocol.
|
* other file format or protocol.
|
||||||
* <p>
|
* <p>
|
||||||
* Unless you know what you are doing, don't use this class to decompress
|
* Unless you know what you are doing, don't use this class to decompress
|
||||||
* standalone .xz files. For that purpose, use <code>XZInputStream</code>.
|
* standalone .xz files. For that purpose, use <code>XZInputStream</code>.
|
||||||
@@ -30,11 +30,11 @@ import org.tukaani.xz.check.Check;
|
|||||||
* <h4>When uncompressed size is known beforehand</h4>
|
* <h4>When uncompressed size is known beforehand</h4>
|
||||||
* <p>
|
* <p>
|
||||||
* If you are decompressing complete XZ streams and your application knows
|
* If you are decompressing complete XZ streams and your application knows
|
||||||
* exactly how much uncompressed data there should be, it is good to try
|
* exactly how much uncompressed data there should be, it is good to try reading
|
||||||
* reading one more byte by calling <code>read()</code> and checking
|
* one more byte by calling <code>read()</code> and checking that it returns
|
||||||
* that it returns <code>-1</code>. This way the decompressor will parse the
|
* <code>-1</code>. This way the decompressor will parse the file footers and
|
||||||
* file footers and verify the integrity checks, giving the caller more
|
* verify the integrity checks, giving the caller more confidence that the
|
||||||
* confidence that the uncompressed data is valid.
|
* uncompressed data is valid.
|
||||||
*
|
*
|
||||||
* @see XZInputStream
|
* @see XZInputStream
|
||||||
*/
|
*/
|
||||||
@@ -52,29 +52,25 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
private final byte[] tempBuf = new byte[1];
|
private final byte[] tempBuf = new byte[1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XZ decompressor that decompresses exactly one
|
* Creates a new XZ decompressor that decompresses exactly one XZ Stream
|
||||||
* XZ Stream from <code>in</code> without a memory usage limit.
|
* from <code>in</code> without a memory usage limit.
|
||||||
* <p>
|
* <p>
|
||||||
* This constructor reads and parses the XZ Stream Header (12 bytes)
|
* This constructor reads and parses the XZ Stream Header (12 bytes) from
|
||||||
* from <code>in</code>. The header of the first Block is not read
|
* <code>in</code>. The header of the first Block is not read until
|
||||||
* until <code>read</code> is called.
|
* <code>read</code> is called.
|
||||||
*
|
*
|
||||||
* @param in input stream from which XZ-compressed
|
* @param in input stream from which XZ-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @throws XZFormatException
|
* @throws XZFormatException input is not in the XZ format
|
||||||
* input is not in the XZ format
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||||
* XZ header CRC32 doesn't match
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||||
* XZ header is valid but specifies options
|
* options not supported by this implementation
|
||||||
* not supported by this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException less than 12 bytes of input was
|
||||||
* less than 12 bytes of input was available
|
* available from
|
||||||
* from <code>in</code>
|
* <code>in</code>
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -83,37 +79,32 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XZ decompressor that decompresses exactly one
|
* Creates a new XZ decompressor that decompresses exactly one XZ Stream
|
||||||
* XZ Stream from <code>in</code> with an optional memory usage limit.
|
* from <code>in</code> with an optional memory usage limit.
|
||||||
* <p>
|
* <p>
|
||||||
* This is identical to <code>SingleXZInputStream(InputStream)</code>
|
* This is identical to <code>SingleXZInputStream(InputStream)</code> except
|
||||||
* except that this takes also the <code>memoryLimit</code> argument.
|
* that this takes also the <code>memoryLimit</code> argument.
|
||||||
*
|
*
|
||||||
* @param in input stream from which XZ-compressed
|
* @param in input stream from which XZ-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||||
* or <code>-1</code> to impose no
|
* <code>-1</code> to impose no memory usage limit
|
||||||
* memory usage limit
|
|
||||||
*
|
*
|
||||||
* @throws XZFormatException
|
* @throws XZFormatException input is not in the XZ format
|
||||||
* input is not in the XZ format
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||||
* XZ header CRC32 doesn't match
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||||
* XZ header is valid but specifies options
|
* options not supported by this implementation
|
||||||
* not supported by this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException less than 12 bytes of input was
|
||||||
* less than 12 bytes of input was available
|
* available from
|
||||||
* from <code>in</code>
|
* <code>in</code>
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
public SingleXZInputStream(InputStream in, int memoryLimit)
|
public SingleXZInputStream(InputStream in, int memoryLimit)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
initialize(in, memoryLimit);
|
initialize(in, memoryLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +114,7 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initialize(InputStream in, int memoryLimit)
|
private void initialize(InputStream in, int memoryLimit)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
byte[] streamHeader = new byte[DecoderUtil.STREAM_HEADER_SIZE];
|
byte[] streamHeader = new byte[DecoderUtil.STREAM_HEADER_SIZE];
|
||||||
new DataInputStream(in).readFully(streamHeader);
|
new DataInputStream(in).readFully(streamHeader);
|
||||||
initialize(in, memoryLimit, streamHeader);
|
initialize(in, memoryLimit, streamHeader);
|
||||||
@@ -158,12 +149,12 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses the next byte from this input stream.
|
* Decompresses the next byte from this input stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Reading lots of data with <code>read()</code> from this input stream
|
* Reading lots of data with <code>read()</code> from this input stream may
|
||||||
* may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
|
* be inefficient. Wrap it in {@link java.io.BufferedInputStream} if you
|
||||||
* if you need to read lots of data one byte at a time.
|
* need to read lots of data one byte at a time.
|
||||||
*
|
*
|
||||||
* @return the next decompressed byte, or <code>-1</code>
|
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||||
* to indicate the end of the compressed stream
|
* end of the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException
|
||||||
@@ -171,8 +162,8 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or
|
||||||
* compressed input is truncated or corrupt
|
* corrupt
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -183,16 +174,16 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses into an array of bytes.
|
* Decompresses into an array of bytes.
|
||||||
* <p>
|
* <p>
|
||||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||||
* is returned. Otherwise this will try to decompress <code>len</code>
|
* returned. Otherwise this will try to decompress <code>len</code> bytes of
|
||||||
* bytes of uncompressed data. Less than <code>len</code> bytes may
|
* uncompressed data. Less than <code>len</code> bytes may be read only in
|
||||||
* be read only in the following situations:
|
* the following situations:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The end of the compressed data was reached successfully.</li>
|
* <li>The end of the compressed data was reached successfully.</li>
|
||||||
* <li>An error is detected after at least one but less <code>len</code>
|
* <li>An error is detected after at least one but less <code>len</code>
|
||||||
* bytes have already been successfully decompressed.
|
* bytes have already been successfully decompressed. The next call with
|
||||||
* The next call with non-zero <code>len</code> will immediately
|
* non-zero <code>len</code> will immediately throw the pending
|
||||||
* throw the pending exception.</li>
|
* exception.</li>
|
||||||
* <li>An exception is thrown.</li>
|
* <li>An exception is thrown.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@@ -200,8 +191,8 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len maximum number of uncompressed bytes to read
|
* @param len maximum number of uncompressed bytes to read
|
||||||
*
|
*
|
||||||
* @return number of bytes read, or <code>-1</code> to indicate
|
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||||
* the end of the compressed stream
|
* the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException
|
||||||
@@ -209,8 +200,8 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or
|
||||||
* compressed input is truncated or corrupt
|
* corrupt
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -237,7 +228,7 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
if (blockDecoder == null)
|
if (blockDecoder == null)
|
||||||
try {
|
try {
|
||||||
blockDecoder = new BlockInputStream(
|
blockDecoder = new BlockInputStream(
|
||||||
in, check, memoryLimit, -1, -1);
|
in, check, memoryLimit, -1, -1);
|
||||||
} catch (IndexIndicatorException e) {
|
} catch (IndexIndicatorException e) {
|
||||||
indexHash.validate(in);
|
indexHash.validate(in);
|
||||||
validateStreamFooter();
|
validateStreamFooter();
|
||||||
@@ -275,19 +266,18 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
streamFooterFlags)
|
streamFooterFlags)
|
||||||
|| indexHash.getIndexSize() != streamFooterFlags.backwardSize)
|
|| indexHash.getIndexSize() != streamFooterFlags.backwardSize)
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"XZ Stream Footer does not match Stream Header");
|
"XZ Stream Footer does not match Stream Header");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of uncompressed bytes that can be read
|
* Returns the number of uncompressed bytes that can be read without
|
||||||
* without blocking. The value is returned with an assumption
|
* blocking. The value is returned with an assumption that the compressed
|
||||||
* that the compressed input data will be valid. If the compressed
|
* input data will be valid. If the compressed data is corrupt,
|
||||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||||
* thrown before the number of bytes claimed to be available have
|
* bytes claimed to be available have been read from this input stream.
|
||||||
* been read from this input stream.
|
|
||||||
*
|
*
|
||||||
* @return the number of uncompressed bytes that can be read
|
* @return the number of uncompressed bytes that can be read without
|
||||||
* without blocking
|
* blocking
|
||||||
*/
|
*/
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
if (in == null)
|
if (in == null)
|
||||||
@@ -300,8 +290,8 @@ public class SingleXZInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream and calls <code>in.close()</code>.
|
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||||
* If the stream was already closed, this does nothing.
|
* already closed, this does nothing.
|
||||||
*
|
*
|
||||||
* @throws IOException if thrown by <code>in.close()</code>
|
* @throws IOException if thrown by <code>in.close()</code>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,23 +9,23 @@
|
|||||||
package org.tukaani.xz;
|
package org.tukaani.xz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when compression options not supported by this implementation
|
* Thrown when compression options not supported by this implementation are
|
||||||
* are detected. Some other implementation might support those options.
|
* detected. Some other implementation might support those options.
|
||||||
*/
|
*/
|
||||||
public class UnsupportedOptionsException extends XZIOException {
|
public class UnsupportedOptionsException extends XZIOException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 3L;
|
private static final long serialVersionUID = 3L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new UnsupportedOptionsException with null
|
* Creates a new UnsupportedOptionsException with null as its error detail
|
||||||
* as its error detail message.
|
* message.
|
||||||
*/
|
*/
|
||||||
public UnsupportedOptionsException() {
|
public UnsupportedOptionsException() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new UnsupportedOptionsException with the given
|
* Creates a new UnsupportedOptionsException with the given error detail
|
||||||
* error detail message.
|
* message.
|
||||||
*
|
*
|
||||||
* @param s error detail message
|
* @param s error detail message
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,23 +14,23 @@ package org.tukaani.xz;
|
|||||||
public class XZ {
|
public class XZ {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XZ Header Magic Bytes begin a XZ file.
|
* XZ Header Magic Bytes begin a XZ file. This can be useful to detect XZ
|
||||||
* This can be useful to detect XZ compressed data.
|
* compressed data.
|
||||||
*/
|
*/
|
||||||
public static final byte[] HEADER_MAGIC = {
|
public static final byte[] HEADER_MAGIC = {
|
||||||
(byte) 0xFD, '7', 'z', 'X', 'Z', '\0'};
|
(byte) 0xFD, '7', 'z', 'X', 'Z', '\0' };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XZ Footer Magic Bytes are the last bytes of a XZ Stream.
|
* XZ Footer Magic Bytes are the last bytes of a XZ Stream.
|
||||||
*/
|
*/
|
||||||
public static final byte[] FOOTER_MAGIC = {'Y', 'Z'};
|
public static final byte[] FOOTER_MAGIC = { 'Y', 'Z' };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integrity check ID indicating that no integrity check is calculated.
|
* Integrity check ID indicating that no integrity check is calculated.
|
||||||
* <p>
|
* <p>
|
||||||
* Omitting the integrity check is strongly discouraged except when
|
* Omitting the integrity check is strongly discouraged except when the
|
||||||
* the integrity of the data will be verified by other means anyway,
|
* integrity of the data will be verified by other means anyway, and
|
||||||
* and calculating the check twice would be useless.
|
* calculating the check twice would be useless.
|
||||||
*/
|
*/
|
||||||
public static final int CHECK_NONE = 0;
|
public static final int CHECK_NONE = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,8 @@
|
|||||||
package org.tukaani.xz;
|
package org.tukaani.xz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic {@link java.io.IOException IOException} specific to this package.
|
* Generic {@link java.io.IOException IOException} specific to this package. The
|
||||||
* The other IOExceptions in this package extend
|
* other IOExceptions in this package extend from <code>XZIOException</code>.
|
||||||
* from <code>XZIOException</code>.
|
|
||||||
*/
|
*/
|
||||||
public class XZIOException extends java.io.IOException {
|
public class XZIOException extends java.io.IOException {
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import org.tukaani.xz.common.DecoderUtil;
|
|||||||
/**
|
/**
|
||||||
* Decompresses a .xz file in streamed mode (no seeking).
|
* Decompresses a .xz file in streamed mode (no seeking).
|
||||||
* <p>
|
* <p>
|
||||||
* Use this to decompress regular standalone .xz files. This reads from
|
* Use this to decompress regular standalone .xz files. This reads from its
|
||||||
* its input stream until the end of the input or until an error occurs.
|
* input stream until the end of the input or until an error occurs. This
|
||||||
* This supports decompressing concatenated .xz files.
|
* supports decompressing concatenated .xz files.
|
||||||
*
|
*
|
||||||
* <h4>Typical use cases</h4>
|
* <h4>Typical use cases</h4>
|
||||||
* <p>
|
* <p>
|
||||||
@@ -30,18 +30,18 @@ import org.tukaani.xz.common.DecoderUtil;
|
|||||||
* XZInputStream inxz = new XZInputStream(infile);
|
* XZInputStream inxz = new XZInputStream(infile);
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* <p>
|
* <p>
|
||||||
* It's important to keep in mind that decompressor memory usage depends
|
* It's important to keep in mind that decompressor memory usage depends on the
|
||||||
* on the settings used to compress the file. The worst-case memory usage
|
* settings used to compress the file. The worst-case memory usage of
|
||||||
* of XZInputStream is currently 1.5 GiB. Still, very few files will
|
* XZInputStream is currently 1.5 GiB. Still, very few files will require
|
||||||
* require more than about 65 MiB because that's how much decompressing
|
* more than about 65 MiB because that's how much decompressing a file
|
||||||
* a file created with the highest preset level will need, and only a few
|
* created with the highest preset level will need, and only a few people use
|
||||||
* people use settings other than the predefined presets.
|
* settings other than the predefined presets.
|
||||||
* <p>
|
* <p>
|
||||||
* It is possible to specify a memory usage limit for
|
* It is possible to specify a memory usage limit for
|
||||||
* <code>XZInputStream</code>. If decompression requires more memory than
|
* <code>XZInputStream</code>. If decompression requires more memory than the
|
||||||
* the specified limit, MemoryLimitException will be thrown when reading
|
* specified limit, MemoryLimitException will be thrown when reading from the
|
||||||
* from the stream. For example, the following sets the memory usage limit
|
* stream. For example, the following sets the memory usage limit to
|
||||||
* to 100 MiB:
|
* 100 MiB:
|
||||||
* <p>
|
* <p>
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* InputStream infile = new FileInputStream("foo.xz");
|
* InputStream infile = new FileInputStream("foo.xz");
|
||||||
@@ -50,13 +50,12 @@ import org.tukaani.xz.common.DecoderUtil;
|
|||||||
*
|
*
|
||||||
* <h4>When uncompressed size is known beforehand</h4>
|
* <h4>When uncompressed size is known beforehand</h4>
|
||||||
* <p>
|
* <p>
|
||||||
* If you are decompressing complete files and your application knows
|
* If you are decompressing complete files and your application knows exactly
|
||||||
* exactly how much uncompressed data there should be, it is good to try
|
* how much uncompressed data there should be, it is good to try reading one
|
||||||
* reading one more byte by calling <code>read()</code> and checking
|
* more byte by calling <code>read()</code> and checking that it returns
|
||||||
* that it returns <code>-1</code>. This way the decompressor will parse the
|
* <code>-1</code>. This way the decompressor will parse the file footers and
|
||||||
* file footers and verify the integrity checks, giving the caller more
|
* verify the integrity checks, giving the caller more confidence that the
|
||||||
* confidence that the uncompressed data is valid. (This advice seems to
|
* uncompressed data is valid. (This advice seems to apply to
|
||||||
* apply to
|
|
||||||
* {@link java.util.zip.GZIPInputStream java.util.zip.GZIPInputStream} too.)
|
* {@link java.util.zip.GZIPInputStream java.util.zip.GZIPInputStream} too.)
|
||||||
*
|
*
|
||||||
* @see SingleXZInputStream
|
* @see SingleXZInputStream
|
||||||
@@ -74,26 +73,22 @@ public class XZInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Creates a new XZ decompressor without a memory usage limit.
|
* Creates a new XZ decompressor without a memory usage limit.
|
||||||
* <p>
|
* <p>
|
||||||
* This constructor reads and parses the XZ Stream Header (12 bytes)
|
* This constructor reads and parses the XZ Stream Header (12 bytes) from
|
||||||
* from <code>in</code>. The header of the first Block is not read
|
* <code>in</code>. The header of the first Block is not read until
|
||||||
* until <code>read</code> is called.
|
* <code>read</code> is called.
|
||||||
*
|
*
|
||||||
* @param in input stream from which XZ-compressed
|
* @param in input stream from which XZ-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @throws XZFormatException
|
* @throws XZFormatException input is not in the XZ format
|
||||||
* input is not in the XZ format
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||||
* XZ header CRC32 doesn't match
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||||
* XZ header is valid but specifies options
|
* options not supported by this implementation
|
||||||
* not supported by this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException less than 12 bytes of input was
|
||||||
* less than 12 bytes of input was available
|
* available from
|
||||||
* from <code>in</code>
|
* <code>in</code>
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -104,29 +99,24 @@ public class XZInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Creates a new XZ decompressor with an optional memory usage limit.
|
* Creates a new XZ decompressor with an optional memory usage limit.
|
||||||
* <p>
|
* <p>
|
||||||
* This is identical to <code>XZInputStream(InputStream)</code> except
|
* This is identical to <code>XZInputStream(InputStream)</code> except that
|
||||||
* that this takes also the <code>memoryLimit</code> argument.
|
* this takes also the <code>memoryLimit</code> argument.
|
||||||
*
|
*
|
||||||
* @param in input stream from which XZ-compressed
|
* @param in input stream from which XZ-compressed data is read
|
||||||
* data is read
|
|
||||||
*
|
*
|
||||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||||
* or <code>-1</code> to impose no
|
* <code>-1</code> to impose no memory usage limit
|
||||||
* memory usage limit
|
|
||||||
*
|
*
|
||||||
* @throws XZFormatException
|
* @throws XZFormatException input is not in the XZ format
|
||||||
* input is not in the XZ format
|
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||||
* XZ header CRC32 doesn't match
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||||
* XZ header is valid but specifies options
|
* options not supported by this implementation
|
||||||
* not supported by this implementation
|
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException less than 12 bytes of input was
|
||||||
* less than 12 bytes of input was available
|
* available from
|
||||||
* from <code>in</code>
|
* <code>in</code>
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -139,12 +129,12 @@ public class XZInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses the next byte from this input stream.
|
* Decompresses the next byte from this input stream.
|
||||||
* <p>
|
* <p>
|
||||||
* Reading lots of data with <code>read()</code> from this input stream
|
* Reading lots of data with <code>read()</code> from this input stream may
|
||||||
* may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
|
* be inefficient. Wrap it in {@link java.io.BufferedInputStream} if you
|
||||||
* if you need to read lots of data one byte at a time.
|
* need to read lots of data one byte at a time.
|
||||||
*
|
*
|
||||||
* @return the next decompressed byte, or <code>-1</code>
|
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||||
* to indicate the end of the compressed stream
|
* end of the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException
|
||||||
@@ -152,8 +142,8 @@ public class XZInputStream extends InputStream {
|
|||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or
|
||||||
* compressed input is truncated or corrupt
|
* corrupt
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -164,16 +154,16 @@ public class XZInputStream extends InputStream {
|
|||||||
/**
|
/**
|
||||||
* Decompresses into an array of bytes.
|
* Decompresses into an array of bytes.
|
||||||
* <p>
|
* <p>
|
||||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||||
* is returned. Otherwise this will try to decompress <code>len</code>
|
* returned. Otherwise this will try to decompress <code>len</code> bytes of
|
||||||
* bytes of uncompressed data. Less than <code>len</code> bytes may
|
* uncompressed data. Less than <code>len</code> bytes may be read only in
|
||||||
* be read only in the following situations:
|
* the following situations:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The end of the compressed data was reached successfully.</li>
|
* <li>The end of the compressed data was reached successfully.</li>
|
||||||
* <li>An error is detected after at least one but less <code>len</code>
|
* <li>An error is detected after at least one but less <code>len</code>
|
||||||
* bytes have already been successfully decompressed.
|
* bytes have already been successfully decompressed. The next call with
|
||||||
* The next call with non-zero <code>len</code> will immediately
|
* non-zero <code>len</code> will immediately throw the pending
|
||||||
* throw the pending exception.</li>
|
* exception.</li>
|
||||||
* <li>An exception is thrown.</li>
|
* <li>An exception is thrown.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@@ -181,8 +171,8 @@ public class XZInputStream extends InputStream {
|
|||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len maximum number of uncompressed bytes to read
|
* @param len maximum number of uncompressed bytes to read
|
||||||
*
|
*
|
||||||
* @return number of bytes read, or <code>-1</code> to indicate
|
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||||
* the end of the compressed stream
|
* the compressed stream
|
||||||
*
|
*
|
||||||
* @throws CorruptedInputException
|
* @throws CorruptedInputException
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException
|
||||||
@@ -190,8 +180,8 @@ public class XZInputStream extends InputStream {
|
|||||||
*
|
*
|
||||||
* @throws XZIOException if the stream has been closed
|
* @throws XZIOException if the stream has been closed
|
||||||
*
|
*
|
||||||
* @throws EOFException
|
* @throws EOFException compressed input is truncated or
|
||||||
* compressed input is truncated or corrupt
|
* corrupt
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by <code>in</code>
|
* @throws IOException may be thrown by <code>in</code>
|
||||||
*/
|
*/
|
||||||
@@ -271,20 +261,19 @@ public class XZInputStream extends InputStream {
|
|||||||
// Since this isn't the first .xz Stream, it is more
|
// Since this isn't the first .xz Stream, it is more
|
||||||
// logical to tell that the data is corrupt.
|
// logical to tell that the data is corrupt.
|
||||||
throw new CorruptedInputException(
|
throw new CorruptedInputException(
|
||||||
"Garbage after a valid XZ Stream");
|
"Garbage after a valid XZ Stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of uncompressed bytes that can be read
|
* Returns the number of uncompressed bytes that can be read without
|
||||||
* without blocking. The value is returned with an assumption
|
* blocking. The value is returned with an assumption that the compressed
|
||||||
* that the compressed input data will be valid. If the compressed
|
* input data will be valid. If the compressed data is corrupt,
|
||||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||||
* thrown before the number of bytes claimed to be available have
|
* bytes claimed to be available have been read from this input stream.
|
||||||
* been read from this input stream.
|
|
||||||
*
|
*
|
||||||
* @return the number of uncompressed bytes that can be read
|
* @return the number of uncompressed bytes that can be read without
|
||||||
* without blocking
|
* blocking
|
||||||
*/
|
*/
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
if (in == null)
|
if (in == null)
|
||||||
@@ -297,8 +286,8 @@ public class XZInputStream extends InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream and calls <code>in.close()</code>.
|
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||||
* If the stream was already closed, this does nothing.
|
* already closed, this does nothing.
|
||||||
*
|
*
|
||||||
* @throws IOException if thrown by <code>in.close()</code>
|
* @throws IOException if thrown by <code>in.close()</code>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,25 +20,24 @@ import org.tukaani.xz.index.IndexEncoder;
|
|||||||
*
|
*
|
||||||
* <h4>Examples</h4>
|
* <h4>Examples</h4>
|
||||||
* <p>
|
* <p>
|
||||||
* Getting an output stream to compress with LZMA2 using the default
|
* Getting an output stream to compress with LZMA2 using the default settings
|
||||||
* settings and the default integrity check type (CRC64):
|
* and the default integrity check type (CRC64):
|
||||||
* <p>
|
* <p>
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* FileOutputStream outfile = new FileOutputStream("foo.xz");
|
* FileOutputStream outfile = new FileOutputStream("foo.xz");
|
||||||
* XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options());
|
* XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options());
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* <p>
|
* <p>
|
||||||
* Using the preset level <code>8</code> for LZMA2 (the default
|
* Using the preset level <code>8</code> for LZMA2 (the default is
|
||||||
* is <code>6</code>) and SHA-256 instead of CRC64 for integrity checking:
|
* <code>6</code>) and SHA-256 instead of CRC64 for integrity checking:
|
||||||
* <p>
|
* <p>
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options(8),
|
* XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options(8),
|
||||||
* XZ.CHECK_SHA256);
|
* XZ.CHECK_SHA256);
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* <p>
|
* <p>
|
||||||
* Using the x86 BCJ filter together with LZMA2 to compress x86 executables
|
* Using the x86 BCJ filter together with LZMA2 to compress x86 executables and
|
||||||
* and printing the memory usage information before creating the
|
* printing the memory usage information before creating the XZOutputStream:
|
||||||
* XZOutputStream:
|
|
||||||
* <p>
|
* <p>
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* X86Options x86 = new X86Options();
|
* X86Options x86 = new X86Options();
|
||||||
@@ -64,9 +63,9 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
private FilterEncoder[] filters;
|
private FilterEncoder[] filters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the current filter chain supports flushing.
|
* True if the current filter chain supports flushing. If it doesn't support
|
||||||
* If it doesn't support flushing, <code>flush()</code>
|
* flushing, <code>flush()</code> will use <code>endBlock()</code> as a
|
||||||
* will use <code>endBlock()</code> as a fallback.
|
* fallback.
|
||||||
*/
|
*/
|
||||||
private boolean filtersSupportFlushing;
|
private boolean filtersSupportFlushing;
|
||||||
|
|
||||||
@@ -76,88 +75,80 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
private final byte[] tempBuf = new byte[1];
|
private final byte[] tempBuf = new byte[1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XZ compressor using one filter and CRC64 as
|
* Creates a new XZ compressor using one filter and CRC64 as the integrity
|
||||||
* the integrity check. This constructor is equivalent to passing
|
* check. This constructor is equivalent to passing a single-member
|
||||||
* a single-member FilterOptions array to
|
* FilterOptions array to
|
||||||
* <code>XZOutputStream(OutputStream, FilterOptions[])</code>.
|
* <code>XZOutputStream(OutputStream, FilterOptions[])</code>.
|
||||||
*
|
*
|
||||||
* @param out output stream to which the compressed data
|
* @param out output stream to which the compressed data will be
|
||||||
* will be written
|
* written
|
||||||
*
|
*
|
||||||
* @param filterOptions
|
* @param filterOptions filter options to use
|
||||||
* filter options to use
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException invalid filter chain
|
||||||
* invalid filter chain
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown from <code>out</code>
|
* @throws IOException may be thrown from <code>out</code>
|
||||||
*/
|
*/
|
||||||
public XZOutputStream(OutputStream out, FilterOptions filterOptions)
|
public XZOutputStream(OutputStream out, FilterOptions filterOptions)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this(out, filterOptions, XZ.CHECK_CRC64);
|
this(out, filterOptions, XZ.CHECK_CRC64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XZ compressor using one filter and the specified
|
* Creates a new XZ compressor using one filter and the specified integrity
|
||||||
* integrity check type. This constructor is equivalent to
|
* check type. This constructor is equivalent to passing a single-member
|
||||||
* passing a single-member FilterOptions array to
|
* FilterOptions array to
|
||||||
* <code>XZOutputStream(OutputStream, FilterOptions[], int)</code>.
|
* <code>XZOutputStream(OutputStream, FilterOptions[], int)</code>.
|
||||||
*
|
*
|
||||||
* @param out output stream to which the compressed data
|
* @param out output stream to which the compressed data will be
|
||||||
* will be written
|
* written
|
||||||
*
|
*
|
||||||
* @param filterOptions
|
* @param filterOptions filter options to use
|
||||||
* filter options to use
|
|
||||||
*
|
*
|
||||||
* @param checkType type of the integrity check,
|
* @param checkType type of the integrity check, for example
|
||||||
* for example XZ.CHECK_CRC32
|
* XZ.CHECK_CRC32
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException invalid filter chain
|
||||||
* invalid filter chain
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown from <code>out</code>
|
* @throws IOException may be thrown from <code>out</code>
|
||||||
*/
|
*/
|
||||||
public XZOutputStream(OutputStream out, FilterOptions filterOptions,
|
public XZOutputStream(OutputStream out, FilterOptions filterOptions,
|
||||||
int checkType) throws IOException {
|
int checkType) throws IOException {
|
||||||
this(out, new FilterOptions[] {filterOptions}, checkType);
|
this(out, new FilterOptions[] { filterOptions }, checkType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XZ compressor using 1-4 filters and CRC64 as
|
* Creates a new XZ compressor using 1-4 filters and CRC64 as the integrity
|
||||||
* the integrity check. This constructor is equivalent
|
* check. This constructor is equivalent
|
||||||
* <code>XZOutputStream(out, filterOptions, XZ.CHECK_CRC64)</code>.
|
* <code>XZOutputStream(out, filterOptions, XZ.CHECK_CRC64)</code>.
|
||||||
*
|
*
|
||||||
* @param out output stream to which the compressed data
|
* @param out output stream to which the compressed data will be
|
||||||
* will be written
|
* written
|
||||||
*
|
*
|
||||||
* @param filterOptions
|
* @param filterOptions array of filter options to use
|
||||||
* array of filter options to use
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException invalid filter chain
|
||||||
* invalid filter chain
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown from <code>out</code>
|
* @throws IOException may be thrown from <code>out</code>
|
||||||
*/
|
*/
|
||||||
public XZOutputStream(OutputStream out, FilterOptions[] filterOptions)
|
public XZOutputStream(OutputStream out, FilterOptions[] filterOptions)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this(out, filterOptions, XZ.CHECK_CRC64);
|
this(out, filterOptions, XZ.CHECK_CRC64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XZ compressor using 1-4 filters and the specified
|
* Creates a new XZ compressor using 1-4 filters and the specified integrity
|
||||||
* integrity check type.
|
* check type.
|
||||||
*
|
*
|
||||||
* @param out output stream to which the compressed data
|
* @param out output stream to which the compressed data will be
|
||||||
* will be written
|
* written
|
||||||
*
|
*
|
||||||
* @param filterOptions
|
* @param filterOptions array of filter options to use
|
||||||
* array of filter options to use
|
|
||||||
*
|
*
|
||||||
* @param checkType type of the integrity check,
|
* @param checkType type of the integrity check, for example
|
||||||
* for example XZ.CHECK_CRC32
|
* XZ.CHECK_CRC32
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException invalid filter chain
|
||||||
* invalid filter chain
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown from <code>out</code>
|
* @throws IOException may be thrown from <code>out</code>
|
||||||
*/
|
*/
|
||||||
@@ -173,19 +164,17 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the filter chain with a single filter.
|
* Updates the filter chain with a single filter. This is equivalent to
|
||||||
* This is equivalent to passing a single-member FilterOptions array
|
* passing a single-member FilterOptions array to
|
||||||
* to <code>updateFilters(FilterOptions[])</code>.
|
* <code>updateFilters(FilterOptions[])</code>.
|
||||||
*
|
*
|
||||||
* @param filterOptions
|
* @param filterOptions new filter to use
|
||||||
* new filter to use
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException unsupported filter chain, or trying
|
||||||
* unsupported filter chain, or trying to change
|
* to change the filter chain in the middle of a Block
|
||||||
* the filter chain in the middle of a Block
|
|
||||||
*/
|
*/
|
||||||
public void updateFilters(FilterOptions filterOptions)
|
public void updateFilters(FilterOptions filterOptions)
|
||||||
throws XZIOException {
|
throws XZIOException {
|
||||||
FilterOptions[] opts = new FilterOptions[1];
|
FilterOptions[] opts = new FilterOptions[1];
|
||||||
opts[0] = filterOptions;
|
opts[0] = filterOptions;
|
||||||
updateFilters(opts);
|
updateFilters(opts);
|
||||||
@@ -194,27 +183,25 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
/**
|
/**
|
||||||
* Updates the filter chain with 1-4 filters.
|
* Updates the filter chain with 1-4 filters.
|
||||||
* <p>
|
* <p>
|
||||||
* Currently this cannot be used to update e.g. LZMA2 options in the
|
* Currently this cannot be used to update e.g. LZMA2 options in the middle
|
||||||
* middle of a XZ Block. Use <code>endBlock()</code> to finish the
|
* of a XZ Block. Use <code>endBlock()</code> to finish the current XZ Block
|
||||||
* current XZ Block before calling this function. The new filter chain
|
* before calling this function. The new filter chain will then be used for
|
||||||
* will then be used for the next XZ Block.
|
* the next XZ Block.
|
||||||
*
|
*
|
||||||
* @param filterOptions
|
* @param filterOptions new filter chain to use
|
||||||
* new filter chain to use
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOptionsException
|
* @throws UnsupportedOptionsException unsupported filter chain, or trying
|
||||||
* unsupported filter chain, or trying to change
|
* to change the filter chain in the middle of a Block
|
||||||
* the filter chain in the middle of a Block
|
|
||||||
*/
|
*/
|
||||||
public void updateFilters(FilterOptions[] filterOptions)
|
public void updateFilters(FilterOptions[] filterOptions)
|
||||||
throws XZIOException {
|
throws XZIOException {
|
||||||
if (blockEncoder != null)
|
if (blockEncoder != null)
|
||||||
throw new UnsupportedOptionsException("Changing filter options "
|
throw new UnsupportedOptionsException("Changing filter options "
|
||||||
+ "in the middle of a XZ Block not implemented");
|
+ "in the middle of a XZ Block not implemented");
|
||||||
|
|
||||||
if (filterOptions.length < 1 || filterOptions.length > 4)
|
if (filterOptions.length < 1 || filterOptions.length > 4)
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"XZ filter chain must be 1-4 filters");
|
"XZ filter chain must be 1-4 filters");
|
||||||
|
|
||||||
filtersSupportFlushing = true;
|
filtersSupportFlushing = true;
|
||||||
FilterEncoder[] newFilters = new FilterEncoder[filterOptions.length];
|
FilterEncoder[] newFilters = new FilterEncoder[filterOptions.length];
|
||||||
@@ -230,12 +217,10 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
/**
|
/**
|
||||||
* Writes one byte to be compressed.
|
* Writes one byte to be compressed.
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException XZ Stream has grown too big
|
||||||
* XZ Stream has grown too big
|
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException <code>finish()</code> or <code>close()</code> was
|
||||||
* <code>finish()</code> or <code>close()</code>
|
* already called
|
||||||
* was already called
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by the underlying output stream
|
* @throws IOException may be thrown by the underlying output stream
|
||||||
*/
|
*/
|
||||||
@@ -245,26 +230,22 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes an array of bytes to be compressed.
|
* Writes an array of bytes to be compressed. The compressors tend to do
|
||||||
* The compressors tend to do internal buffering and thus the written
|
* internal buffering and thus the written data won't be readable from the
|
||||||
* data won't be readable from the compressed output immediately.
|
* compressed output immediately. Use <code>flush()</code> to force
|
||||||
* Use <code>flush()</code> to force everything written so far to
|
* everything written so far to be written to the underlaying output stream,
|
||||||
* be written to the underlaying output stream, but be aware that
|
* but be aware that flushing reduces compression ratio.
|
||||||
* flushing reduces compression ratio.
|
|
||||||
*
|
*
|
||||||
* @param buf buffer of bytes to be written
|
* @param buf buffer of bytes to be written
|
||||||
* @param off start offset in <code>buf</code>
|
* @param off start offset in <code>buf</code>
|
||||||
* @param len number of bytes to write
|
* @param len number of bytes to write
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException XZ Stream has grown too big: total file size about
|
||||||
* XZ Stream has grown too big: total file size
|
* 8 EiB or the Index field exceeds 16 GiB; you shouldn't reach
|
||||||
* about 8 EiB or the Index field exceeds
|
* these sizes in practice
|
||||||
* 16 GiB; you shouldn't reach these sizes
|
|
||||||
* in practice
|
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException <code>finish()</code> or <code>close()</code> was
|
||||||
* <code>finish()</code> or <code>close()</code>
|
* already called and len > 0
|
||||||
* was already called and len > 0
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by the underlying output stream
|
* @throws IOException may be thrown by the underlying output stream
|
||||||
*/
|
*/
|
||||||
@@ -290,27 +271,25 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finishes the current XZ Block (but not the whole XZ Stream).
|
* Finishes the current XZ Block (but not the whole XZ Stream). This doesn't
|
||||||
* This doesn't flush the stream so it's possible that not all data will
|
* flush the stream so it's possible that not all data will be
|
||||||
* be decompressible from the output stream when this function returns.
|
* decompressible from the output stream when this function returns. Call
|
||||||
* Call also <code>flush()</code> if flushing is wanted in addition to
|
* also <code>flush()</code> if flushing is wanted in addition to finishing
|
||||||
* finishing the current XZ Block.
|
* the current XZ Block.
|
||||||
* <p>
|
* <p>
|
||||||
* If there is no unfinished Block open, this function will do nothing.
|
* If there is no unfinished Block open, this function will do nothing. (No
|
||||||
* (No empty XZ Block will be created.)
|
* empty XZ Block will be created.)
|
||||||
* <p>
|
* <p>
|
||||||
* This function can be useful, for example, to create
|
* This function can be useful, for example, to create random-accessible .xz
|
||||||
* random-accessible .xz files.
|
* files.
|
||||||
* <p>
|
* <p>
|
||||||
* Starting a new XZ Block means that the encoder state is reset.
|
* Starting a new XZ Block means that the encoder state is reset. Doing this
|
||||||
* Doing this very often will increase the size of the compressed
|
* very often will increase the size of the compressed file a lot (more than
|
||||||
* file a lot (more than plain <code>flush()</code> would do).
|
* plain <code>flush()</code> would do).
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException XZ Stream has grown too big
|
||||||
* XZ Stream has grown too big
|
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException stream finished or closed
|
||||||
* stream finished or closed
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by the underlying output stream
|
* @throws IOException may be thrown by the underlying output stream
|
||||||
*/
|
*/
|
||||||
@@ -337,24 +316,21 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flushes the encoder and calls <code>out.flush()</code>.
|
* Flushes the encoder and calls <code>out.flush()</code>. All buffered
|
||||||
* All buffered pending data will then be decompressible from
|
* pending data will then be decompressible from the output stream.
|
||||||
* the output stream.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Calling this function very often may increase the compressed
|
* Calling this function very often may increase the compressed file size a
|
||||||
* file size a lot. The filter chain options may affect the size
|
* lot. The filter chain options may affect the size increase too. For
|
||||||
* increase too. For example, with LZMA2 the HC4 match finder has
|
* example, with LZMA2 the HC4 match finder has smaller penalty with
|
||||||
* smaller penalty with flushing than BT4.
|
* flushing than BT4.
|
||||||
* <p>
|
* <p>
|
||||||
* Some filters don't support flushing. If the filter chain has
|
* Some filters don't support flushing. If the filter chain has such a
|
||||||
* such a filter, <code>flush()</code> will call <code>endBlock()</code>
|
* filter, <code>flush()</code> will call <code>endBlock()</code> before
|
||||||
* before flushing.
|
* flushing.
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException XZ Stream has grown too big
|
||||||
* XZ Stream has grown too big
|
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException stream finished or closed
|
||||||
* stream finished or closed
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by the underlying output stream
|
* @throws IOException may be thrown by the underlying output stream
|
||||||
*/
|
*/
|
||||||
@@ -384,20 +360,19 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finishes compression without closing the underlying stream.
|
* Finishes compression without closing the underlying stream. No more data
|
||||||
* No more data can be written to this stream after finishing
|
* can be written to this stream after finishing (calling <code>write</code>
|
||||||
* (calling <code>write</code> with an empty buffer is OK).
|
* with an empty buffer is OK).
|
||||||
* <p>
|
* <p>
|
||||||
* Repeated calls to <code>finish()</code> do nothing unless
|
* Repeated calls to <code>finish()</code> do nothing unless an exception
|
||||||
* an exception was thrown by this stream earlier. In that case
|
* was thrown by this stream earlier. In that case the same exception is
|
||||||
* the same exception is thrown again.
|
* thrown again.
|
||||||
* <p>
|
* <p>
|
||||||
* After finishing, the stream may be closed normally with
|
* After finishing, the stream may be closed normally with
|
||||||
* <code>close()</code>. If the stream will be closed anyway, there
|
* <code>close()</code>. If the stream will be closed anyway, there usually
|
||||||
* usually is no need to call <code>finish()</code> separately.
|
* is no need to call <code>finish()</code> separately.
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException XZ Stream has grown too big
|
||||||
* XZ Stream has grown too big
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by the underlying output stream
|
* @throws IOException may be thrown by the underlying output stream
|
||||||
*/
|
*/
|
||||||
@@ -423,14 +398,13 @@ public class XZOutputStream extends FinishableOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finishes compression and closes the underlying stream.
|
* Finishes compression and closes the underlying stream. The underlying
|
||||||
* The underlying stream <code>out</code> is closed even if finishing
|
* stream <code>out</code> is closed even if finishing fails. If both
|
||||||
* fails. If both finishing and closing fail, the exception thrown
|
* finishing and closing fail, the exception thrown by <code>finish()</code>
|
||||||
* by <code>finish()</code> is thrown and the exception from the failed
|
* is thrown and the exception from the failed <code>out.close()</code> is
|
||||||
* <code>out.close()</code> is lost.
|
* lost.
|
||||||
*
|
*
|
||||||
* @throws XZIOException
|
* @throws XZIOException XZ Stream has grown too big
|
||||||
* XZ Stream has grown too big
|
|
||||||
*
|
*
|
||||||
* @throws IOException may be thrown by the underlying output stream
|
* @throws IOException may be thrown by the underlying output stream
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ public class CRC32 extends Check {
|
|||||||
|
|
||||||
public byte[] finish() {
|
public byte[] finish() {
|
||||||
long value = state.getValue();
|
long value = state.getValue();
|
||||||
byte[] buf = {(byte) (value),
|
byte[] buf = { (byte) (value),
|
||||||
(byte) (value >>> 8),
|
(byte) (value >>> 8),
|
||||||
(byte) (value >>> 16),
|
(byte) (value >>> 16),
|
||||||
(byte) (value >>> 24)};
|
(byte) (value >>> 24) };
|
||||||
state.reset();
|
state.reset();
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,27 +33,27 @@ public abstract class Check {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Check getInstance(int checkType)
|
public static Check getInstance(int checkType)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
switch (checkType) {
|
switch (checkType) {
|
||||||
case XZ.CHECK_NONE:
|
case XZ.CHECK_NONE:
|
||||||
return new None();
|
return new None();
|
||||||
|
|
||||||
case XZ.CHECK_CRC32:
|
case XZ.CHECK_CRC32:
|
||||||
return new CRC32();
|
return new CRC32();
|
||||||
|
|
||||||
case XZ.CHECK_CRC64:
|
case XZ.CHECK_CRC64:
|
||||||
return new CRC64();
|
return new CRC64();
|
||||||
|
|
||||||
case XZ.CHECK_SHA256:
|
case XZ.CHECK_SHA256:
|
||||||
try {
|
try {
|
||||||
return new SHA256();
|
return new SHA256();
|
||||||
} catch (java.security.NoSuchAlgorithmException e) {
|
} catch (java.security.NoSuchAlgorithmException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported Check ID " + checkType);
|
"Unsupported Check ID " + checkType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class DecoderUtil extends Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static StreamFlags decodeStreamHeader(byte[] buf)
|
public static StreamFlags decodeStreamHeader(byte[] buf)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
for (int i = 0; i < XZ.HEADER_MAGIC.length; ++i)
|
for (int i = 0; i < XZ.HEADER_MAGIC.length; ++i)
|
||||||
if (buf[i] != XZ.HEADER_MAGIC[i])
|
if (buf[i] != XZ.HEADER_MAGIC[i])
|
||||||
throw new XZFormatException();
|
throw new XZFormatException();
|
||||||
@@ -46,12 +46,12 @@ public class DecoderUtil extends Util {
|
|||||||
return decodeStreamFlags(buf, XZ.HEADER_MAGIC.length);
|
return decodeStreamFlags(buf, XZ.HEADER_MAGIC.length);
|
||||||
} catch (UnsupportedOptionsException e) {
|
} catch (UnsupportedOptionsException e) {
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported options in XZ Stream Header");
|
"Unsupported options in XZ Stream Header");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StreamFlags decodeStreamFooter(byte[] buf)
|
public static StreamFlags decodeStreamFooter(byte[] buf)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (buf[10] != XZ.FOOTER_MAGIC[0] || buf[11] != XZ.FOOTER_MAGIC[1])
|
if (buf[10] != XZ.FOOTER_MAGIC[0] || buf[11] != XZ.FOOTER_MAGIC[1])
|
||||||
// NOTE: The exception could be XZFormatException too.
|
// NOTE: The exception could be XZFormatException too.
|
||||||
// It depends on the situation which one is better.
|
// It depends on the situation which one is better.
|
||||||
@@ -65,7 +65,7 @@ public class DecoderUtil extends Util {
|
|||||||
streamFlags = decodeStreamFlags(buf, 8);
|
streamFlags = decodeStreamFlags(buf, 8);
|
||||||
} catch (UnsupportedOptionsException e) {
|
} catch (UnsupportedOptionsException e) {
|
||||||
throw new UnsupportedOptionsException(
|
throw new UnsupportedOptionsException(
|
||||||
"Unsupported options in XZ Stream Footer");
|
"Unsupported options in XZ Stream Footer");
|
||||||
}
|
}
|
||||||
|
|
||||||
streamFlags.backwardSize = 0;
|
streamFlags.backwardSize = 0;
|
||||||
@@ -78,7 +78,7 @@ public class DecoderUtil extends Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static StreamFlags decodeStreamFlags(byte[] buf, int off)
|
private static StreamFlags decodeStreamFlags(byte[] buf, int off)
|
||||||
throws UnsupportedOptionsException {
|
throws UnsupportedOptionsException {
|
||||||
if (buf[off] != 0x00 || (buf[off + 1] & 0xFF) >= 0x10)
|
if (buf[off] != 0x00 || (buf[off + 1] & 0xFF) >= 0x10)
|
||||||
throw new UnsupportedOptionsException();
|
throw new UnsupportedOptionsException();
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import java.util.zip.CRC32;
|
|||||||
public class EncoderUtil extends Util {
|
public class EncoderUtil extends Util {
|
||||||
|
|
||||||
public static void writeCRC32(OutputStream out, byte[] buf)
|
public static void writeCRC32(OutputStream out, byte[] buf)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
CRC32 crc32 = new CRC32();
|
CRC32 crc32 = new CRC32();
|
||||||
crc32.update(buf);
|
crc32.update(buf);
|
||||||
long value = crc32.getValue();
|
long value = crc32.getValue();
|
||||||
@@ -25,7 +25,7 @@ public class EncoderUtil extends Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void encodeVLI(OutputStream out, long num)
|
public static void encodeVLI(OutputStream out, long num)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
while (num >= 0x80) {
|
while (num >= 0x80) {
|
||||||
out.write((byte) (num | 0x80));
|
out.write((byte) (num | 0x80));
|
||||||
num >>>= 7;
|
num >>>= 7;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class IndexDecoder extends IndexBase {
|
|||||||
|
|
||||||
public IndexDecoder(SeekableInputStream in, StreamFlags streamFooterFlags,
|
public IndexDecoder(SeekableInputStream in, StreamFlags streamFooterFlags,
|
||||||
long streamPadding, int memoryLimit)
|
long streamPadding, int memoryLimit)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
super(new CorruptedInputException("XZ Index is corrupt"));
|
super(new CorruptedInputException("XZ Index is corrupt"));
|
||||||
this.streamFlags = streamFooterFlags;
|
this.streamFlags = streamFooterFlags;
|
||||||
this.streamPadding = streamPadding;
|
this.streamPadding = streamPadding;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class IndexEncoder extends IndexBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void add(long unpaddedSize, long uncompressedSize)
|
public void add(long unpaddedSize, long uncompressedSize)
|
||||||
throws XZIOException {
|
throws XZIOException {
|
||||||
super.add(unpaddedSize, uncompressedSize);
|
super.add(unpaddedSize, uncompressedSize);
|
||||||
records.add(new IndexRecord(unpaddedSize, uncompressedSize));
|
records.add(new IndexRecord(unpaddedSize, uncompressedSize));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class IndexHash extends IndexBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void add(long unpaddedSize, long uncompressedSize)
|
public void add(long unpaddedSize, long uncompressedSize)
|
||||||
throws XZIOException {
|
throws XZIOException {
|
||||||
super.add(unpaddedSize, uncompressedSize);
|
super.add(unpaddedSize, uncompressedSize);
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(2 * 8);
|
ByteBuffer buf = ByteBuffer.allocate(2 * 8);
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ final class HC4 extends LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new LZEncoder with the HC4 match finder.
|
* Creates a new LZEncoder with the HC4 match finder. See
|
||||||
* See <code>LZEncoder.getInstance</code> for parameter descriptions.
|
* <code>LZEncoder.getInstance</code> for parameter descriptions.
|
||||||
*/
|
*/
|
||||||
HC4(int dictSize, int beforeSizeMin, int readAheadMax,
|
HC4(int dictSize, int beforeSizeMin, int readAheadMax,
|
||||||
int niceLen, int matchLenMax, int depthLimit) {
|
int niceLen, int matchLenMax, int depthLimit) {
|
||||||
@@ -54,8 +54,8 @@ final class HC4 extends LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves to the next byte, checks that there is enough available space,
|
* Moves to the next byte, checks that there is enough available space, and
|
||||||
* and possibly normalizes the hash tables and the hash chain.
|
* possibly normalizes the hash tables and the hash chain.
|
||||||
*
|
*
|
||||||
* @return number of bytes available, including the current byte
|
* @return number of bytes available, including the current byte
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public final class LZDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void copyUncompressed(DataInputStream inData, int len)
|
public void copyUncompressed(DataInputStream inData, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int copySize = Math.min(buf.length - pos, len);
|
int copySize = Math.min(buf.length - pos, len);
|
||||||
inData.readFully(buf, pos, copySize);
|
inData.readFully(buf, pos, copySize);
|
||||||
pos += copySize;
|
pos += copySize;
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ public abstract class LZEncoder {
|
|||||||
public static final int MF_BT4 = 0x14;
|
public static final int MF_BT4 = 0x14;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of bytes to keep available before the current byte
|
* Number of bytes to keep available before the current byte when moving the
|
||||||
* when moving the LZ window.
|
* LZ window.
|
||||||
*/
|
*/
|
||||||
private final int keepSizeBefore;
|
private final int keepSizeBefore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of bytes that must be available, the current byte included,
|
* Number of bytes that must be available, the current byte included, to
|
||||||
* to make hasEnoughData return true. Flushing and finishing are
|
* make hasEnoughData return true. Flushing and finishing are naturally
|
||||||
* naturally exceptions to this since there cannot be any data after
|
* exceptions to this since there cannot be any data after the end of the
|
||||||
* the end of the uncompressed input.
|
* uncompressed input.
|
||||||
*/
|
*/
|
||||||
private final int keepSizeAfter;
|
private final int keepSizeAfter;
|
||||||
|
|
||||||
@@ -54,8 +54,8 @@ public abstract class LZEncoder {
|
|||||||
* Gets the size of the LZ window buffer that needs to be allocated.
|
* Gets the size of the LZ window buffer that needs to be allocated.
|
||||||
*/
|
*/
|
||||||
private static int getBufSize(
|
private static int getBufSize(
|
||||||
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
||||||
int matchLenMax) {
|
int matchLenMax) {
|
||||||
int keepSizeBefore = extraSizeBefore + dictSize;
|
int keepSizeBefore = extraSizeBefore + dictSize;
|
||||||
int keepSizeAfter = extraSizeAfter + matchLenMax;
|
int keepSizeAfter = extraSizeAfter + matchLenMax;
|
||||||
int reserveSize = Math.min(dictSize / 2 + (256 << 10), 512 << 20);
|
int reserveSize = Math.min(dictSize / 2 + (256 << 10), 512 << 20);
|
||||||
@@ -63,27 +63,27 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets approximate memory usage of the LZEncoder base structure and
|
* Gets approximate memory usage of the LZEncoder base structure and the
|
||||||
* the match finder as kibibytes.
|
* match finder as kibibytes.
|
||||||
*/
|
*/
|
||||||
public static int getMemoryUsage(
|
public static int getMemoryUsage(
|
||||||
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
||||||
int matchLenMax, int mf) {
|
int matchLenMax, int mf) {
|
||||||
// Buffer size + a little extra
|
// Buffer size + a little extra
|
||||||
int m = getBufSize(dictSize, extraSizeBefore, extraSizeAfter,
|
int m = getBufSize(dictSize, extraSizeBefore, extraSizeAfter,
|
||||||
matchLenMax) / 1024 + 10;
|
matchLenMax) / 1024 + 10;
|
||||||
|
|
||||||
switch (mf) {
|
switch (mf) {
|
||||||
case MF_HC4:
|
case MF_HC4:
|
||||||
m += HC4.getMemoryUsage(dictSize);
|
m += HC4.getMemoryUsage(dictSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MF_BT4:
|
case MF_BT4:
|
||||||
m += BT4.getMemoryUsage(dictSize);
|
m += BT4.getMemoryUsage(dictSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
@@ -94,17 +94,15 @@ public abstract class LZEncoder {
|
|||||||
* <p>
|
* <p>
|
||||||
* @param dictSize dictionary size
|
* @param dictSize dictionary size
|
||||||
*
|
*
|
||||||
* @param extraSizeBefore
|
* @param extraSizeBefore number of bytes to keep available in the history
|
||||||
* number of bytes to keep available in the
|
* in addition to dictSize
|
||||||
* history in addition to dictSize
|
|
||||||
*
|
*
|
||||||
* @param extraSizeAfter
|
* @param extraSizeAfter number of bytes that must be available after
|
||||||
* number of bytes that must be available
|
* current position + matchLenMax
|
||||||
* after current position + matchLenMax
|
|
||||||
*
|
*
|
||||||
* @param niceLen if a match of at least <code>niceLen</code>
|
* @param niceLen if a match of at least <code>niceLen</code> bytes
|
||||||
* bytes is found, be happy with it and don't
|
* is
|
||||||
* stop looking for longer matches
|
* found, be happy with it and don't stop looking for longer matches
|
||||||
*
|
*
|
||||||
* @param matchLenMax don't test for matches longer than
|
* @param matchLenMax don't test for matches longer than
|
||||||
* <code>matchLenMax</code> bytes
|
* <code>matchLenMax</code> bytes
|
||||||
@@ -114,16 +112,16 @@ public abstract class LZEncoder {
|
|||||||
* @param depthLimit match finder search depth limit
|
* @param depthLimit match finder search depth limit
|
||||||
*/
|
*/
|
||||||
public static LZEncoder getInstance(
|
public static LZEncoder getInstance(
|
||||||
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
||||||
int niceLen, int matchLenMax, int mf, int depthLimit) {
|
int niceLen, int matchLenMax, int mf, int depthLimit) {
|
||||||
switch (mf) {
|
switch (mf) {
|
||||||
case MF_HC4:
|
case MF_HC4:
|
||||||
return new HC4(dictSize, extraSizeBefore, extraSizeAfter,
|
return new HC4(dictSize, extraSizeBefore, extraSizeAfter,
|
||||||
niceLen, matchLenMax, depthLimit);
|
niceLen, matchLenMax, depthLimit);
|
||||||
|
|
||||||
case MF_BT4:
|
case MF_BT4:
|
||||||
return new BT4(dictSize, extraSizeBefore, extraSizeAfter,
|
return new BT4(dictSize, extraSizeBefore, extraSizeAfter,
|
||||||
niceLen, matchLenMax, depthLimit);
|
niceLen, matchLenMax, depthLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@@ -145,9 +143,9 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a preset dictionary. If a preset dictionary is wanted, this
|
* Sets a preset dictionary. If a preset dictionary is wanted, this function
|
||||||
* function must be called immediately after creating the LZEncoder
|
* must be called immediately after creating the LZEncoder before any data
|
||||||
* before any data has been encoded.
|
* has been encoded.
|
||||||
*/
|
*/
|
||||||
public void setPresetDict(int dictSize, byte[] presetDict) {
|
public void setPresetDict(int dictSize, byte[] presetDict) {
|
||||||
assert !isStarted();
|
assert !isStarted();
|
||||||
@@ -165,8 +163,8 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves data from the end of the buffer to the beginning, discarding
|
* Moves data from the end of the buffer to the beginning, discarding old
|
||||||
* old data and making space for new input.
|
* data and making space for new input.
|
||||||
*/
|
*/
|
||||||
private void moveWindow() {
|
private void moveWindow() {
|
||||||
// Align the move to a multiple of 16 bytes. LZMA2 needs this
|
// Align the move to a multiple of 16 bytes. LZMA2 needs this
|
||||||
@@ -212,8 +210,8 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process pending bytes remaining from preset dictionary initialization
|
* Process pending bytes remaining from preset dictionary initialization or
|
||||||
* or encoder flush operation.
|
* encoder flush operation.
|
||||||
*/
|
*/
|
||||||
private void processPendingBytes() {
|
private void processPendingBytes() {
|
||||||
// After flushing or setting a preset dictionary there will be
|
// After flushing or setting a preset dictionary there will be
|
||||||
@@ -234,16 +232,16 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if at least one byte has already been run through
|
* Returns true if at least one byte has already been run through the match
|
||||||
* the match finder.
|
* finder.
|
||||||
*/
|
*/
|
||||||
public boolean isStarted() {
|
public boolean isStarted() {
|
||||||
return readPos != -1;
|
return readPos != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks that all the input needs to be made available in
|
* Marks that all the input needs to be made available in the encoded
|
||||||
* the encoded output.
|
* output.
|
||||||
*/
|
*/
|
||||||
public void setFlushing() {
|
public void setFlushing() {
|
||||||
readLimit = writePos - 1;
|
readLimit = writePos - 1;
|
||||||
@@ -251,8 +249,8 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks that there is no more input remaining. The read position
|
* Marks that there is no more input remaining. The read position can be
|
||||||
* can be advanced until the end of the data.
|
* advanced until the end of the data.
|
||||||
*/
|
*/
|
||||||
public void setFinishing() {
|
public void setFinishing() {
|
||||||
readLimit = writePos - 1;
|
readLimit = writePos - 1;
|
||||||
@@ -261,15 +259,15 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if there is enough input available to let the caller encode
|
* Tests if there is enough input available to let the caller encode at
|
||||||
* at least one more byte.
|
* least one more byte.
|
||||||
*/
|
*/
|
||||||
public boolean hasEnoughData(int alreadyReadLen) {
|
public boolean hasEnoughData(int alreadyReadLen) {
|
||||||
return readPos - alreadyReadLen < readLimit;
|
return readPos - alreadyReadLen < readLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyUncompressed(OutputStream out, int backward, int len)
|
public void copyUncompressed(OutputStream out, int backward, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
out.write(buf, readPos + 1 - backward, len);
|
out.write(buf, readPos + 1 - backward, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,8 +275,8 @@ public abstract class LZEncoder {
|
|||||||
* Get the number of bytes available, including the current byte.
|
* Get the number of bytes available, including the current byte.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that the result is undefined if <code>getMatches</code> or
|
* Note that the result is undefined if <code>getMatches</code> or
|
||||||
* <code>skip</code> hasn't been called yet and no preset dictionary
|
* <code>skip</code> hasn't been called yet and no preset dictionary is
|
||||||
* is being used.
|
* being used.
|
||||||
*/
|
*/
|
||||||
public int getAvail() {
|
public int getAvail() {
|
||||||
assert isStarted();
|
assert isStarted();
|
||||||
@@ -296,9 +294,8 @@ public abstract class LZEncoder {
|
|||||||
/**
|
/**
|
||||||
* Gets the byte from the given backward offset.
|
* Gets the byte from the given backward offset.
|
||||||
* <p>
|
* <p>
|
||||||
* The current byte is at <code>0</code>, the previous byte
|
* The current byte is at <code>0</code>, the previous byte at
|
||||||
* at <code>1</code> etc. To get a byte at zero-based distance,
|
* <code>1</code> etc. To get a byte at zero-based distance, use <code>getByte(dist + 1)<code>.
|
||||||
* use <code>getByte(dist + 1)<code>.
|
|
||||||
* <p>
|
* <p>
|
||||||
* This function is equivalent to <code>getByte(0, backward)</code>.
|
* This function is equivalent to <code>getByte(0, backward)</code>.
|
||||||
*/
|
*/
|
||||||
@@ -307,9 +304,9 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the byte from the given forward minus backward offset.
|
* Gets the byte from the given forward minus backward offset. The forward
|
||||||
* The forward offset is added to the current position. This lets
|
* offset is added to the current position. This lets one read bytes ahead
|
||||||
* one read bytes ahead of the current byte.
|
* of the current byte.
|
||||||
*/
|
*/
|
||||||
public int getByte(int forward, int backward) {
|
public int getByte(int forward, int backward) {
|
||||||
return buf[readPos + forward - backward] & 0xFF;
|
return buf[readPos + forward - backward] & 0xFF;
|
||||||
@@ -354,10 +351,10 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that the matches returned by the match finder are valid.
|
* Verifies that the matches returned by the match finder are valid. This is
|
||||||
* This is meant to be used in an assert statement. This is totally
|
* meant to be used in an assert statement. This is totally useless for
|
||||||
* useless for actual encoding since match finder's results should
|
* actual encoding since match finder's results should naturally always be
|
||||||
* naturally always be valid if it isn't broken.
|
* valid if it isn't broken.
|
||||||
*
|
*
|
||||||
* @param matches return value from <code>getMatches</code>
|
* @param matches return value from <code>getMatches</code>
|
||||||
*
|
*
|
||||||
@@ -374,21 +371,17 @@ public abstract class LZEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves to the next byte, checks if there is enough input available,
|
* Moves to the next byte, checks if there is enough input available, and
|
||||||
* and returns the amount of input available.
|
* returns the amount of input available.
|
||||||
*
|
*
|
||||||
* @param requiredForFlushing
|
* @param requiredForFlushing minimum number of available bytes when
|
||||||
* minimum number of available bytes when
|
* flushing; encoding may be continued with new input after flushing
|
||||||
* flushing; encoding may be continued with
|
* @param requiredForFinishing minimum number of available bytes when
|
||||||
* new input after flushing
|
* finishing; encoding must not be continued after finishing or the match
|
||||||
* @param requiredForFinishing
|
* finder state may be corrupt
|
||||||
* minimum number of available bytes when
|
|
||||||
* finishing; encoding must not be continued
|
|
||||||
* after finishing or the match finder state
|
|
||||||
* may be corrupt
|
|
||||||
*
|
*
|
||||||
* @return the number of bytes available or zero if there
|
* @return the number of bytes available or zero if there is not enough
|
||||||
* is not enough input available
|
* input available
|
||||||
*/
|
*/
|
||||||
int movePos(int requiredForFlushing, int requiredForFinishing) {
|
int movePos(int requiredForFlushing, int requiredForFinishing) {
|
||||||
assert requiredForFlushing >= requiredForFinishing;
|
assert requiredForFlushing >= requiredForFinishing;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user