update code style

This commit is contained in:
huangyuhui
2016-01-01 11:03:09 +08:00
parent 1f7eb04215
commit b82243a9c0
298 changed files with 3902 additions and 3998 deletions

View File

@@ -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();
} * }
}*/ * }
*/
} }

View File

@@ -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");

View File

@@ -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
*/ */

View File

@@ -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;

View File

@@ -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
* *

View File

@@ -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.
* *

View File

@@ -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?
*/ */

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;
} }

View 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;

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hellominecraft.launcher.utils.assets; package org.jackhuang.hellominecraft.launcher.utils.assets;
/** /**
* *
* @author huangyuhui * @author huangyuhui

View File

@@ -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;

View File

@@ -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
*/ */

View File

@@ -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) {

View File

@@ -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");

View File

@@ -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:

View File

@@ -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();
} }
}; };
} }

View File

@@ -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();
} }

View File

@@ -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);

View File

@@ -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);

View File

@@ -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))

View File

@@ -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/");

View File

@@ -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) {

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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) {

View File

@@ -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;
} }

View File

@@ -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();
} }

View File

@@ -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;

View File

@@ -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);

View File

@@ -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>

View File

@@ -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;

View File

@@ -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 });
} }
}); });
} }

View File

@@ -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());

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
} }
} }

View File

@@ -38,7 +38,8 @@ public class TaskObservable<T> extends TaskInfo {
@Override @Override
public void executeTask() { public void executeTask() {
r.subscribe(t->{}); r.subscribe(t -> {
});
} }
} }

View File

@@ -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 {

View File

@@ -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

View File

@@ -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();

View File

@@ -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);
} }
}); });

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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");

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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");

View File

@@ -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);

View File

@@ -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)
); );
} }

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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
*/ */

View File

@@ -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);
} }

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();
} }

View File

@@ -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);
} }

View File

@@ -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);
} }

View File

@@ -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>
*/ */

View File

@@ -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&nbsp;MiB, * uncompressed size of the file exceeds 8&nbsp;MiB, 16&nbsp;MiB, or
* 16&nbsp;MiB, or 32&nbsp;MiB, it is waste of memory to use the * 32&nbsp;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&nbsp;+&nbsp;2^(n-1) bytes are somewhat * of 2^n and 2^n&nbsp;+&nbsp;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&nbsp;+&nbsp;2^(n-1) bytes. This is because the .xz * not 2^n or 2^n&nbsp;+&nbsp;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

View File

@@ -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)

View File

@@ -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&nbsp;% slower) than with {@link LZMA2InputStream} * worse (maybe 10-20&nbsp;% 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>
*/ */

View File

@@ -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)
*/ */

View File

@@ -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");
} }
} }

View File

@@ -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 {

View File

@@ -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;
} }

View File

@@ -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&nbsp;KiB of memory and each Block 16 bytes of memory, rounded up * 1&nbsp;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&nbsp;&lt;&lt;&nbsp;XZ.CHECK_CRC64)
* <code>(1&nbsp;&lt;&lt;&nbsp;XZ.CHECK_CRC64)
* | (1&nbsp;&lt;&lt;&nbsp;XZ.CHECK_SHA256)</code>. * | (1&nbsp;&lt;&lt;&nbsp;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&nbsp;&lt;&nbsp;0</code> or * <code>blockNumber&nbsp;&lt;&nbsp;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&nbsp;&lt;&nbsp;0</code> or * <code>blockNumber&nbsp;&lt;&nbsp;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&nbsp;&lt;&nbsp;0</code> or
* <code>pos&nbsp;&lt;&nbsp;0</code> or
* <code>pos&nbsp;&gt;=&nbsp;length()</code>. * <code>pos&nbsp;&gt;=&nbsp;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&nbsp;&lt;&nbsp;0</code> or
* if <code>blockNumber&nbsp;&lt;&nbsp;0</code> or * <code>blockNumber&nbsp;&gt;=&nbsp;getBlockCount()</code>, or if stream
* <code>blockNumber&nbsp;&gt;=&nbsp;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();

View File

@@ -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>
*/ */

View File

@@ -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
*/ */

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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&nbsp;GiB. Still, very few files will * XZInputStream is currently 1.5&nbsp;GiB. Still, very few files will require
* require more than about 65&nbsp;MiB because that's how much decompressing * more than about 65&nbsp;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&nbsp;MiB: * 100&nbsp;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>
*/ */

View File

@@ -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&nbsp;EiB or the Index field exceeds 16&nbsp;GiB; you shouldn't reach
* about 8&nbsp;EiB or the Index field exceeds * these sizes in practice
* 16&nbsp;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 &gt; 0
* was already called and len &gt; 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
*/ */

View File

@@ -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;
} }

View File

@@ -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);
} }
} }

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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));
} }

View File

@@ -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);

View File

@@ -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
*/ */

View File

@@ -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;

View File

@@ -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