update code style
This commit is contained in:
@@ -174,15 +174,16 @@ public final class Launcher {
|
||||
}
|
||||
}
|
||||
/*
|
||||
static Object getShutdownHaltLock() {
|
||||
try {
|
||||
Class z = Class.forName("java.lang.Shutdown");
|
||||
Field haltLock = z.getDeclaredField("haltLock");
|
||||
haltLock.setAccessible(true);
|
||||
return haltLock.get(null);
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
return new Object();
|
||||
}
|
||||
}*/
|
||||
* static Object getShutdownHaltLock() {
|
||||
* try {
|
||||
* Class z = Class.forName("java.lang.Shutdown");
|
||||
* Field haltLock = z.getDeclaredField("haltLock");
|
||||
* haltLock.setAccessible(true);
|
||||
* return haltLock.get(null);
|
||||
* } catch (Throwable ex) {
|
||||
* ex.printStackTrace();
|
||||
* return new Object();
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public interface IPlugin {
|
||||
* You can modify the application actions by this method.
|
||||
*
|
||||
* @param profile info to the Minecraft Loader
|
||||
*
|
||||
* @return For example, you can implement IMinecraftProvider to support
|
||||
* MultiMC
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hellominecraft.launcher.launch;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jackhuang.hellominecraft.C;
|
||||
import org.jackhuang.hellominecraft.HMCLog;
|
||||
import org.jackhuang.hellominecraft.launcher.launch.GameLauncher.DownloadLibraryJob;
|
||||
|
||||
@@ -111,7 +111,7 @@ public class GameLauncher {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> lst = null;
|
||||
List<String> lst;
|
||||
try {
|
||||
lst = loader.makeLaunchingCommand();
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -39,8 +39,6 @@ public abstract class IMinecraftDownloadService extends IMinecraftService {
|
||||
|
||||
public abstract boolean downloadMinecraftVersionJson(String id);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the libraries that need to download.
|
||||
*
|
||||
|
||||
@@ -74,6 +74,7 @@ public abstract class IMinecraftProvider {
|
||||
/**
|
||||
*
|
||||
* @param v should be resolved
|
||||
*
|
||||
* @return libraries of resolved minecraft version v.
|
||||
*/
|
||||
public abstract GameLauncher.DecompressLibraryJob getDecompressLibraries(MinecraftVersion v);
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jackhuang.hellominecraft.launcher.settings.Profile;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public abstract class IMinecraftService {
|
||||
|
||||
public Profile profile;
|
||||
|
||||
public IMinecraftService(Profile profile) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package org.jackhuang.hellominecraft.launcher.utils.assets;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
|
||||
@@ -46,6 +46,7 @@ public abstract class IAuthenticator {
|
||||
* @param info username & password
|
||||
*
|
||||
* @return login result
|
||||
*
|
||||
* @throws
|
||||
* org.jackhuang.hellominecraft.launcher.utils.auth.AuthenticationException
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,6 @@ public enum InstallerType {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
public String getLocalizedName() {
|
||||
return this.name();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public abstract class InstallerVersionList implements Consumer<String[]> {
|
||||
* Get installers you want.
|
||||
*
|
||||
* @param mcVersion the installers to this Minecraft version.
|
||||
*
|
||||
* @return cached result.
|
||||
*/
|
||||
protected abstract List<InstallerVersion> getVersionsImpl(String mcVersion);
|
||||
@@ -56,6 +57,7 @@ public abstract class InstallerVersionList implements Consumer<String[]> {
|
||||
* Get installers you want, please cache this method's result to save time.
|
||||
*
|
||||
* @param mcVersion the installers to this Minecraft version.
|
||||
*
|
||||
* @return a copy of the cached data to prevent
|
||||
* ConcurrentModificationException.
|
||||
*/
|
||||
|
||||
@@ -76,9 +76,11 @@ public class ForgeInstaller extends Task {
|
||||
FileUtils.copyFile(new File(from, profile.install.minecraft + ".jar"),
|
||||
new File(to, profile.install.target + ".jar"));
|
||||
HMCLog.log("Creating new version profile..." + profile.install.target + ".json");
|
||||
/*for (MinecraftLibrary library : profile.versionInfo.libraries)
|
||||
if (library.name.startsWith("net.minecraftforge:forge:"))
|
||||
library.url = installerVersion.universal;*/
|
||||
/*
|
||||
* for (MinecraftLibrary library : profile.versionInfo.libraries)
|
||||
* 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));
|
||||
|
||||
HMCLog.log("Extracting universal forge pack..." + profile.install.filePath);
|
||||
|
||||
@@ -35,6 +35,7 @@ public abstract class IUpgrader implements Event<VersionNumber> {
|
||||
*
|
||||
* @param nowVersion now launcher version
|
||||
* @param args Application CommandLine Arguments
|
||||
*
|
||||
* @return true if it is needed to break the main thread to shutdown this
|
||||
* application.
|
||||
*/
|
||||
@@ -45,6 +46,7 @@ public abstract class IUpgrader implements Event<VersionNumber> {
|
||||
*
|
||||
* @param sender Should be VersionChecker
|
||||
* @param number the newest version
|
||||
*
|
||||
* @return should return true
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -40,6 +40,7 @@ import rx.Observable;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class MinecraftDownloadService extends IMinecraftDownloadService {
|
||||
|
||||
MinecraftVersionManager mgr;
|
||||
|
||||
public MinecraftDownloadService(Profile p, MinecraftVersionManager mgr) {
|
||||
|
||||
@@ -42,10 +42,9 @@ public class GameDownloadPanel extends AnimatedPanel implements Selectable {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
|
||||
@@ -39,10 +39,9 @@ public class ServerListCellRenderer extends javax.swing.JPanel implements ListCe
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
|
||||
@@ -57,10 +57,9 @@ public class ServerListView extends javax.swing.JDialog {
|
||||
public static final int FAILED_TO_SELECT = -1;
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
|
||||
@@ -32,7 +32,8 @@ public class DoubleTask extends Task {
|
||||
|
||||
@Override
|
||||
public void executeTask() throws Throwable {
|
||||
a.executeTask(); b.executeTask();
|
||||
a.executeTask();
|
||||
b.executeTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,7 +38,8 @@ public class TaskObservable<T> extends TaskInfo {
|
||||
|
||||
@Override
|
||||
public void executeTask() {
|
||||
r.subscribe(t->{});
|
||||
r.subscribe(t -> {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -113,15 +113,13 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
||||
connection.connect();
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
// Check for valid content length.
|
||||
int contentLength = connection.getContentLength();
|
||||
if (contentLength < 1) {
|
||||
if (contentLength < 1)
|
||||
throw new NetException("The content length is invalid.");
|
||||
}
|
||||
|
||||
filePath.getParentFile().mkdirs();
|
||||
|
||||
@@ -179,7 +177,8 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
||||
closeFiles();
|
||||
}
|
||||
}
|
||||
if (failReason != null) throw failReason;
|
||||
if (failReason != null)
|
||||
throw failReason;
|
||||
}
|
||||
|
||||
public static void download(String url, String file, DownloadListener dl) throws Throwable {
|
||||
|
||||
@@ -76,7 +76,8 @@ public class HTTPGetTask extends TaskInfo implements PreviousResult<String> {
|
||||
t = new NetException("Failed to get " + url, ex);
|
||||
}
|
||||
}
|
||||
if (t != null) throw t;
|
||||
if (t != null)
|
||||
throw t;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,22 +32,29 @@ public interface IUpdateChecker {
|
||||
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
|
||||
*
|
||||
* @see process
|
||||
*/
|
||||
VersionNumber getNewVersion();
|
||||
|
||||
/**
|
||||
* Download the version number synchronously.
|
||||
* When you execute this method first, should leave "showMessage" false.
|
||||
* @param showMessage If it is requested to warn the user that there is a new version.
|
||||
* Download the version number synchronously. When you execute this method
|
||||
* first, should leave "showMessage" false.
|
||||
*
|
||||
* @param showMessage If it is requested to warn the user that there is a
|
||||
* new version.
|
||||
*
|
||||
* @return the process observable.
|
||||
*/
|
||||
Observable process(boolean showMessage);
|
||||
|
||||
/**
|
||||
* Get the download links.
|
||||
*
|
||||
* @return a JSON, which contains the server response.
|
||||
*/
|
||||
Observable<Map<String, String>> requestDownloadLink();
|
||||
|
||||
@@ -53,7 +53,8 @@ public final class NetUtils {
|
||||
|
||||
public static String getStreamContent(InputStream is, String encoding)
|
||||
throws IOException {
|
||||
if (is == null) return null;
|
||||
if (is == null)
|
||||
return null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try (InputStreamReader br = new InputStreamReader(is, encoding)) {
|
||||
int len;
|
||||
|
||||
@@ -54,10 +54,14 @@ public final class StrUtils {
|
||||
cmdbuf.append("\\");
|
||||
cmdbuf.append('"');
|
||||
} else if (s.endsWith("\""))
|
||||
/* The argument has already been quoted. */
|
||||
/*
|
||||
* The argument has already been quoted.
|
||||
*/
|
||||
cmdbuf.append(s);
|
||||
else
|
||||
/* Unmatched quote for the argument. */
|
||||
/*
|
||||
* Unmatched quote for the argument.
|
||||
*/
|
||||
throw new IllegalArgumentException();
|
||||
else
|
||||
cmdbuf.append(s);
|
||||
|
||||
@@ -72,9 +72,9 @@ public class Java {
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------
|
||||
MAC OS X
|
||||
-----------------------------------
|
||||
* -----------------------------------
|
||||
* MAC OS X
|
||||
* -----------------------------------
|
||||
*/
|
||||
public static List<Java> queryAllJDKInMac() {
|
||||
List<Java> ans = new ArrayList<>();
|
||||
@@ -88,9 +88,9 @@ public class Java {
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------
|
||||
WINDOWS
|
||||
-----------------------------------
|
||||
* -----------------------------------
|
||||
* WINDOWS
|
||||
* -----------------------------------
|
||||
*/
|
||||
public static List<Java> queryAllJavaHomeInWindowsByReg() {
|
||||
List<Java> ans = new ArrayList<>();
|
||||
|
||||
@@ -33,31 +33,32 @@ public class LogWindowOutputStream extends OutputStream {
|
||||
|
||||
private final LogWindow txt;
|
||||
private final Level sas;
|
||||
|
||||
/*
|
||||
private final CacheTask t = new CacheTask();
|
||||
private class CacheTask extends TimerTask {
|
||||
private final Object lock = new Object();
|
||||
private StringBuilder cachedString = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized(lock) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String t = txt.getText() + cachedString.toString().replace("\t", " ");
|
||||
txt.setText(t);
|
||||
txt.setCaretPosition(t.length());
|
||||
cachedString = new StringBuilder();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void cache(String s) {
|
||||
synchronized(lock) {
|
||||
cachedString.append(s);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
* private final CacheTask t = new CacheTask();
|
||||
* private class CacheTask extends TimerTask {
|
||||
* private final Object lock = new Object();
|
||||
* private StringBuilder cachedString = new StringBuilder();
|
||||
*
|
||||
* @Override
|
||||
* public void run() {
|
||||
* synchronized(lock) {
|
||||
* SwingUtilities.invokeLater(() -> {
|
||||
* String t = txt.getText() + cachedString.toString().replace("\t", " ");
|
||||
* txt.setText(t);
|
||||
* txt.setCaretPosition(t.length());
|
||||
* cachedString = new StringBuilder();
|
||||
* });
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* void cache(String s) {
|
||||
* synchronized(lock) {
|
||||
* cachedString.append(s);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public LogWindowOutputStream(LogWindow logWindow, Level l) {
|
||||
txt = logWindow;
|
||||
this.sas = l;
|
||||
|
||||
@@ -21,14 +21,17 @@ abstract class BCJCoder implements FilterCoder {
|
||||
return filterID >= 0x04 && filterID <= 0x09;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changesSize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nonLastOK() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lastOK() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,23 +21,28 @@ class BCJDecoder extends BCJCoder implements FilterDecoder {
|
||||
assert isBCJFilterID(filterID);
|
||||
this.filterID = filterID;
|
||||
|
||||
if (props.length == 0)
|
||||
switch (props.length) {
|
||||
case 0:
|
||||
startOffset = 0;
|
||||
else if (props.length == 4) {
|
||||
break;
|
||||
case 4:
|
||||
int n = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
n |= (props[i] & 0xFF) << (i * 8);
|
||||
|
||||
startOffset = n;
|
||||
} else
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOptionsException(
|
||||
"Unsupported BCJ filter properties");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMemoryUsage() {
|
||||
return SimpleInputStream.getMemoryUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(InputStream in) {
|
||||
SimpleFilter simpleFilter = null;
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ abstract class BCJOptions extends FilterOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start offset for the address conversions.
|
||||
* Normally this is useless so you shouldn't use this function.
|
||||
* The default value is <code>0</code>.
|
||||
* Sets the start offset for the address conversions. Normally this is
|
||||
* useless so you shouldn't use this function. The default value is
|
||||
* <code>0</code>.
|
||||
*/
|
||||
public void setStartOffset(int startOffset)
|
||||
throws UnsupportedOptionsException {
|
||||
|
||||
@@ -9,25 +9,25 @@
|
||||
package org.tukaani.xz;
|
||||
|
||||
/**
|
||||
* Thrown when the compressed input data is corrupt.
|
||||
* However, it is possible that some or all of the data
|
||||
* already read from the input stream was corrupt too.
|
||||
* Thrown when the compressed input data is corrupt. However, it is possible
|
||||
* that some or all of the data already read from the input stream was corrupt
|
||||
* too.
|
||||
*/
|
||||
public class CorruptedInputException extends XZIOException {
|
||||
|
||||
private static final long serialVersionUID = 3L;
|
||||
|
||||
/**
|
||||
* Creates a new CorruptedInputException with
|
||||
* the default error detail message.
|
||||
* Creates a new CorruptedInputException with the default error detail
|
||||
* message.
|
||||
*/
|
||||
public CorruptedInputException() {
|
||||
super("Compressed data is corrupt");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CorruptedInputException with
|
||||
* the specified error detail message.
|
||||
* Creates a new CorruptedInputException with the specified error detail
|
||||
* message.
|
||||
*
|
||||
* @param s error detail message
|
||||
*/
|
||||
|
||||
@@ -22,10 +22,12 @@ class DeltaDecoder extends DeltaCoder implements FilterDecoder {
|
||||
distance = (props[0] & 0xFF) + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMemoryUsage() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(InputStream in) {
|
||||
return new DeltaInputStream(in, distance);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ import org.tukaani.xz.delta.DeltaDecoder;
|
||||
/**
|
||||
* Decodes raw Delta-filtered data (no XZ headers).
|
||||
* <p>
|
||||
* The delta filter doesn't change the size of the data and thus it
|
||||
* cannot have an end-of-payload marker. It will simply decode until
|
||||
* its input stream indicates end of input.
|
||||
* The delta filter doesn't change the size of the data and thus it cannot have
|
||||
* an end-of-payload marker. It will simply decode until its input stream
|
||||
* indicates end of input.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param in input stream from which Delta filtered data
|
||||
* is read
|
||||
* @param in input stream from which Delta filtered data is read
|
||||
*
|
||||
* @param distance delta calculation distance, must be in the
|
||||
* range [<code>DISTANCE_MIN</code>,
|
||||
* <code>DISTANCE_MAX</code>]
|
||||
* @param distance delta calculation distance, must be in the range
|
||||
* [<code>DISTANCE_MIN</code>, <code>DISTANCE_MAX</code>]
|
||||
*/
|
||||
public DeltaInputStream(InputStream in, int distance) {
|
||||
// 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.
|
||||
*
|
||||
* @return the next decoded byte, or <code>-1</code> to indicate
|
||||
* the end of input on the input stream <code>in</code>
|
||||
* @return the next decoded byte, or <code>-1</code> to indicate the end of
|
||||
* input on the input stream <code>in</code>
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
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.
|
||||
* <p>
|
||||
* This calls <code>in.read(buf, off, len)</code> and defilters the
|
||||
* returned data.
|
||||
* This calls <code>in.read(buf, off, len)</code> and defilters the returned
|
||||
* data.
|
||||
*
|
||||
* @param buf target buffer for decoded data
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len maximum number of bytes to read
|
||||
*
|
||||
* @return number of bytes read, or <code>-1</code> to indicate
|
||||
* the end of the input stream <code>in</code>
|
||||
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||
* the input stream <code>in</code>
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws IOException may be thrown by underlaying input
|
||||
* stream <code>in</code>
|
||||
* @throws IOException may be thrown by underlaying input stream
|
||||
* <code>in</code>
|
||||
*/
|
||||
@Override
|
||||
public int read(byte[] buf, int off, int len) throws IOException {
|
||||
if (len == 0)
|
||||
return 0;
|
||||
@@ -118,6 +118,7 @@ public class DeltaInputStream extends InputStream {
|
||||
*
|
||||
* @return the value returned by <code>in.available()</code>
|
||||
*/
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
if (in == null)
|
||||
throw new XZIOException("Stream closed");
|
||||
@@ -129,11 +130,12 @@ public class DeltaInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and calls <code>in.close()</code>.
|
||||
* If the stream was already closed, this does nothing.
|
||||
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||
* already closed, this does nothing.
|
||||
*
|
||||
* @throws IOException if thrown by <code>in.close()</code>
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (in != null)
|
||||
try {
|
||||
|
||||
@@ -11,19 +11,19 @@ package org.tukaani.xz;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Delta filter options. The Delta filter can be used only as a non-last
|
||||
* filter in the chain, for example Delta + LZMA2.
|
||||
* Delta filter options. The Delta filter can be used only as a non-last filter
|
||||
* in the chain, for example Delta + LZMA2.
|
||||
* <p>
|
||||
* Currently only simple byte-wise delta is supported. The only option
|
||||
* is the delta distance, which you should set to match your data.
|
||||
* It's not possible to provide a generic default value for it.
|
||||
* Currently only simple byte-wise delta is supported. The only option is the
|
||||
* delta distance, which you should set to match your data. It's not possible to
|
||||
* provide a generic default value for it.
|
||||
* <p>
|
||||
* For example, with distance = 2 and eight-byte input
|
||||
* A1 B1 A2 B3 A3 B5 A4 B7, the output will be A1 B1 01 02 01 02 01 02.
|
||||
* For example, with distance = 2 and eight-byte input A1 B1 A2 B3 A3 B5 A4 B7,
|
||||
* the output will be A1 B1 01 02 01 02 01 02.
|
||||
* <p>
|
||||
* The Delta filter can be good with uncompressed bitmap images. It can
|
||||
* also help with PCM audio, although special-purpose compressors like
|
||||
* FLAC will give much smaller result at much better compression speed.
|
||||
* The Delta filter can be good with uncompressed bitmap images. It can also
|
||||
* help with PCM audio, although special-purpose compressors like FLAC will give
|
||||
* much smaller result at much better compression speed.
|
||||
*/
|
||||
public class DeltaOptions extends FilterOptions {
|
||||
|
||||
@@ -53,8 +53,8 @@ public class DeltaOptions extends FilterOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delta distance in bytes. The new distance must be in
|
||||
* the range [DISTANCE_MIN, DISTANCE_MAX].
|
||||
* Sets the delta distance in bytes. The new distance must be in the range
|
||||
* [DISTANCE_MIN, DISTANCE_MAX].
|
||||
*/
|
||||
public void setDistance(int distance) throws UnsupportedOptionsException {
|
||||
if (distance < DISTANCE_MIN || distance > DISTANCE_MAX)
|
||||
@@ -72,26 +72,32 @@ public class DeltaOptions extends FilterOptions {
|
||||
return distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEncoderMemoryUsage() {
|
||||
return DeltaOutputStream.getMemoryUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
|
||||
return new DeltaOutputStream(out, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDecoderMemoryUsage() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(InputStream in) {
|
||||
return new DeltaInputStream(in, distance);
|
||||
}
|
||||
|
||||
@Override
|
||||
FilterEncoder getFilterEncoder() {
|
||||
return new DeltaEncoder(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
|
||||
@@ -18,10 +18,9 @@ import java.io.IOException;
|
||||
public abstract class FilterOptions implements Cloneable {
|
||||
|
||||
/**
|
||||
* Gets how much memory the encoder will need with
|
||||
* the given filter chain. This function simply calls
|
||||
* <code>getEncoderMemoryUsage()</code> for every filter
|
||||
* in the array and returns the sum of the returned values.
|
||||
* Gets how much memory the encoder will need with the given filter chain.
|
||||
* This function simply calls <code>getEncoderMemoryUsage()</code> for every
|
||||
* filter in the array and returns the sum of the returned values.
|
||||
*/
|
||||
public static int getEncoderMemoryUsage(FilterOptions[] options) {
|
||||
int m = 0;
|
||||
@@ -33,10 +32,9 @@ public abstract class FilterOptions implements Cloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets how much memory the decoder will need with
|
||||
* the given filter chain. This function simply calls
|
||||
* <code>getDecoderMemoryUsage()</code> for every filter
|
||||
* in the array and returns the sum of the returned values.
|
||||
* Gets how much memory the decoder will need with the given filter chain.
|
||||
* This function simply calls <code>getDecoderMemoryUsage()</code> for every
|
||||
* filter in the array and returns the sum of the returned values.
|
||||
*/
|
||||
public static int getDecoderMemoryUsage(FilterOptions[] options) {
|
||||
int m = 0;
|
||||
@@ -53,18 +51,18 @@ public abstract class FilterOptions implements Cloneable {
|
||||
public abstract int getEncoderMemoryUsage();
|
||||
|
||||
/**
|
||||
* Gets a raw (no XZ headers) encoder output stream using these options.
|
||||
* Raw streams are an advanced feature. In most cases you want to store
|
||||
* the compressed data in the .xz container format instead of using
|
||||
* a raw stream. To use this filter in a .xz file, pass this object
|
||||
* to XZOutputStream.
|
||||
* Gets a raw (no XZ headers) encoder output stream using these options. Raw
|
||||
* streams are an advanced feature. In most cases you want to store the
|
||||
* compressed data in the .xz container format instead of using a raw
|
||||
* stream. To use this filter in a .xz file, pass this object to
|
||||
* XZOutputStream.
|
||||
*/
|
||||
public abstract FinishableOutputStream getOutputStream(
|
||||
FinishableOutputStream out);
|
||||
|
||||
/**
|
||||
* Gets how much memory the decoder will need to decompress the data
|
||||
* that was encoded with these options.
|
||||
* Gets how much memory the decoder will need to decompress the data that
|
||||
* was encoded with these options.
|
||||
*/
|
||||
public abstract int getDecoderMemoryUsage();
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
||||
/**
|
||||
* Calls {@link java.io.OutputStream#write(int) out.write(b)}.
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
out.write(b);
|
||||
}
|
||||
@@ -42,6 +43,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
||||
/**
|
||||
* Calls {@link java.io.OutputStream#write(byte[]) out.write(buf)}.
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] buf) throws IOException {
|
||||
out.write(buf);
|
||||
}
|
||||
@@ -50,6 +52,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
||||
* Calls {@link java.io.OutputStream#write(byte[],int,int)
|
||||
* out.write(buf, off, len)}.
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] buf, int off, int len) throws IOException {
|
||||
out.write(buf, off, len);
|
||||
}
|
||||
@@ -57,6 +60,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
||||
/**
|
||||
* Calls {@link java.io.OutputStream#flush() out.flush()}.
|
||||
*/
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
out.flush();
|
||||
}
|
||||
@@ -64,6 +68,7 @@ public class FinishableWrapperOutputStream extends FinishableOutputStream {
|
||||
/**
|
||||
* Calls {@link java.io.OutputStream#close() out.close()}.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
}
|
||||
|
||||
@@ -25,10 +25,12 @@ class LZMA2Decoder extends LZMA2Coder implements FilterDecoder {
|
||||
dictSize <<= (props[0] >>> 1) + 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMemoryUsage() {
|
||||
return LZMA2InputStream.getMemoryUsage(dictSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(InputStream in) {
|
||||
return new LZMA2InputStream(in, dictSize);
|
||||
}
|
||||
|
||||
@@ -32,18 +32,22 @@ class LZMA2Encoder extends LZMA2Coder implements FilterEncoder {
|
||||
this.options = (LZMA2Options) options.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFilterID() {
|
||||
return FILTER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getFilterProps() {
|
||||
return props;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFlushing() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
|
||||
return options.getOutputStream(out);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ public class LZMA2InputStream extends InputStream {
|
||||
/**
|
||||
* Smallest valid LZMA2 dictionary size.
|
||||
* <p>
|
||||
* Very tiny dictionaries would be a performance problem, so
|
||||
* the minimum is 4 KiB.
|
||||
* Very tiny dictionaries would be a performance problem, so the minimum is
|
||||
* 4 KiB.
|
||||
*/
|
||||
public static final int DICT_SIZE_MIN = 4096;
|
||||
|
||||
@@ -33,11 +33,11 @@ public class LZMA2InputStream extends InputStream {
|
||||
* Largest dictionary size supported by this implementation.
|
||||
* <p>
|
||||
* 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
|
||||
* LZMA2 streams, and for .xz files the maximum is 1.5 GiB. This
|
||||
* limitation is due to Java using signed 32-bit integers for array
|
||||
* indexing. The limitation shouldn't matter much in practice since so
|
||||
* huge dictionaries are not normally used.
|
||||
* This implementation supports only 16 bytes less than 2 GiB for raw LZMA2
|
||||
* streams, and for .xz files the maximum is 1.5 GiB. This limitation is due
|
||||
* to Java using signed 32-bit integers for array indexing. The limitation
|
||||
* shouldn't matter much in practice since so huge dictionaries are not
|
||||
* normally used.
|
||||
*/
|
||||
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];
|
||||
|
||||
/**
|
||||
* Gets approximate decompressor memory requirements as kibibytes for
|
||||
* the given dictionary size.
|
||||
* Gets approximate decompressor memory requirements as kibibytes for the
|
||||
* given dictionary size.
|
||||
*
|
||||
* @param dictSize LZMA2 dictionary size as bytes, must be
|
||||
* in the range [<code>DICT_SIZE_MIN</code>,
|
||||
* <code>DICT_SIZE_MAX</code>]
|
||||
* @param dictSize LZMA2 dictionary size as bytes, must be in the range
|
||||
* [<code>DICT_SIZE_MIN</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @return approximate memory requirements as kibibytes (KiB)
|
||||
*/
|
||||
@@ -91,27 +90,25 @@ public class LZMA2InputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream that decompresses raw LZMA2 data
|
||||
* from <code>in</code>.
|
||||
* Creates a new input stream that decompresses raw LZMA2 data from
|
||||
* <code>in</code>.
|
||||
* <p>
|
||||
* The caller needs to know the dictionary size used when compressing;
|
||||
* the dictionary size isn't stored as part of a raw LZMA2 stream.
|
||||
* The caller needs to know the dictionary size used when compressing; the
|
||||
* dictionary size isn't stored as part of a raw LZMA2 stream.
|
||||
* <p>
|
||||
* Specifying a too small dictionary size will prevent decompressing
|
||||
* the stream. Specifying a too big dictionary is waste of memory but
|
||||
* Specifying a too small dictionary size will prevent decompressing the
|
||||
* stream. Specifying a too big dictionary is waste of memory but
|
||||
* decompression will work.
|
||||
* <p>
|
||||
* There is no need to specify a dictionary bigger than
|
||||
* the uncompressed size of the data even if a bigger dictionary
|
||||
* was used when compressing. If you know the uncompressed size
|
||||
* of the data, this might allow saving some memory.
|
||||
* There is no need to specify a dictionary bigger than the uncompressed
|
||||
* size of the data even if a bigger dictionary was used when compressing.
|
||||
* If you know the uncompressed size of the data, this might allow saving
|
||||
* some memory.
|
||||
*
|
||||
* @param in input stream from which LZMA2-compressed
|
||||
* data is read
|
||||
* @param in input stream from which LZMA2-compressed data is read
|
||||
*
|
||||
* @param dictSize LZMA2 dictionary size as bytes, must be
|
||||
* in the range [<code>DICT_SIZE_MIN</code>,
|
||||
* <code>DICT_SIZE_MAX</code>]
|
||||
* @param dictSize LZMA2 dictionary size as bytes, must be in the range
|
||||
* [<code>DICT_SIZE_MIN</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*/
|
||||
public LZMA2InputStream(InputStream in, int dictSize) {
|
||||
this(in, dictSize, null);
|
||||
@@ -120,20 +117,18 @@ public class LZMA2InputStream extends InputStream {
|
||||
/**
|
||||
* Creates a new LZMA2 decompressor using a preset dictionary.
|
||||
* <p>
|
||||
* This is like <code>LZMA2InputStream(InputStream, int)</code> except
|
||||
* that the dictionary may be initialized using a preset dictionary.
|
||||
* If a preset dictionary was used when compressing the data, the
|
||||
* same preset dictionary must be provided when decompressing.
|
||||
* This is like <code>LZMA2InputStream(InputStream, int)</code> except that
|
||||
* the dictionary may be initialized using a preset dictionary. If a preset
|
||||
* dictionary was used when compressing the data, the same preset dictionary
|
||||
* must be provided when decompressing.
|
||||
*
|
||||
* @param in input stream from which LZMA2-compressed
|
||||
* data is read
|
||||
* @param in input stream from which LZMA2-compressed data is read
|
||||
*
|
||||
* @param dictSize LZMA2 dictionary size as bytes, must be
|
||||
* in the range [<code>DICT_SIZE_MIN</code>,
|
||||
* <code>DICT_SIZE_MAX</code>]
|
||||
* @param dictSize LZMA2 dictionary size as bytes, must be in the range
|
||||
* [<code>DICT_SIZE_MIN</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @param presetDict preset dictionary or <code>null</code>
|
||||
* to use no preset dictionary
|
||||
* @param presetDict preset dictionary or <code>null</code> to use no preset
|
||||
* dictionary
|
||||
*/
|
||||
public LZMA2InputStream(InputStream in, int dictSize, byte[] presetDict) {
|
||||
// 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.
|
||||
* <p>
|
||||
* Reading lots of data with <code>read()</code> from this input stream
|
||||
* may be inefficient. Wrap it in <code>java.io.BufferedInputStream</code>
|
||||
* if you need to read lots of data one byte at a time.
|
||||
* Reading lots of data with <code>read()</code> from this input stream may
|
||||
* be inefficient. Wrap it in <code>java.io.BufferedInputStream</code> if
|
||||
* you need to read lots of data one byte at a time.
|
||||
*
|
||||
* @return the next decompressed byte, or <code>-1</code>
|
||||
* to indicate the end of the compressed stream
|
||||
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||
* end of the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or corrupt
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -174,24 +168,23 @@ public class LZMA2InputStream extends InputStream {
|
||||
/**
|
||||
* Decompresses into an array of bytes.
|
||||
* <p>
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
||||
* is returned. Otherwise this will block until <code>len</code>
|
||||
* bytes have been decompressed, the end of the LZMA2 stream is reached,
|
||||
* or an exception is thrown.
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||
* returned. Otherwise this will block until <code>len</code> bytes have
|
||||
* been decompressed, the end of the LZMA2 stream is reached, or an
|
||||
* exception is thrown.
|
||||
*
|
||||
* @param buf target buffer for uncompressed data
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len maximum number of uncompressed bytes to read
|
||||
*
|
||||
* @return number of bytes read, or <code>-1</code> to indicate
|
||||
* the end of the compressed stream
|
||||
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||
* the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or corrupt
|
||||
*
|
||||
* @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
|
||||
* without blocking. The value is returned with an assumption
|
||||
* that the compressed input data will be valid. If the compressed
|
||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
||||
* thrown before the number of bytes claimed to be available have
|
||||
* been read from this input stream.
|
||||
* Returns the number of uncompressed bytes that can be read without
|
||||
* blocking. The value is returned with an assumption that the compressed
|
||||
* input data will be valid. If the compressed data is corrupt,
|
||||
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||
* bytes claimed to be available have been read from this input stream.
|
||||
* <p>
|
||||
* In LZMA2InputStream, the return value will be non-zero when the
|
||||
* decompressor is in the middle of an LZMA2 chunk. The return value
|
||||
* will then be the number of uncompressed bytes remaining from that
|
||||
* chunk.
|
||||
* decompressor is in the middle of an LZMA2 chunk. The return value will
|
||||
* then be the number of uncompressed bytes remaining from that chunk.
|
||||
*
|
||||
* @return the number of uncompressed bytes that can be read
|
||||
* without blocking
|
||||
* @return the number of uncompressed bytes that can be read without
|
||||
* blocking
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
if (in == null)
|
||||
@@ -337,8 +328,8 @@ public class LZMA2InputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and calls <code>in.close()</code>.
|
||||
* If the stream was already closed, this does nothing.
|
||||
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||
* already closed, this does nothing.
|
||||
*
|
||||
* @throws IOException if thrown by <code>in.close()</code>
|
||||
*/
|
||||
|
||||
@@ -16,9 +16,8 @@ import org.tukaani.xz.lzma.LZMAEncoder;
|
||||
/**
|
||||
* LZMA2 compression options.
|
||||
* <p>
|
||||
* While this allows setting the LZMA2 compression options in detail,
|
||||
* often you only need <code>LZMA2Options()</code> or
|
||||
* <code>LZMA2Options(int)</code>.
|
||||
* While this allows setting the LZMA2 compression options in detail, often you
|
||||
* only need <code>LZMA2Options()</code> or <code>LZMA2Options(int)</code>.
|
||||
*/
|
||||
public class LZMA2Options extends FilterOptions {
|
||||
|
||||
@@ -45,13 +44,13 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Maximum dictionary size for compression is 768 MiB.
|
||||
* <p>
|
||||
* The decompressor supports bigger dictionaries, up to almost 2 GiB.
|
||||
* With HC4 the encoder would support dictionaries bigger than 768 MiB.
|
||||
* The 768 MiB limit comes from the current implementation of BT4 where
|
||||
* we would otherwise hit the limits of signed ints in array indexing.
|
||||
* The decompressor supports bigger dictionaries, up to almost 2 GiB. With
|
||||
* HC4 the encoder would support dictionaries bigger than 768 MiB. The 768
|
||||
* MiB limit comes from the current implementation of BT4 where we would
|
||||
* otherwise hit the limits of signed ints in array indexing.
|
||||
* <p>
|
||||
* If you really need bigger dictionary for decompression,
|
||||
* use {@link LZMA2InputStream} directly.
|
||||
* If you really need bigger dictionary for decompression, use
|
||||
* {@link LZMA2InputStream} directly.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Compression mode: uncompressed.
|
||||
* The data is wrapped into a LZMA2 stream without compression.
|
||||
* Compression mode: uncompressed. The data is wrapped into a LZMA2 stream
|
||||
* without compression.
|
||||
*/
|
||||
public static final int MODE_UNCOMPRESSED = 0;
|
||||
|
||||
/**
|
||||
* Compression mode: fast.
|
||||
* This is usually combined with a hash chain match finder.
|
||||
* Compression mode: fast. This is usually combined with a hash chain match
|
||||
* finder.
|
||||
*/
|
||||
public static final int MODE_FAST = LZMAEncoder.MODE_FAST;
|
||||
|
||||
/**
|
||||
* Compression mode: normal.
|
||||
* This is usually combined with a binary tree match finder.
|
||||
* Compression mode: normal. This is usually combined with a binary tree
|
||||
* match finder.
|
||||
*/
|
||||
public static final int MODE_NORMAL = LZMAEncoder.MODE_NORMAL;
|
||||
|
||||
@@ -140,8 +139,8 @@ public class LZMA2Options extends FilterOptions {
|
||||
private int depthLimit;
|
||||
|
||||
/**
|
||||
* Creates new LZMA2 options and sets them to the default values.
|
||||
* This is equivalent to <code>LZMA2Options(PRESET_DEFAULT)</code>.
|
||||
* Creates new LZMA2 options and sets them to the default values. This is
|
||||
* equivalent to <code>LZMA2Options(PRESET_DEFAULT)</code>.
|
||||
*/
|
||||
public LZMA2Options() {
|
||||
try {
|
||||
@@ -155,8 +154,7 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Creates new LZMA2 options and sets them to the given preset.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>preset</code> is not supported
|
||||
* @throws UnsupportedOptionsException <code>preset</code> is not supported
|
||||
*/
|
||||
public LZMA2Options(int preset) throws UnsupportedOptionsException {
|
||||
setPreset(preset);
|
||||
@@ -165,8 +163,7 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Creates new LZMA2 options and sets them to the given custom values.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* unsupported options were specified
|
||||
* @throws UnsupportedOptionsException unsupported options were specified
|
||||
*/
|
||||
public LZMA2Options(int dictSize, int lc, int lp, int pb, int mode,
|
||||
int niceLen, int mf, int depthLimit)
|
||||
@@ -183,18 +180,17 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the compression options to the given preset.
|
||||
* <p>
|
||||
* The presets 0-3 are fast presets with medium compression.
|
||||
* The presets 4-6 are fairly slow presets with high compression.
|
||||
* The default preset (<code>PRESET_DEFAULT</code>) is 6.
|
||||
* The presets 0-3 are fast presets with medium compression. The presets 4-6
|
||||
* are fairly slow presets with high compression. The default preset
|
||||
* (<code>PRESET_DEFAULT</code>) is 6.
|
||||
* <p>
|
||||
* The presets 7-9 are like the preset 6 but use bigger dictionaries
|
||||
* and have higher compressor and decompressor memory requirements.
|
||||
* Unless the uncompressed size of the file exceeds 8 MiB,
|
||||
* 16 MiB, or 32 MiB, it is waste of memory to use the
|
||||
* presets 7, 8, or 9, respectively.
|
||||
* The presets 7-9 are like the preset 6 but use bigger dictionaries and
|
||||
* have higher compressor and decompressor memory requirements. Unless the
|
||||
* uncompressed size of the file exceeds 8 MiB, 16 MiB, or
|
||||
* 32 MiB, it is waste of memory to use the presets 7, 8, or 9,
|
||||
* respectively.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>preset</code> is not supported
|
||||
* @throws UnsupportedOptionsException <code>preset</code> is not supported
|
||||
*/
|
||||
public void setPreset(int preset) throws UnsupportedOptionsException {
|
||||
if (preset < 0 || preset > 9)
|
||||
@@ -227,12 +223,11 @@ public class LZMA2Options extends FilterOptions {
|
||||
* However, using a dictioanary bigger than the size of the uncompressed
|
||||
* data is waste of memory.
|
||||
* <p>
|
||||
* Any value in the range [DICT_SIZE_MIN, DICT_SIZE_MAX] is valid,
|
||||
* but sizes of 2^n and 2^n + 2^(n-1) bytes are somewhat
|
||||
* recommended.
|
||||
* Any value in the range [DICT_SIZE_MIN, DICT_SIZE_MAX] is valid, but sizes
|
||||
* of 2^n and 2^n + 2^(n-1) bytes are somewhat recommended.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>dictSize</code> is not supported
|
||||
* @throws UnsupportedOptionsException <code>dictSize</code> is not
|
||||
* supported
|
||||
*/
|
||||
public void setDictSize(int dictSize) throws UnsupportedOptionsException {
|
||||
if (dictSize < DICT_SIZE_MIN)
|
||||
@@ -256,18 +251,18 @@ public class LZMA2Options extends FilterOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a preset dictionary. Use null to disable the use of
|
||||
* a preset dictionary. By default there is no preset dictionary.
|
||||
* Sets a preset dictionary. Use null to disable the use of a preset
|
||||
* dictionary. By default there is no preset dictionary.
|
||||
* <p>
|
||||
* <b>The .xz format doesn't support a preset dictionary for now.
|
||||
* Do not set a preset dictionary unless you use raw LZMA2.</b>
|
||||
* <b>The .xz format doesn't support a preset dictionary for now. Do not set
|
||||
* a preset dictionary unless you use raw LZMA2.</b>
|
||||
* <p>
|
||||
* Preset dictionary can be useful when compressing many similar,
|
||||
* relatively small chunks of data independently from each other.
|
||||
* A preset dictionary should contain typical strings that occur in
|
||||
* the files being compressed. The most probable strings should be
|
||||
* near the end of the preset dictionary. The preset dictionary used
|
||||
* for compression is also needed for decompression.
|
||||
* Preset dictionary can be useful when compressing many similar, relatively
|
||||
* small chunks of data independently from each other. A preset dictionary
|
||||
* should contain typical strings that occur in the files being compressed.
|
||||
* The most probable strings should be near the end of the preset
|
||||
* dictionary. The preset dictionary used for compression is also needed for
|
||||
* decompression.
|
||||
*/
|
||||
public void setPresetDict(byte[] presetDict) {
|
||||
this.presetDict = presetDict;
|
||||
@@ -283,12 +278,11 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the number of literal context bits and literal position bits.
|
||||
* <p>
|
||||
* The sum of <code>lc</code> and <code>lp</code> is limited to 4.
|
||||
* Trying to exceed it will throw an exception. This function lets
|
||||
* you change both at the same time.
|
||||
* The sum of <code>lc</code> and <code>lp</code> is limited to 4. Trying to
|
||||
* exceed it will throw an exception. This function lets you change both at
|
||||
* the same time.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>lc</code> and <code>lp</code>
|
||||
* @throws UnsupportedOptionsException <code>lc</code> and <code>lp</code>
|
||||
* are invalid
|
||||
*/
|
||||
public void setLcLp(int lc, int lp) throws UnsupportedOptionsException {
|
||||
@@ -305,28 +299,25 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the number of literal context bits.
|
||||
* <p>
|
||||
* All bytes that cannot be encoded as matches are encoded as literals.
|
||||
* That is, literals are simply 8-bit bytes that are encoded one at
|
||||
* a time.
|
||||
* All bytes that cannot be encoded as matches are encoded as literals. That
|
||||
* is, literals are simply 8-bit bytes that are encoded one at a time.
|
||||
* <p>
|
||||
* The literal coding makes an assumption that the highest <code>lc</code>
|
||||
* bits of the previous uncompressed byte correlate with the next byte.
|
||||
* For example, in typical English text, an upper-case letter is often
|
||||
* followed by a lower-case letter, and a lower-case letter is usually
|
||||
* followed by another lower-case letter. In the US-ASCII character set,
|
||||
* the highest three bits are 010 for upper-case letters and 011 for
|
||||
* lower-case letters. When <code>lc</code> is at least 3, the literal
|
||||
* coding can take advantage of this property in the uncompressed data.
|
||||
* bits of the previous uncompressed byte correlate with the next byte. For
|
||||
* example, in typical English text, an upper-case letter is often followed
|
||||
* by a lower-case letter, and a lower-case letter is usually followed by
|
||||
* another lower-case letter. In the US-ASCII character set, the highest
|
||||
* three bits are 010 for upper-case letters and 011 for lower-case letters.
|
||||
* When <code>lc</code> is at least 3, the literal coding can take advantage
|
||||
* of this property in the uncompressed data.
|
||||
* <p>
|
||||
* 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
|
||||
* makes compression worse. If it makes it worse, test for example
|
||||
* <code>setLc(2)</code> too.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>lc</code> is invalid, or the sum
|
||||
* of <code>lc</code> and <code>lp</code>
|
||||
* exceed LC_LP_MAX
|
||||
* @throws UnsupportedOptionsException <code>lc</code> is invalid, or the
|
||||
* sum of <code>lc</code> and <code>lp</code> exceed LC_LP_MAX
|
||||
*/
|
||||
public void setLc(int lc) throws UnsupportedOptionsException {
|
||||
setLcLp(lc, lp);
|
||||
@@ -335,14 +326,12 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the number of literal position bits.
|
||||
* <p>
|
||||
* This affets what kind of alignment in the uncompressed data is
|
||||
* assumed when encoding literals. See {@link #setPb(int) setPb} for
|
||||
* more information about alignment.
|
||||
* This affets what kind of alignment in the uncompressed data is assumed
|
||||
* when encoding literals. See {@link #setPb(int) setPb} for more
|
||||
* information about alignment.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>lp</code> is invalid, or the sum
|
||||
* of <code>lc</code> and <code>lp</code>
|
||||
* exceed LC_LP_MAX
|
||||
* @throws UnsupportedOptionsException <code>lp</code> is invalid, or the
|
||||
* sum of <code>lc</code> and <code>lp</code> exceed LC_LP_MAX
|
||||
*/
|
||||
public void setLp(int lp) throws UnsupportedOptionsException {
|
||||
setLcLp(lc, lp);
|
||||
@@ -365,26 +354,23 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the number of position bits.
|
||||
* <p>
|
||||
* This affects what kind of alignment in the uncompressed data is
|
||||
* assumed in general. The default (2) means four-byte alignment
|
||||
* (2^<code>pb</code> = 2^2 = 4), which is often a good choice when
|
||||
* there's no better guess.
|
||||
* This affects what kind of alignment in the uncompressed data is assumed
|
||||
* in general. The default (2) means four-byte alignment (2^<code>pb</code>
|
||||
* = 2^2 = 4), which is often a good choice when there's no better guess.
|
||||
* <p>
|
||||
* When the alignment is known, setting the number of position bits
|
||||
* accordingly may reduce the file size a little. For example with text
|
||||
* files having one-byte alignment (US-ASCII, ISO-8859-*, UTF-8), using
|
||||
* <code>setPb(0)</code> can improve compression slightly. For UTF-16
|
||||
* text, <code>setPb(1)</code> is a good choice. If the alignment is
|
||||
* an odd number like 3 bytes, <code>setPb(0)</code> might be the best
|
||||
* choice.
|
||||
* <code>setPb(0)</code> can improve compression slightly. For UTF-16 text,
|
||||
* <code>setPb(1)</code> is a good choice. If the alignment is an odd number
|
||||
* like 3 bytes, <code>setPb(0)</code> might be the best choice.
|
||||
* <p>
|
||||
* Even though the assumed alignment can be adjusted with
|
||||
* <code>setPb</code> and <code>setLp</code>, LZMA2 still slightly favors
|
||||
* 16-byte alignment. It might be worth taking into account when designing
|
||||
* file formats that are likely to be often compressed with LZMA2.
|
||||
* Even though the assumed alignment can be adjusted with <code>setPb</code>
|
||||
* and <code>setLp</code>, LZMA2 still slightly favors 16-byte alignment. It
|
||||
* might be worth taking into account when designing file formats that are
|
||||
* likely to be often compressed with LZMA2.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>pb</code> is invalid
|
||||
* @throws UnsupportedOptionsException <code>pb</code> is invalid
|
||||
*/
|
||||
public void setPb(int pb) throws UnsupportedOptionsException {
|
||||
if (pb < 0 || pb > PB_MAX)
|
||||
@@ -404,20 +390,19 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the compression mode.
|
||||
* <p>
|
||||
* This specifies the method to analyze the data produced by
|
||||
* a match finder. The default is <code>MODE_FAST</code> for presets
|
||||
* 0-3 and <code>MODE_NORMAL</code> for presets 4-9.
|
||||
* This specifies the method to analyze the data produced by a match finder.
|
||||
* The default is <code>MODE_FAST</code> for presets 0-3 and
|
||||
* <code>MODE_NORMAL</code> for presets 4-9.
|
||||
* <p>
|
||||
* Usually <code>MODE_FAST</code> is used with Hash Chain match finders
|
||||
* and <code>MODE_NORMAL</code> with Binary Tree match finders. This is
|
||||
* also what the presets do.
|
||||
* Usually <code>MODE_FAST</code> is used with Hash Chain match finders and
|
||||
* <code>MODE_NORMAL</code> with Binary Tree match finders. This is also
|
||||
* what the presets do.
|
||||
* <p>
|
||||
* The special mode <code>MODE_UNCOMPRESSED</code> doesn't try to
|
||||
* compress the data at all (and doesn't use a match finder) and will
|
||||
* simply wrap it in uncompressed LZMA2 chunks.
|
||||
* The special mode <code>MODE_UNCOMPRESSED</code> doesn't try to compress
|
||||
* the data at all (and doesn't use a match finder) and will simply wrap it
|
||||
* in uncompressed LZMA2 chunks.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>mode</code> is not supported
|
||||
* @throws UnsupportedOptionsException <code>mode</code> is not supported
|
||||
*/
|
||||
public void setMode(int mode) throws UnsupportedOptionsException {
|
||||
if (mode < MODE_UNCOMPRESSED || mode > MODE_NORMAL)
|
||||
@@ -435,14 +420,12 @@ public class LZMA2Options extends FilterOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the nice length of matches.
|
||||
* Once a match of at least <code>niceLen</code> bytes is found,
|
||||
* the algorithm stops looking for better matches. Higher values tend
|
||||
* to give better compression at the expense of speed. The default
|
||||
* depends on the preset.
|
||||
* Sets the nice length of matches. Once a match of at least
|
||||
* <code>niceLen</code> bytes is found, the algorithm stops looking for
|
||||
* better matches. Higher values tend to give better compression at the
|
||||
* expense of speed. The default depends on the preset.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>niceLen</code> is invalid
|
||||
* @throws UnsupportedOptionsException <code>niceLen</code> is invalid
|
||||
*/
|
||||
public void setNiceLen(int niceLen) throws UnsupportedOptionsException {
|
||||
if (niceLen < NICE_LEN_MIN)
|
||||
@@ -468,13 +451,12 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the match finder type.
|
||||
* <p>
|
||||
* Match finder has a major effect on compression speed, memory usage,
|
||||
* and compression ratio. Usually Hash Chain match finders are faster
|
||||
* than Binary Tree match finders. The default depends on the preset:
|
||||
* 0-3 use <code>MF_HC4</code> and 4-9 use <code>MF_BT4</code>.
|
||||
* Match finder has a major effect on compression speed, memory usage, and
|
||||
* compression ratio. Usually Hash Chain match finders are faster than
|
||||
* Binary Tree match finders. The default depends on the preset: 0-3 use
|
||||
* <code>MF_HC4</code> and 4-9 use <code>MF_BT4</code>.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>mf</code> is not supported
|
||||
* @throws UnsupportedOptionsException <code>mf</code> is not supported
|
||||
*/
|
||||
public void setMatchFinder(int mf) throws UnsupportedOptionsException {
|
||||
if (mf != MF_HC4 && mf != MF_BT4)
|
||||
@@ -494,18 +476,17 @@ public class LZMA2Options extends FilterOptions {
|
||||
/**
|
||||
* Sets the match finder search depth limit.
|
||||
* <p>
|
||||
* The default is a special value of <code>0</code> which indicates that
|
||||
* the depth limit should be automatically calculated by the selected
|
||||
* match finder from the nice length of matches.
|
||||
* The default is a special value of <code>0</code> which indicates that the
|
||||
* depth limit should be automatically calculated by the selected match
|
||||
* finder from the nice length of matches.
|
||||
* <p>
|
||||
* Reasonable depth limit for Hash Chain match finders is 4-100 and
|
||||
* 16-1000 for Binary Tree match finders. Using very high values can
|
||||
* make the compressor extremely slow with some files. Avoid settings
|
||||
* higher than 1000 unless you are prepared to interrupt the compression
|
||||
* in case it is taking far too long.
|
||||
* Reasonable depth limit for Hash Chain match finders is 4-100 and 16-1000
|
||||
* for Binary Tree match finders. Using very high values can make the
|
||||
* compressor extremely slow with some files. Avoid settings higher than
|
||||
* 1000 unless you are prepared to interrupt the compression in case it is
|
||||
* taking far too long.
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* <code>depthLimit</code> is invalid
|
||||
* @throws UnsupportedOptionsException <code>depthLimit</code> is invalid
|
||||
*/
|
||||
public void setDepthLimit(int depthLimit)
|
||||
throws UnsupportedOptionsException {
|
||||
@@ -540,12 +521,12 @@ public class LZMA2Options extends FilterOptions {
|
||||
* 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.
|
||||
* <p>
|
||||
* The returned value may bigger than the value returned by a direct call
|
||||
* to {@link LZMA2InputStream#getMemoryUsage(int)} if the dictionary size
|
||||
* is not 2^n or 2^n + 2^(n-1) bytes. This is because the .xz
|
||||
* headers store the dictionary size in such a format and other values
|
||||
* are rounded up to the next such value. Such rounding is harmess except
|
||||
* it might waste some memory if an unsual dictionary size is used.
|
||||
* The returned value may bigger than the value returned by a direct call to
|
||||
* {@link LZMA2InputStream#getMemoryUsage(int)} if the dictionary size is
|
||||
* not 2^n or 2^n + 2^(n-1) bytes. This is because the .xz headers
|
||||
* store the dictionary size in such a format and other values are rounded
|
||||
* up to the next such value. Such rounding is harmess except it might waste
|
||||
* some memory if an unsual dictionary size is used.
|
||||
* <p>
|
||||
* If you use raw LZMA2 streams and unusual dictioanary size, call
|
||||
* {@link LZMA2InputStream#getMemoryUsage} directly to get raw decoder
|
||||
|
||||
@@ -20,16 +20,16 @@ import org.tukaani.xz.lzma.LZMADecoder;
|
||||
* Decompresses legacy .lzma files and raw LZMA streams (no .lzma header).
|
||||
* <p>
|
||||
* <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
|
||||
* is for example {@link java.io.FileInputStream}, wrapping it into
|
||||
* {@link java.io.BufferedInputStream} tends to improve performance a lot.
|
||||
* This is not automatically done by this class because there may be use
|
||||
* cases where it is desired that this class won't read any bytes past
|
||||
* the end of the LZMA stream.
|
||||
* reads data from its input stream one byte at a time. If the input stream is
|
||||
* for example {@link java.io.FileInputStream}, wrapping it into
|
||||
* {@link java.io.BufferedInputStream} tends to improve performance a lot. This
|
||||
* is not automatically done by this class because there may be use cases where
|
||||
* it is desired that this class won't read any bytes past the end of the LZMA
|
||||
* stream.
|
||||
* <p>
|
||||
* Even when using <code>BufferedInputStream</code>, the performance tends
|
||||
* to be worse (maybe 10-20 % slower) than with {@link LZMA2InputStream}
|
||||
* or {@link XZInputStream} (when the .xz file contains LZMA2-compressed data).
|
||||
* Even when using <code>BufferedInputStream</code>, the performance tends to be
|
||||
* worse (maybe 10-20 % slower) than with {@link LZMA2InputStream} or
|
||||
* {@link XZInputStream} (when the .xz file contains LZMA2-compressed data).
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
@@ -39,10 +39,10 @@ public class LZMAInputStream extends InputStream {
|
||||
* Largest dictionary size supported by this implementation.
|
||||
* <p>
|
||||
* LZMA allows dictionaries up to one byte less than 4 GiB. This
|
||||
* implementation supports only 16 bytes less than 2 GiB. This
|
||||
* limitation is due to Java using signed 32-bit integers for array
|
||||
* indexing. The limitation shouldn't matter much in practice since so
|
||||
* huge dictionaries are not normally used.
|
||||
* implementation supports only 16 bytes less than 2 GiB. This limitation is
|
||||
* due to Java using signed 32-bit integers for array indexing. The
|
||||
* limitation shouldn't matter much in practice since so huge dictionaries
|
||||
* are not normally used.
|
||||
*/
|
||||
public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
|
||||
|
||||
@@ -56,33 +56,29 @@ public class LZMAInputStream extends InputStream {
|
||||
private final byte[] tempBuf = new byte[1];
|
||||
|
||||
/**
|
||||
* Number of uncompressed bytes left to be decompressed, or -1 if
|
||||
* the end marker is used.
|
||||
* Number of uncompressed bytes left to be decompressed, or -1 if the end
|
||||
* marker is used.
|
||||
*/
|
||||
private long remainingSize;
|
||||
|
||||
private IOException exception = null;
|
||||
|
||||
/**
|
||||
* Gets approximate decompressor memory requirements as kibibytes for
|
||||
* the given dictionary size and LZMA properties byte (lc, lp, and pb).
|
||||
* Gets approximate decompressor memory requirements as kibibytes for the
|
||||
* given dictionary size and LZMA properties byte (lc, lp, and pb).
|
||||
*
|
||||
* @param dictSize LZMA dictionary size as bytes, should be
|
||||
* in the range [<code>0</code>,
|
||||
* <code>DICT_SIZE_MAX</code>]
|
||||
* @param dictSize LZMA dictionary size as bytes, should be in the range
|
||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @param propsByte LZMA properties byte that encodes the values
|
||||
* of lc, lp, and pb
|
||||
* @param propsByte LZMA properties byte that encodes the values of lc, lp,
|
||||
* and pb
|
||||
*
|
||||
* @return approximate memory requirements as kibibytes (KiB)
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* if <code>dictSize</code> is outside
|
||||
* the range [<code>0</code>,
|
||||
* <code>DICT_SIZE_MAX</code>]
|
||||
* @throws UnsupportedOptionsException if <code>dictSize</code> is outside
|
||||
* the range [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* if <code>propsByte</code> is invalid
|
||||
* @throws CorruptedInputException if <code>propsByte</code> is invalid
|
||||
*/
|
||||
public static int getMemoryUsage(int dictSize, byte propsByte)
|
||||
throws UnsupportedOptionsException, CorruptedInputException {
|
||||
@@ -102,18 +98,17 @@ public class LZMAInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets approximate decompressor memory requirements as kibibytes for
|
||||
* the given dictionary size, lc, and lp. Note that pb isn't needed.
|
||||
* Gets approximate decompressor memory requirements as kibibytes for the
|
||||
* given dictionary size, lc, and lp. Note that pb isn't needed.
|
||||
*
|
||||
* @param dictSize LZMA dictionary size as bytes, must be
|
||||
* in the range [<code>0</code>,
|
||||
* <code>DICT_SIZE_MAX</code>]
|
||||
* @param dictSize LZMA dictionary size as bytes, must be in the range
|
||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @param lc number of literal context bits, must be
|
||||
* in the range [0, 8]
|
||||
* @param lc number of literal context bits, must be in the range [0,
|
||||
* 8]
|
||||
*
|
||||
* @param lp number of literal position bits, must be
|
||||
* in the range [0, 4]
|
||||
* @param lp number of literal position bits, must be in the range [0,
|
||||
* 4]
|
||||
*
|
||||
* @return approximate memory requirements as kibibytes (KiB)
|
||||
*/
|
||||
@@ -156,25 +151,22 @@ public class LZMAInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new .lzma file format decompressor without
|
||||
* a memory usage limit.
|
||||
* Creates a new .lzma file format decompressor without a memory usage
|
||||
* limit.
|
||||
*
|
||||
* @param in input stream from which .lzma data is read;
|
||||
* it might be a good idea to wrap it in
|
||||
* <code>BufferedInputStream</code>, see the
|
||||
* note at the top of this page
|
||||
* @param in input stream from which .lzma data is read; it might be a good
|
||||
* idea to wrap it in <code>BufferedInputStream</code>, see the note at the
|
||||
* top of this page
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* file is corrupt or perhaps not in
|
||||
* the .lzma format at all
|
||||
* @throws CorruptedInputException file is corrupt or perhaps not in the
|
||||
* .lzma format at all
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* dictionary size or uncompressed size is too
|
||||
* big for this implementation
|
||||
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||
* is too big for this implementation
|
||||
*
|
||||
* @throws EOFException
|
||||
* file is truncated or perhaps not in
|
||||
* the .lzma format at all
|
||||
* @throws EOFException file is truncated or perhaps not in
|
||||
* the .lzma format
|
||||
* at all
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -183,32 +175,28 @@ public class LZMAInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new .lzma file format decompressor with an optional
|
||||
* memory usage limit.
|
||||
* Creates a new .lzma file format decompressor with an optional memory
|
||||
* usage limit.
|
||||
*
|
||||
* @param in input stream from which .lzma data is read;
|
||||
* it might be a good idea to wrap it in
|
||||
* <code>BufferedInputStream</code>, see the
|
||||
* note at the top of this page
|
||||
* @param in input stream from which .lzma data is read; it might
|
||||
* be a good
|
||||
* idea to wrap it in <code>BufferedInputStream</code>, see the note at the
|
||||
* top of this page
|
||||
*
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
||||
* or <code>-1</code> to impose no
|
||||
* memory usage limit
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||
* <code>-1</code> to impose no memory usage limit
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* file is corrupt or perhaps not in
|
||||
* the .lzma format at all
|
||||
* @throws CorruptedInputException file is corrupt or perhaps not in the
|
||||
* .lzma format at all
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* dictionary size or uncompressed size is too
|
||||
* big for this implementation
|
||||
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||
* is too big for this implementation
|
||||
*
|
||||
* @throws MemoryLimitException
|
||||
* memory usage limit was exceeded
|
||||
* @throws MemoryLimitException memory usage limit was exceeded
|
||||
*
|
||||
* @throws EOFException
|
||||
* file is truncated or perhaps not in
|
||||
* the .lzma format at all
|
||||
* @throws EOFException file is truncated or perhaps not in
|
||||
* the .lzma format
|
||||
* at all
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -244,45 +232,43 @@ public class LZMAInputStream extends InputStream {
|
||||
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
||||
* header) from <code>in</code>.
|
||||
* <p>
|
||||
* The caller needs to know if the "end of payload marker (EOPM)" alias
|
||||
* "end of stream marker (EOS marker)" alias "end marker" present.
|
||||
* If the end marker isn't used, the caller must know the exact
|
||||
* uncompressed size of the stream.
|
||||
* The caller needs to know if the "end of payload marker (EOPM)" alias "end
|
||||
* of stream marker (EOS marker)" alias "end marker" present. If the end
|
||||
* marker isn't used, the caller must know the exact uncompressed size of
|
||||
* the stream.
|
||||
* <p>
|
||||
* The caller also needs to provide the LZMA properties byte that encodes
|
||||
* the number of literal context bits (lc), literal position bits (lp),
|
||||
* and position bits (pb).
|
||||
* the number of literal context bits (lc), literal position bits (lp), and
|
||||
* position bits (pb).
|
||||
* <p>
|
||||
* The dictionary size used when compressing is also needed. Specifying
|
||||
* a too small dictionary size will prevent decompressing the stream.
|
||||
* Specifying a too big dictionary is waste of memory but decompression
|
||||
* will work.
|
||||
* The dictionary size used when compressing is also needed. Specifying a
|
||||
* too small dictionary size will prevent decompressing the stream.
|
||||
* Specifying a too big dictionary is waste of memory but decompression will
|
||||
* work.
|
||||
* <p>
|
||||
* There is no need to specify a dictionary bigger than
|
||||
* the uncompressed size of the data even if a bigger dictionary
|
||||
* was used when compressing. If you know the uncompressed size
|
||||
* of the data, this might allow saving some memory.
|
||||
* There is no need to specify a dictionary bigger than the uncompressed
|
||||
* size of the data even if a bigger dictionary was used when compressing.
|
||||
* If you know the uncompressed size of the data, this might allow saving
|
||||
* some memory.
|
||||
*
|
||||
* @param in input stream from which compressed
|
||||
* data is read
|
||||
* @param in input stream from which compressed data is read
|
||||
*
|
||||
* @param uncompSize uncompressed size of the LZMA stream or -1
|
||||
* if the end marker is used in the LZMA stream
|
||||
* @param uncompSize uncompressed size of the LZMA stream or -1 if the end
|
||||
* marker is used in the LZMA stream
|
||||
*
|
||||
* @param propsByte LZMA properties byte that has the encoded
|
||||
* values for literal context bits (lc), literal
|
||||
* position bits (lp), and position bits (pb)
|
||||
* @param propsByte LZMA properties byte that has the encoded values for
|
||||
* literal context bits (lc), literal position bits (lp), and position bits
|
||||
* (pb)
|
||||
*
|
||||
* @param dictSize dictionary size as bytes, must be in the range
|
||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* if <code>propsByte</code> is invalid or
|
||||
* @throws CorruptedInputException if <code>propsByte</code> is invalid
|
||||
* or
|
||||
* the first input byte is not 0x00
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* dictionary size or uncompressed size is too
|
||||
* big for this implementation
|
||||
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||
* is too 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
|
||||
* header) from <code>in</code> optionally with a preset dictionary.
|
||||
*
|
||||
* @param in input stream from which LZMA-compressed
|
||||
* data is read
|
||||
* @param in input stream from which LZMA-compressed data is read
|
||||
*
|
||||
* @param uncompSize uncompressed size of the LZMA stream or -1
|
||||
* if the end marker is used in the LZMA stream
|
||||
* @param uncompSize uncompressed size of the LZMA stream or -1 if the end
|
||||
* marker is used in the LZMA stream
|
||||
*
|
||||
* @param propsByte LZMA properties byte that has the encoded
|
||||
* values for literal context bits (lc), literal
|
||||
* position bits (lp), and position bits (pb)
|
||||
* @param propsByte LZMA properties byte that has the encoded values for
|
||||
* literal context bits (lc), literal position bits (lp), and position bits
|
||||
* (pb)
|
||||
*
|
||||
* @param dictSize dictionary size as bytes, must be in the range
|
||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @param presetDict preset dictionary or <code>null</code>
|
||||
* to use no preset dictionary
|
||||
* @param presetDict preset dictionary or <code>null</code> to use no preset
|
||||
* dictionary
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* if <code>propsByte</code> is invalid or
|
||||
* @throws CorruptedInputException if <code>propsByte</code> is invalid
|
||||
* or
|
||||
* the first input byte is not 0x00
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* dictionary size or uncompressed size is too
|
||||
* big for this implementation
|
||||
* @throws UnsupportedOptionsException dictionary size or uncompressed size
|
||||
* is too big for this implementation
|
||||
*
|
||||
* @throws EOFException file is truncated or corrupt
|
||||
*
|
||||
@@ -333,29 +317,26 @@ public class LZMAInputStream extends InputStream {
|
||||
* Creates a new input stream that decompresses raw LZMA data (no .lzma
|
||||
* header) from <code>in</code> optionally with a preset dictionary.
|
||||
*
|
||||
* @param in input stream from which LZMA-compressed
|
||||
* data is read
|
||||
* @param in input stream from which LZMA-compressed data is read
|
||||
*
|
||||
* @param uncompSize uncompressed size of the LZMA stream or -1
|
||||
* if the end marker is used in the LZMA stream
|
||||
* @param uncompSize uncompressed size of the LZMA stream or -1 if the end
|
||||
* marker is used in the LZMA stream
|
||||
*
|
||||
* @param lc number of literal context bits, must be
|
||||
* in the range [0, 8]
|
||||
* @param lc number of literal context bits, must be in the range
|
||||
* [0, 8]
|
||||
*
|
||||
* @param lp number of literal position bits, must be
|
||||
* in the range [0, 4]
|
||||
* @param lp number of literal position bits, must be in the range
|
||||
* [0, 4]
|
||||
*
|
||||
* @param pb number position bits, must be
|
||||
* in the range [0, 4]
|
||||
* @param pb number position bits, must be in the range [0, 4]
|
||||
*
|
||||
* @param dictSize dictionary size as bytes, must be in the range
|
||||
* [<code>0</code>, <code>DICT_SIZE_MAX</code>]
|
||||
*
|
||||
* @param presetDict preset dictionary or <code>null</code>
|
||||
* to use no preset dictionary
|
||||
* @param presetDict preset dictionary or <code>null</code> to use no preset
|
||||
* dictionary
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* if the first input byte is not 0x00
|
||||
* @throws CorruptedInputException if the first input byte is not 0x00
|
||||
*
|
||||
* @throws EOFException file is truncated or corrupt
|
||||
*
|
||||
@@ -424,19 +405,18 @@ public class LZMAInputStream extends InputStream {
|
||||
/**
|
||||
* Decompresses the next byte from this input stream.
|
||||
* <p>
|
||||
* Reading lots of data with <code>read()</code> from this input stream
|
||||
* may be inefficient. Wrap it in <code>java.io.BufferedInputStream</code>
|
||||
* if you need to read lots of data one byte at a time.
|
||||
* Reading lots of data with <code>read()</code> from this input stream may
|
||||
* be inefficient. Wrap it in <code>java.io.BufferedInputStream</code> if
|
||||
* you need to read lots of data one byte at a time.
|
||||
*
|
||||
* @return the next decompressed byte, or <code>-1</code>
|
||||
* to indicate the end of the compressed stream
|
||||
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||
* end of the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or corrupt
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -447,17 +427,17 @@ public class LZMAInputStream extends InputStream {
|
||||
/**
|
||||
* Decompresses into an array of bytes.
|
||||
* <p>
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
||||
* is returned. Otherwise this will block until <code>len</code>
|
||||
* bytes have been decompressed, the end of the LZMA stream is reached,
|
||||
* or an exception is thrown.
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||
* returned. Otherwise this will block until <code>len</code> bytes have
|
||||
* been decompressed, the end of the LZMA stream is reached, or an exception
|
||||
* is thrown.
|
||||
*
|
||||
* @param buf target buffer for uncompressed data
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len maximum number of uncompressed bytes to read
|
||||
*
|
||||
* @return number of bytes read, or <code>-1</code> to indicate
|
||||
* the end of the compressed stream
|
||||
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||
* the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
*
|
||||
@@ -552,8 +532,8 @@ public class LZMAInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and calls <code>in.close()</code>.
|
||||
* If the stream was already closed, this does nothing.
|
||||
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||
* already closed, this does nothing.
|
||||
*
|
||||
* @throws IOException if thrown by <code>in.close()</code>
|
||||
*/
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
package org.tukaani.xz;
|
||||
|
||||
/**
|
||||
* Thrown when the memory usage limit given to the XZ decompressor
|
||||
* would be exceeded.
|
||||
* Thrown when the memory usage limit given to the XZ decompressor would be
|
||||
* exceeded.
|
||||
* <p>
|
||||
* The amount of memory required and the memory usage limit are
|
||||
* included in the error detail message in human readable format.
|
||||
* The amount of memory required and the memory usage limit are included in the
|
||||
* error detail message in human readable format.
|
||||
*/
|
||||
public class MemoryLimitException extends XZIOException {
|
||||
|
||||
@@ -25,8 +25,8 @@ public class MemoryLimitException extends XZIOException {
|
||||
/**
|
||||
* Creates a new MemoryLimitException.
|
||||
* <p>
|
||||
* The amount of memory needed and the memory usage limit are
|
||||
* included in the error detail message.
|
||||
* The amount of memory needed and the memory usage limit are included in
|
||||
* the error detail message.
|
||||
*
|
||||
* @param memoryNeeded amount of memory needed 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
|
||||
* was created.
|
||||
* Gets what the memory usage limit was at the time the exception was
|
||||
* created.
|
||||
*
|
||||
* @return memory usage limit as kibibytes (KiB)
|
||||
*/
|
||||
|
||||
@@ -14,14 +14,14 @@ import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
/**
|
||||
* Wraps a {@link java.io.RandomAccessFile RandomAccessFile}
|
||||
* in a SeekableInputStream.
|
||||
* Wraps a {@link java.io.RandomAccessFile RandomAccessFile} in a
|
||||
* SeekableInputStream.
|
||||
*/
|
||||
public class SeekableFileInputStream extends SeekableInputStream {
|
||||
|
||||
/**
|
||||
* The RandomAccessFile that has been wrapped
|
||||
* into a SeekableFileInputStream.
|
||||
* The RandomAccessFile that has been wrapped into a
|
||||
* SeekableFileInputStream.
|
||||
*/
|
||||
protected RandomAccessFile randomAccessFile;
|
||||
|
||||
@@ -33,8 +33,8 @@ public class SeekableFileInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new seekable input stream that reads from a file with
|
||||
* the specified name.
|
||||
* Creates a new seekable input stream that reads from a file with the
|
||||
* specified name.
|
||||
*/
|
||||
public SeekableFileInputStream(String name) throws FileNotFoundException {
|
||||
randomAccessFile = new RandomAccessFile(name, "r");
|
||||
@@ -63,8 +63,7 @@ public class SeekableFileInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls
|
||||
* {@link RandomAccessFile#read(byte[],int,int)
|
||||
* Calls null null null null null null null null null null null {@link RandomAccessFile#read(byte[],int,int)
|
||||
* randomAccessFile.read(buf, off, len)}.
|
||||
*/
|
||||
public int read(byte[] buf, int off, int len) throws IOException {
|
||||
|
||||
@@ -19,22 +19,21 @@ public abstract class SeekableInputStream extends InputStream {
|
||||
/**
|
||||
* Seeks <code>n</code> bytes forward in this stream.
|
||||
* <p>
|
||||
* This will not seek past the end of the file. If the current position
|
||||
* is already at or past the end of the file, this doesn't seek at all
|
||||
* and returns <code>0</code>. Otherwise, if skipping <code>n</code> bytes
|
||||
* would cause the position to exceed the stream size, this will do
|
||||
* equivalent of <code>seek(length())</code> and the return value will
|
||||
* be adjusted accordingly.
|
||||
* This will not seek past the end of the file. If the current position is
|
||||
* already at or past the end of the file, this doesn't seek at all and
|
||||
* returns <code>0</code>. Otherwise, if skipping <code>n</code> bytes would
|
||||
* cause the position to exceed the stream size, this will do equivalent of
|
||||
* <code>seek(length())</code> and the return value will be adjusted
|
||||
* accordingly.
|
||||
* <p>
|
||||
* If <code>n</code> is negative, the position isn't changed and
|
||||
* the return value is <code>0</code>. It doesn't seek backward
|
||||
* because it would conflict with the specification of
|
||||
* If <code>n</code> is negative, the position isn't changed and the return
|
||||
* value is <code>0</code>. It doesn't seek backward because it would
|
||||
* conflict with the specification of
|
||||
* {@link java.io.InputStream#skip(long) InputStream.skip}.
|
||||
*
|
||||
* @return <code>0</code> if <code>n</code> is negative,
|
||||
* less than <code>n</code> if skipping <code>n</code>
|
||||
* bytes would seek past the end of the file,
|
||||
* <code>n</code> otherwise
|
||||
* @return <code>0</code> if <code>n</code> is negative, less than
|
||||
* <code>n</code> if skipping <code>n</code> bytes would seek past the end
|
||||
* of the file, <code>n</code> otherwise
|
||||
*
|
||||
* @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.
|
||||
* <p>
|
||||
* 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
|
||||
* past the end of the stream, <code>read</code> will return
|
||||
* <code>-1</code> to indicate end of stream.
|
||||
* unless there is a good reason to do otherwise. If one has seeked past the
|
||||
* end of the stream, <code>read</code> will return <code>-1</code> to
|
||||
* indicate end of stream.
|
||||
*
|
||||
* @param pos new read position in the stream
|
||||
*
|
||||
* @throws IOException if <code>pos</code> is negative or if
|
||||
* a stream-specific I/O error occurs
|
||||
* @throws IOException if <code>pos</code> is negative or if a
|
||||
* stream-specific I/O error occurs
|
||||
*/
|
||||
public abstract void seek(long pos) throws IOException;
|
||||
}
|
||||
|
||||
@@ -20,53 +20,52 @@ import org.tukaani.xz.index.IndexDecoder;
|
||||
import org.tukaani.xz.index.BlockInfo;
|
||||
|
||||
/**
|
||||
* Decompresses a .xz file in random access mode.
|
||||
* This supports decompressing concatenated .xz files.
|
||||
* Decompresses a .xz file in random access mode. This supports decompressing
|
||||
* concatenated .xz files.
|
||||
* <p>
|
||||
* Each .xz file consist of one or more Streams. Each Stream consist of zero
|
||||
* or more Blocks. Each Stream contains an Index of Streams' Blocks.
|
||||
* The Indexes from all Streams are loaded in RAM by a constructor of this
|
||||
* class. A typical .xz file has only one Stream, and parsing its Index will
|
||||
* need only three or four seeks.
|
||||
* Each .xz file consist of one or more Streams. Each Stream consist of zero or
|
||||
* more Blocks. Each Stream contains an Index of Streams' Blocks. The Indexes
|
||||
* from all Streams are loaded in RAM by a constructor of this class. A typical
|
||||
* .xz file has only one Stream, and parsing its Index will need only three or
|
||||
* four seeks.
|
||||
* <p>
|
||||
* To make random access possible, the data in a .xz file must be splitted
|
||||
* into multiple Blocks of reasonable size. Decompression can only start at
|
||||
* a Block boundary. When seeking to an uncompressed position that is not at
|
||||
* a Block boundary, decompression starts at the beginning of the Block and
|
||||
* throws away data until the target position is reached. Thus, smaller Blocks
|
||||
* mean faster seeks to arbitrary uncompressed positions. On the other hand,
|
||||
* smaller Blocks mean worse compression. So one has to make a compromise
|
||||
* between random access speed and compression ratio.
|
||||
* To make random access possible, the data in a .xz file must be splitted into
|
||||
* multiple Blocks of reasonable size. Decompression can only start at a Block
|
||||
* boundary. When seeking to an uncompressed position that is not at a Block
|
||||
* boundary, decompression starts at the beginning of the Block and throws away
|
||||
* data until the target position is reached. Thus, smaller Blocks mean faster
|
||||
* seeks to arbitrary uncompressed positions. On the other hand, smaller Blocks
|
||||
* mean worse compression. So one has to make a compromise between random access
|
||||
* speed and compression ratio.
|
||||
* <p>
|
||||
* Implementation note: This class uses linear search to locate the correct
|
||||
* Stream from the data structures in RAM. It was the simplest to implement
|
||||
* and should be fine as long as there aren't too many Streams. The correct
|
||||
* Block inside a Stream is located using binary search and thus is fast
|
||||
* even with a huge number of Blocks.
|
||||
* Stream from the data structures in RAM. It was the simplest to implement and
|
||||
* should be fine as long as there aren't too many Streams. The correct Block
|
||||
* inside a Stream is located using binary search and thus is fast even with a
|
||||
* huge number of Blocks.
|
||||
*
|
||||
* <h4>Memory usage</h4>
|
||||
* <p>
|
||||
* 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
|
||||
* least 1 KiB of memory and each Block 16 bytes of memory, rounded up
|
||||
* to the next kibibyte. So unless the file has a huge number of Streams or
|
||||
* Blocks, these don't take significant amount of memory.
|
||||
* checking the memory usage limit. Each Stream is calculated to need at least
|
||||
* 1 KiB of memory and each Block 16 bytes of memory, rounded up to the
|
||||
* next kibibyte. So unless the file has a huge number of Streams or Blocks,
|
||||
* these don't take significant amount of memory.
|
||||
*
|
||||
* <h4>Creating random-accessible .xz files</h4>
|
||||
* <p>
|
||||
* When using {@link XZOutputStream}, a new Block can be started by calling
|
||||
* its {@link XZOutputStream#endBlock() endBlock} method. If you know
|
||||
* that the decompressor will only need to seek to certain uncompressed
|
||||
* positions, it can be a good idea to start a new Block at (some of) these
|
||||
* positions (and only at these positions to get better compression ratio).
|
||||
* When using {@link XZOutputStream}, a new Block can be started by calling its
|
||||
* {@link XZOutputStream#endBlock() endBlock} method. If you know that the
|
||||
* decompressor will only need to seek to certain uncompressed positions, it can
|
||||
* be a good idea to start a new Block at (some of) these positions (and only at
|
||||
* these positions to get better compression ratio).
|
||||
* <p>
|
||||
* liblzma in XZ Utils supports starting a new Block with
|
||||
* <code>LZMA_FULL_FLUSH</code>. XZ Utils 5.1.1alpha added threaded
|
||||
* compression which creates multi-Block .xz files. XZ Utils 5.1.1alpha
|
||||
* also added the option <code>--block-size=SIZE</code> to the xz command
|
||||
* line tool. XZ Utils 5.1.2alpha added a partial implementation of
|
||||
* <code>--block-list=SIZES</code> which allows specifying sizes of
|
||||
* individual Blocks.
|
||||
* <code>LZMA_FULL_FLUSH</code>. XZ Utils 5.1.1alpha added threaded compression
|
||||
* which creates multi-Block .xz files. XZ Utils 5.1.1alpha also added the
|
||||
* option <code>--block-size=SIZE</code> to the xz command line tool. XZ Utils
|
||||
* 5.1.2alpha added a partial implementation of <code>--block-list=SIZES</code>
|
||||
* which allows specifying sizes of individual Blocks.
|
||||
*
|
||||
* @see SeekableFileInputStream
|
||||
* @see XZInputStream
|
||||
@@ -80,22 +79,21 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
private SeekableInputStream in;
|
||||
|
||||
/**
|
||||
* Memory usage limit after the memory usage of the IndexDecoders have
|
||||
* been substracted.
|
||||
* Memory usage limit after the memory usage of the IndexDecoders have been
|
||||
* substracted.
|
||||
*/
|
||||
private final int memoryLimit;
|
||||
|
||||
/**
|
||||
* Memory usage of the IndexDecoders.
|
||||
* <code>memoryLimit + indexMemoryUsage</code> equals the original
|
||||
* memory usage limit that was passed to the constructor.
|
||||
* <code>memoryLimit + indexMemoryUsage</code> equals the original memory
|
||||
* usage limit that was passed to the constructor.
|
||||
*/
|
||||
private int indexMemoryUsage = 0;
|
||||
|
||||
/**
|
||||
* List of IndexDecoders, one for each Stream in the file.
|
||||
* The list is in reverse order: The first element is
|
||||
* the last Stream in the file.
|
||||
* List of IndexDecoders, one for each Stream in the file. The list is in
|
||||
* reverse order: The first element is the last Stream in the file.
|
||||
*/
|
||||
private final ArrayList streams = new ArrayList();
|
||||
|
||||
@@ -120,20 +118,20 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
private int blockCount = 0;
|
||||
|
||||
/**
|
||||
* Size and position information about the current Block.
|
||||
* If there are no Blocks, all values will be <code>-1</code>.
|
||||
* Size and position information about the current Block. If there are no
|
||||
* Blocks, all values will be <code>-1</code>.
|
||||
*/
|
||||
private final BlockInfo curBlockInfo;
|
||||
|
||||
/**
|
||||
* Temporary (and cached) information about the Block whose information
|
||||
* is queried via <code>getBlockPos</code> and related functions.
|
||||
* Temporary (and cached) information about the Block whose information is
|
||||
* queried via <code>getBlockPos</code> and related functions.
|
||||
*/
|
||||
private final BlockInfo queriedBlockInfo;
|
||||
|
||||
/**
|
||||
* Integrity Check in the current XZ Stream. The constructor leaves
|
||||
* this to point to the Check of the first Stream.
|
||||
* Integrity Check in the current XZ Stream. The constructor leaves this to
|
||||
* point to the Check of the first Stream.
|
||||
*/
|
||||
private Check check;
|
||||
|
||||
@@ -153,14 +151,14 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
private long seekPos;
|
||||
|
||||
/**
|
||||
* True when <code>seek(long)</code> has been called but the actual
|
||||
* seeking hasn't been done yet.
|
||||
* True when <code>seek(long)</code> has been called but the actual seeking
|
||||
* hasn't been done yet.
|
||||
*/
|
||||
private boolean seekNeeded = false;
|
||||
|
||||
/**
|
||||
* True when end of the file was reached. This can be cleared by
|
||||
* calling <code>seek(long)</code>.
|
||||
* True when end of the file was reached. This can be cleared by calling
|
||||
* <code>seek(long)</code>.
|
||||
*/
|
||||
private boolean endReached = false;
|
||||
|
||||
@@ -170,32 +168,28 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
private IOException exception = null;
|
||||
|
||||
/**
|
||||
* Temporary buffer for read(). This avoids reallocating memory
|
||||
* on every read() call.
|
||||
* Temporary buffer for read(). This avoids reallocating memory on every
|
||||
* read() call.
|
||||
*/
|
||||
private final byte[] tempBuf = new byte[1];
|
||||
|
||||
/**
|
||||
* Creates a new seekable XZ decompressor without a memory usage limit.
|
||||
*
|
||||
* @param in seekable input stream containing one or more
|
||||
* XZ Streams; the whole input stream is used
|
||||
* @param in seekable input stream containing one or more XZ Streams; the
|
||||
* whole input stream is used
|
||||
*
|
||||
* @throws XZFormatException
|
||||
* input is not in the XZ format
|
||||
* @throws XZFormatException input is not in the XZ format
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* XZ data is corrupt or truncated
|
||||
* @throws CorruptedInputException XZ data is corrupt or truncated
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* XZ headers seem valid but they specify
|
||||
* options not supported by this implementation
|
||||
* @throws UnsupportedOptionsException XZ headers seem valid but they
|
||||
* specify options not supported by this implementation
|
||||
*
|
||||
* @throws EOFException
|
||||
* less than 6 bytes of input was available
|
||||
* from <code>in</code>, or (unlikely) the size
|
||||
* of the underlying stream got smaller while
|
||||
* this was reading from it
|
||||
* @throws EOFException less than 6 bytes of input was
|
||||
* available from
|
||||
* <code>in</code>, or (unlikely) the size of the underlying stream got
|
||||
* smaller while this was reading from it
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -205,35 +199,31 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new seekable XZ decomporessor with an optional
|
||||
* memory usage limit.
|
||||
* Creates a new seekable XZ decomporessor with an optional memory usage
|
||||
* limit.
|
||||
*
|
||||
* @param in seekable input stream containing one or more
|
||||
* XZ Streams; the whole input stream is used
|
||||
* @param in seekable input stream containing one or more XZ
|
||||
* Streams; the
|
||||
* whole input stream is used
|
||||
*
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
||||
* or <code>-1</code> to impose no
|
||||
* memory usage limit
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||
* <code>-1</code> to impose no memory usage limit
|
||||
*
|
||||
* @throws XZFormatException
|
||||
* input is not in the XZ format
|
||||
* @throws XZFormatException input is not in the XZ format
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* XZ data is corrupt or truncated
|
||||
* @throws CorruptedInputException XZ data is corrupt or truncated
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* XZ headers seem valid but they specify
|
||||
* options not supported by this implementation
|
||||
* @throws UnsupportedOptionsException XZ headers seem valid but they
|
||||
* specify options not supported by this implementation
|
||||
*
|
||||
* @throws MemoryLimitException
|
||||
* decoded XZ Indexes would need more memory
|
||||
* @throws MemoryLimitException decoded XZ Indexes would need more
|
||||
* memory
|
||||
* than allowed by the memory usage limit
|
||||
*
|
||||
* @throws EOFException
|
||||
* less than 6 bytes of input was available
|
||||
* from <code>in</code>, or (unlikely) the size
|
||||
* of the underlying stream got smaller while
|
||||
* this was reading from it
|
||||
* @throws EOFException less than 6 bytes of input was
|
||||
* available from
|
||||
* <code>in</code>, or (unlikely) the size of the underlying stream got
|
||||
* smaller while this was reading from it
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -391,13 +381,11 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the types of integrity checks used in the .xz file.
|
||||
* Multiple checks are possible only if there are multiple
|
||||
* concatenated XZ Streams.
|
||||
* Gets the types of integrity checks used in the .xz file. Multiple checks
|
||||
* are possible only if there are multiple concatenated XZ Streams.
|
||||
* <p>
|
||||
* 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
|
||||
* <code>(1 << XZ.CHECK_CRC64)
|
||||
* For example, if CRC64 and SHA-256 were used, the return value is <code>(1 << XZ.CHECK_CRC64)
|
||||
* | (1 << XZ.CHECK_SHA256)</code>.
|
||||
*/
|
||||
public int getCheckTypes() {
|
||||
@@ -405,22 +393,21 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of memory in kibibytes (KiB) used by
|
||||
* the data structures needed to locate the XZ Blocks.
|
||||
* This is usually useless information but since it is calculated
|
||||
* for memory usage limit anyway, it is nice to make it available to too.
|
||||
* Gets the amount of memory in kibibytes (KiB) used by the data structures
|
||||
* needed to locate the XZ Blocks. This is usually useless information but
|
||||
* since it is calculated for memory usage limit anyway, it is nice to make
|
||||
* it available to too.
|
||||
*/
|
||||
public int getIndexMemoryUsage() {
|
||||
return indexMemoryUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the uncompressed size of the largest XZ Block in bytes.
|
||||
* This can be useful if you want to check that the file doesn't
|
||||
* have huge XZ Blocks which could make seeking to arbitrary offsets
|
||||
* very slow. Note that huge Blocks don't automatically mean that
|
||||
* seeking would be slow, for example, seeking to the beginning of
|
||||
* any Block is always fast.
|
||||
* Gets the uncompressed size of the largest XZ Block in bytes. This can be
|
||||
* useful if you want to check that the file doesn't have huge XZ Blocks
|
||||
* which could make seeking to arbitrary offsets very slow. Note that huge
|
||||
* Blocks don't automatically mean that seeking would be slow, for example,
|
||||
* seeking to the beginning of any Block is always fast.
|
||||
*/
|
||||
public long getLargestBlockSize() {
|
||||
return largestBlockSize;
|
||||
@@ -473,9 +460,9 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position where the given compressed Block starts in
|
||||
* the underlying .xz file.
|
||||
* This information is rarely useful to the users of this class.
|
||||
* Gets the position where the given compressed Block starts in the
|
||||
* underlying .xz file. This information is rarely useful to the users of
|
||||
* this class.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* <code>blockNumber < 0</code> or
|
||||
@@ -489,9 +476,9 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compressed size of the given Block.
|
||||
* This together with the uncompressed size can be used to calculate
|
||||
* the compression ratio of the specific Block.
|
||||
* Gets the compressed size of the given Block. This together with the
|
||||
* uncompressed size can be used to calculate the compression ratio of the
|
||||
* specific Block.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* <code>blockNumber < 0</code> or
|
||||
@@ -524,8 +511,7 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
* Gets the number of the Block that contains the byte at the given
|
||||
* uncompressed position.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* <code>pos < 0</code> or
|
||||
* @throws IndexOutOfBoundsException if <code>pos < 0</code> or
|
||||
* <code>pos >= length()</code>.
|
||||
*
|
||||
* @since 1.3
|
||||
@@ -538,8 +524,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
/**
|
||||
* Decompresses the next byte from this input stream.
|
||||
*
|
||||
* @return the next decompressed byte, or <code>-1</code>
|
||||
* to indicate the end of the compressed stream
|
||||
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||
* end of the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* @throws UnsupportedOptionsException
|
||||
@@ -556,16 +542,16 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
/**
|
||||
* Decompresses into an array of bytes.
|
||||
* <p>
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
||||
* is returned. Otherwise this will try to decompress <code>len</code>
|
||||
* bytes of uncompressed data. Less than <code>len</code> bytes may
|
||||
* be read only in the following situations:
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||
* returned. Otherwise this will try to decompress <code>len</code> bytes of
|
||||
* uncompressed data. Less than <code>len</code> bytes may be read only in
|
||||
* the following situations:
|
||||
* <ul>
|
||||
* <li>The end of the compressed data was reached successfully.</li>
|
||||
* <li>An error is detected after at least one but less than
|
||||
* <code>len</code> bytes have already been successfully
|
||||
* decompressed. The next call with non-zero <code>len</code>
|
||||
* will immediately throw the pending exception.</li>
|
||||
* <code>len</code> bytes have already been successfully decompressed. The
|
||||
* next call with non-zero <code>len</code> will immediately throw the
|
||||
* pending exception.</li>
|
||||
* <li>An exception is thrown.</li>
|
||||
* </ul>
|
||||
*
|
||||
@@ -573,8 +559,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len maximum number of uncompressed bytes to read
|
||||
*
|
||||
* @return number of bytes read, or <code>-1</code> to indicate
|
||||
* the end of the compressed stream
|
||||
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||
* the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* @throws UnsupportedOptionsException
|
||||
@@ -639,15 +625,14 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of uncompressed bytes that can be read
|
||||
* without blocking. The value is returned with an assumption
|
||||
* that the compressed input data will be valid. If the compressed
|
||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
||||
* thrown before the number of bytes claimed to be available have
|
||||
* been read from this input stream.
|
||||
* Returns the number of uncompressed bytes that can be read without
|
||||
* blocking. The value is returned with an assumption that the compressed
|
||||
* input data will be valid. If the compressed data is corrupt,
|
||||
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||
* bytes claimed to be available have been read from this input stream.
|
||||
*
|
||||
* @return the number of uncompressed bytes that can be read
|
||||
* without blocking
|
||||
* @return the number of uncompressed bytes that can be read without
|
||||
* blocking
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
if (in == null)
|
||||
@@ -663,8 +648,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and calls <code>in.close()</code>.
|
||||
* If the stream was already closed, this does nothing.
|
||||
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||
* already closed, this does nothing.
|
||||
*
|
||||
* @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
|
||||
* XZ Streams, the total uncompressed size of all XZ Streams is returned.
|
||||
* Gets the uncompressed size of this input stream. If there are multiple XZ
|
||||
* Streams, the total uncompressed size of all XZ Streams is returned.
|
||||
*/
|
||||
public long length() {
|
||||
return uncompressedSize;
|
||||
@@ -698,20 +683,19 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to the specified absolute uncompressed position in the stream.
|
||||
* This only stores the new position, so this function itself is always
|
||||
* very fast. The actual seek is done when <code>read</code> is called
|
||||
* to read at least one byte.
|
||||
* Seeks to the specified absolute uncompressed position in the stream. This
|
||||
* only stores the new position, so this function itself is always very
|
||||
* fast. The actual seek is done when <code>read</code> is called to read at
|
||||
* least one byte.
|
||||
* <p>
|
||||
* Seeking past the end of the stream is possible. In that case
|
||||
* <code>read</code> will return <code>-1</code> to indicate
|
||||
* the end of the stream.
|
||||
* <code>read</code> will return <code>-1</code> to indicate the end of the
|
||||
* stream.
|
||||
*
|
||||
* @param pos new uncompressed read position
|
||||
*
|
||||
* @throws XZIOException
|
||||
* if <code>pos</code> is negative, or
|
||||
* if stream has been closed
|
||||
* @throws XZIOException if <code>pos</code> is negative, or if stream has
|
||||
* been closed
|
||||
*/
|
||||
public void seek(long pos) throws IOException {
|
||||
if (in == null)
|
||||
@@ -727,10 +711,9 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
/**
|
||||
* Seeks to the beginning of the given XZ Block.
|
||||
*
|
||||
* @throws XZIOException
|
||||
* if <code>blockNumber < 0</code> or
|
||||
* <code>blockNumber >= getBlockCount()</code>,
|
||||
* or if stream has been closed
|
||||
* @throws XZIOException if <code>blockNumber < 0</code> or
|
||||
* <code>blockNumber >= getBlockCount()</code>, or if stream
|
||||
* has been closed
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
@@ -749,8 +732,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the actual seeking. This is also called when <code>read</code>
|
||||
* needs a new Block to decode.
|
||||
* Does the actual seeking. This is also called when <code>read</code> needs
|
||||
* a new Block to decode.
|
||||
*/
|
||||
private void seek() throws IOException {
|
||||
// If seek(long) wasn't called, we simply need to get the next Block
|
||||
@@ -844,8 +827,8 @@ public class SeekableXZInputStream extends SeekableInputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the given Block and stores information about it
|
||||
* to <code>info</code>.
|
||||
* Locates the given Block and stores information about it to
|
||||
* <code>info</code>.
|
||||
*/
|
||||
private void locateBlockByNumber(BlockInfo info, int blockNumber) {
|
||||
// Validate.
|
||||
|
||||
@@ -18,11 +18,11 @@ import org.tukaani.xz.index.IndexHash;
|
||||
import org.tukaani.xz.check.Check;
|
||||
|
||||
/**
|
||||
* Decompresses exactly one XZ Stream in streamed mode (no seeking).
|
||||
* The decompression stops after the first XZ Stream has been decompressed,
|
||||
* and the read position in the input stream is left at the first byte
|
||||
* after the end of the XZ Stream. This can be useful when XZ data has
|
||||
* been stored inside some other file format or protocol.
|
||||
* Decompresses exactly one XZ Stream in streamed mode (no seeking). The
|
||||
* decompression stops after the first XZ Stream has been decompressed, and the
|
||||
* read position in the input stream is left at the first byte after the end of
|
||||
* the XZ Stream. This can be useful when XZ data has been stored inside some
|
||||
* other file format or protocol.
|
||||
* <p>
|
||||
* Unless you know what you are doing, don't use this class to decompress
|
||||
* 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>
|
||||
* <p>
|
||||
* If you are decompressing complete XZ streams and your application knows
|
||||
* exactly how much uncompressed data there should be, it is good to try
|
||||
* reading one more byte by calling <code>read()</code> and checking
|
||||
* that it returns <code>-1</code>. This way the decompressor will parse the
|
||||
* file footers and verify the integrity checks, giving the caller more
|
||||
* confidence that the uncompressed data is valid.
|
||||
* exactly how much uncompressed data there should be, it is good to try reading
|
||||
* one more byte by calling <code>read()</code> and checking that it returns
|
||||
* <code>-1</code>. This way the decompressor will parse the file footers and
|
||||
* verify the integrity checks, giving the caller more confidence that the
|
||||
* uncompressed data is valid.
|
||||
*
|
||||
* @see XZInputStream
|
||||
*/
|
||||
@@ -52,29 +52,25 @@ public class SingleXZInputStream extends InputStream {
|
||||
private final byte[] tempBuf = new byte[1];
|
||||
|
||||
/**
|
||||
* Creates a new XZ decompressor that decompresses exactly one
|
||||
* XZ Stream from <code>in</code> without a memory usage limit.
|
||||
* Creates a new XZ decompressor that decompresses exactly one XZ Stream
|
||||
* from <code>in</code> without a memory usage limit.
|
||||
* <p>
|
||||
* This constructor reads and parses the XZ Stream Header (12 bytes)
|
||||
* from <code>in</code>. The header of the first Block is not read
|
||||
* until <code>read</code> is called.
|
||||
* This constructor reads and parses the XZ Stream Header (12 bytes) from
|
||||
* <code>in</code>. The header of the first Block is not read until
|
||||
* <code>read</code> is called.
|
||||
*
|
||||
* @param in input stream from which XZ-compressed
|
||||
* data is read
|
||||
* @param in input stream from which XZ-compressed data is read
|
||||
*
|
||||
* @throws XZFormatException
|
||||
* input is not in the XZ format
|
||||
* @throws XZFormatException input is not in the XZ format
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* XZ header CRC32 doesn't match
|
||||
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* XZ header is valid but specifies options
|
||||
* not supported by this implementation
|
||||
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||
* options not supported by this implementation
|
||||
*
|
||||
* @throws EOFException
|
||||
* less than 12 bytes of input was available
|
||||
* from <code>in</code>
|
||||
* @throws EOFException less than 12 bytes of input was
|
||||
* available from
|
||||
* <code>in</code>
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -83,32 +79,27 @@ public class SingleXZInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XZ decompressor that decompresses exactly one
|
||||
* XZ Stream from <code>in</code> with an optional memory usage limit.
|
||||
* Creates a new XZ decompressor that decompresses exactly one XZ Stream
|
||||
* from <code>in</code> with an optional memory usage limit.
|
||||
* <p>
|
||||
* This is identical to <code>SingleXZInputStream(InputStream)</code>
|
||||
* except that this takes also the <code>memoryLimit</code> argument.
|
||||
* This is identical to <code>SingleXZInputStream(InputStream)</code> except
|
||||
* that this takes also the <code>memoryLimit</code> argument.
|
||||
*
|
||||
* @param in input stream from which XZ-compressed
|
||||
* data is read
|
||||
* @param in input stream from which XZ-compressed data is read
|
||||
*
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
||||
* or <code>-1</code> to impose no
|
||||
* memory usage limit
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||
* <code>-1</code> to impose no memory usage limit
|
||||
*
|
||||
* @throws XZFormatException
|
||||
* input is not in the XZ format
|
||||
* @throws XZFormatException input is not in the XZ format
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* XZ header CRC32 doesn't match
|
||||
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* XZ header is valid but specifies options
|
||||
* not supported by this implementation
|
||||
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||
* options not supported by this implementation
|
||||
*
|
||||
* @throws EOFException
|
||||
* less than 12 bytes of input was available
|
||||
* from <code>in</code>
|
||||
* @throws EOFException less than 12 bytes of input was
|
||||
* available from
|
||||
* <code>in</code>
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -158,12 +149,12 @@ public class SingleXZInputStream extends InputStream {
|
||||
/**
|
||||
* Decompresses the next byte from this input stream.
|
||||
* <p>
|
||||
* Reading lots of data with <code>read()</code> from this input stream
|
||||
* may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
|
||||
* if you need to read lots of data one byte at a time.
|
||||
* Reading lots of data with <code>read()</code> from this input stream may
|
||||
* be inefficient. Wrap it in {@link java.io.BufferedInputStream} if you
|
||||
* need to read lots of data one byte at a time.
|
||||
*
|
||||
* @return the next decompressed byte, or <code>-1</code>
|
||||
* to indicate the end of the compressed stream
|
||||
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||
* end of the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* @throws UnsupportedOptionsException
|
||||
@@ -171,8 +162,8 @@ public class SingleXZInputStream extends InputStream {
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or
|
||||
* corrupt
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -183,16 +174,16 @@ public class SingleXZInputStream extends InputStream {
|
||||
/**
|
||||
* Decompresses into an array of bytes.
|
||||
* <p>
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
||||
* is returned. Otherwise this will try to decompress <code>len</code>
|
||||
* bytes of uncompressed data. Less than <code>len</code> bytes may
|
||||
* be read only in the following situations:
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||
* returned. Otherwise this will try to decompress <code>len</code> bytes of
|
||||
* uncompressed data. Less than <code>len</code> bytes may be read only in
|
||||
* the following situations:
|
||||
* <ul>
|
||||
* <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>
|
||||
* bytes have already been successfully decompressed.
|
||||
* The next call with non-zero <code>len</code> will immediately
|
||||
* throw the pending exception.</li>
|
||||
* bytes have already been successfully decompressed. The next call with
|
||||
* non-zero <code>len</code> will immediately throw the pending
|
||||
* exception.</li>
|
||||
* <li>An exception is thrown.</li>
|
||||
* </ul>
|
||||
*
|
||||
@@ -200,8 +191,8 @@ public class SingleXZInputStream extends InputStream {
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len maximum number of uncompressed bytes to read
|
||||
*
|
||||
* @return number of bytes read, or <code>-1</code> to indicate
|
||||
* the end of the compressed stream
|
||||
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||
* the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* @throws UnsupportedOptionsException
|
||||
@@ -209,8 +200,8 @@ public class SingleXZInputStream extends InputStream {
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or
|
||||
* corrupt
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -279,15 +270,14 @@ public class SingleXZInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of uncompressed bytes that can be read
|
||||
* without blocking. The value is returned with an assumption
|
||||
* that the compressed input data will be valid. If the compressed
|
||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
||||
* thrown before the number of bytes claimed to be available have
|
||||
* been read from this input stream.
|
||||
* Returns the number of uncompressed bytes that can be read without
|
||||
* blocking. The value is returned with an assumption that the compressed
|
||||
* input data will be valid. If the compressed data is corrupt,
|
||||
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||
* bytes claimed to be available have been read from this input stream.
|
||||
*
|
||||
* @return the number of uncompressed bytes that can be read
|
||||
* without blocking
|
||||
* @return the number of uncompressed bytes that can be read without
|
||||
* blocking
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
if (in == null)
|
||||
@@ -300,8 +290,8 @@ public class SingleXZInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and calls <code>in.close()</code>.
|
||||
* If the stream was already closed, this does nothing.
|
||||
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||
* already closed, this does nothing.
|
||||
*
|
||||
* @throws IOException if thrown by <code>in.close()</code>
|
||||
*/
|
||||
|
||||
@@ -9,23 +9,23 @@
|
||||
package org.tukaani.xz;
|
||||
|
||||
/**
|
||||
* Thrown when compression options not supported by this implementation
|
||||
* are detected. Some other implementation might support those options.
|
||||
* Thrown when compression options not supported by this implementation are
|
||||
* detected. Some other implementation might support those options.
|
||||
*/
|
||||
public class UnsupportedOptionsException extends XZIOException {
|
||||
|
||||
private static final long serialVersionUID = 3L;
|
||||
|
||||
/**
|
||||
* Creates a new UnsupportedOptionsException with null
|
||||
* as its error detail message.
|
||||
* Creates a new UnsupportedOptionsException with null as its error detail
|
||||
* message.
|
||||
*/
|
||||
public UnsupportedOptionsException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UnsupportedOptionsException with the given
|
||||
* error detail message.
|
||||
* Creates a new UnsupportedOptionsException with the given error detail
|
||||
* message.
|
||||
*
|
||||
* @param s error detail message
|
||||
*/
|
||||
|
||||
@@ -14,8 +14,8 @@ package org.tukaani.xz;
|
||||
public class XZ {
|
||||
|
||||
/**
|
||||
* XZ Header Magic Bytes begin a XZ file.
|
||||
* This can be useful to detect XZ compressed data.
|
||||
* XZ Header Magic Bytes begin a XZ file. This can be useful to detect XZ
|
||||
* compressed data.
|
||||
*/
|
||||
public static final byte[] HEADER_MAGIC = {
|
||||
(byte) 0xFD, '7', 'z', 'X', 'Z', '\0' };
|
||||
@@ -28,9 +28,9 @@ public class XZ {
|
||||
/**
|
||||
* Integrity check ID indicating that no integrity check is calculated.
|
||||
* <p>
|
||||
* Omitting the integrity check is strongly discouraged except when
|
||||
* the integrity of the data will be verified by other means anyway,
|
||||
* and calculating the check twice would be useless.
|
||||
* Omitting the integrity check is strongly discouraged except when the
|
||||
* integrity of the data will be verified by other means anyway, and
|
||||
* calculating the check twice would be useless.
|
||||
*/
|
||||
public static final int CHECK_NONE = 0;
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
package org.tukaani.xz;
|
||||
|
||||
/**
|
||||
* Generic {@link java.io.IOException IOException} specific to this package.
|
||||
* The other IOExceptions in this package extend
|
||||
* from <code>XZIOException</code>.
|
||||
* Generic {@link java.io.IOException IOException} specific to this package. The
|
||||
* other IOExceptions in this package extend from <code>XZIOException</code>.
|
||||
*/
|
||||
public class XZIOException extends java.io.IOException {
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ import org.tukaani.xz.common.DecoderUtil;
|
||||
/**
|
||||
* Decompresses a .xz file in streamed mode (no seeking).
|
||||
* <p>
|
||||
* Use this to decompress regular standalone .xz files. This reads from
|
||||
* its input stream until the end of the input or until an error occurs.
|
||||
* This supports decompressing concatenated .xz files.
|
||||
* Use this to decompress regular standalone .xz files. This reads from its
|
||||
* input stream until the end of the input or until an error occurs. This
|
||||
* supports decompressing concatenated .xz files.
|
||||
*
|
||||
* <h4>Typical use cases</h4>
|
||||
* <p>
|
||||
@@ -30,18 +30,18 @@ import org.tukaani.xz.common.DecoderUtil;
|
||||
* XZInputStream inxz = new XZInputStream(infile);
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* It's important to keep in mind that decompressor memory usage depends
|
||||
* on the settings used to compress the file. The worst-case memory usage
|
||||
* of XZInputStream is currently 1.5 GiB. Still, very few files will
|
||||
* require more than about 65 MiB because that's how much decompressing
|
||||
* a file created with the highest preset level will need, and only a few
|
||||
* people use settings other than the predefined presets.
|
||||
* It's important to keep in mind that decompressor memory usage depends on the
|
||||
* settings used to compress the file. The worst-case memory usage of
|
||||
* XZInputStream is currently 1.5 GiB. Still, very few files will require
|
||||
* more than about 65 MiB because that's how much decompressing a file
|
||||
* created with the highest preset level will need, and only a few people use
|
||||
* settings other than the predefined presets.
|
||||
* <p>
|
||||
* It is possible to specify a memory usage limit for
|
||||
* <code>XZInputStream</code>. If decompression requires more memory than
|
||||
* the specified limit, MemoryLimitException will be thrown when reading
|
||||
* from the stream. For example, the following sets the memory usage limit
|
||||
* to 100 MiB:
|
||||
* <code>XZInputStream</code>. If decompression requires more memory than the
|
||||
* specified limit, MemoryLimitException will be thrown when reading from the
|
||||
* stream. For example, the following sets the memory usage limit to
|
||||
* 100 MiB:
|
||||
* <p>
|
||||
* <blockquote><pre>
|
||||
* InputStream infile = new FileInputStream("foo.xz");
|
||||
@@ -50,13 +50,12 @@ import org.tukaani.xz.common.DecoderUtil;
|
||||
*
|
||||
* <h4>When uncompressed size is known beforehand</h4>
|
||||
* <p>
|
||||
* If you are decompressing complete files and your application knows
|
||||
* exactly how much uncompressed data there should be, it is good to try
|
||||
* reading one more byte by calling <code>read()</code> and checking
|
||||
* that it returns <code>-1</code>. This way the decompressor will parse the
|
||||
* file footers and verify the integrity checks, giving the caller more
|
||||
* confidence that the uncompressed data is valid. (This advice seems to
|
||||
* apply to
|
||||
* If you are decompressing complete files and your application knows exactly
|
||||
* how much uncompressed data there should be, it is good to try reading one
|
||||
* more byte by calling <code>read()</code> and checking that it returns
|
||||
* <code>-1</code>. This way the decompressor will parse the file footers and
|
||||
* verify the integrity checks, giving the caller more confidence that the
|
||||
* uncompressed data is valid. (This advice seems to apply to
|
||||
* {@link java.util.zip.GZIPInputStream java.util.zip.GZIPInputStream} too.)
|
||||
*
|
||||
* @see SingleXZInputStream
|
||||
@@ -74,26 +73,22 @@ public class XZInputStream extends InputStream {
|
||||
/**
|
||||
* Creates a new XZ decompressor without a memory usage limit.
|
||||
* <p>
|
||||
* This constructor reads and parses the XZ Stream Header (12 bytes)
|
||||
* from <code>in</code>. The header of the first Block is not read
|
||||
* until <code>read</code> is called.
|
||||
* This constructor reads and parses the XZ Stream Header (12 bytes) from
|
||||
* <code>in</code>. The header of the first Block is not read until
|
||||
* <code>read</code> is called.
|
||||
*
|
||||
* @param in input stream from which XZ-compressed
|
||||
* data is read
|
||||
* @param in input stream from which XZ-compressed data is read
|
||||
*
|
||||
* @throws XZFormatException
|
||||
* input is not in the XZ format
|
||||
* @throws XZFormatException input is not in the XZ format
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* XZ header CRC32 doesn't match
|
||||
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* XZ header is valid but specifies options
|
||||
* not supported by this implementation
|
||||
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||
* options not supported by this implementation
|
||||
*
|
||||
* @throws EOFException
|
||||
* less than 12 bytes of input was available
|
||||
* from <code>in</code>
|
||||
* @throws EOFException less than 12 bytes of input was
|
||||
* available from
|
||||
* <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.
|
||||
* <p>
|
||||
* This is identical to <code>XZInputStream(InputStream)</code> except
|
||||
* that this takes also the <code>memoryLimit</code> argument.
|
||||
* This is identical to <code>XZInputStream(InputStream)</code> except that
|
||||
* this takes also the <code>memoryLimit</code> argument.
|
||||
*
|
||||
* @param in input stream from which XZ-compressed
|
||||
* data is read
|
||||
* @param in input stream from which XZ-compressed data is read
|
||||
*
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB)
|
||||
* or <code>-1</code> to impose no
|
||||
* memory usage limit
|
||||
* @param memoryLimit memory usage limit in kibibytes (KiB) or
|
||||
* <code>-1</code> to impose no memory usage limit
|
||||
*
|
||||
* @throws XZFormatException
|
||||
* input is not in the XZ format
|
||||
* @throws XZFormatException input is not in the XZ format
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* XZ header CRC32 doesn't match
|
||||
* @throws CorruptedInputException XZ header CRC32 doesn't match
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* XZ header is valid but specifies options
|
||||
* not supported by this implementation
|
||||
* @throws UnsupportedOptionsException XZ header is valid but specifies
|
||||
* options not supported by this implementation
|
||||
*
|
||||
* @throws EOFException
|
||||
* less than 12 bytes of input was available
|
||||
* from <code>in</code>
|
||||
* @throws EOFException less than 12 bytes of input was
|
||||
* available from
|
||||
* <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.
|
||||
* <p>
|
||||
* Reading lots of data with <code>read()</code> from this input stream
|
||||
* may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
|
||||
* if you need to read lots of data one byte at a time.
|
||||
* Reading lots of data with <code>read()</code> from this input stream may
|
||||
* be inefficient. Wrap it in {@link java.io.BufferedInputStream} if you
|
||||
* need to read lots of data one byte at a time.
|
||||
*
|
||||
* @return the next decompressed byte, or <code>-1</code>
|
||||
* to indicate the end of the compressed stream
|
||||
* @return the next decompressed byte, or <code>-1</code> to indicate the
|
||||
* end of the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* @throws UnsupportedOptionsException
|
||||
@@ -152,8 +142,8 @@ public class XZInputStream extends InputStream {
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or
|
||||
* corrupt
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -164,16 +154,16 @@ public class XZInputStream extends InputStream {
|
||||
/**
|
||||
* Decompresses into an array of bytes.
|
||||
* <p>
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code>
|
||||
* is returned. Otherwise this will try to decompress <code>len</code>
|
||||
* bytes of uncompressed data. Less than <code>len</code> bytes may
|
||||
* be read only in the following situations:
|
||||
* If <code>len</code> is zero, no bytes are read and <code>0</code> is
|
||||
* returned. Otherwise this will try to decompress <code>len</code> bytes of
|
||||
* uncompressed data. Less than <code>len</code> bytes may be read only in
|
||||
* the following situations:
|
||||
* <ul>
|
||||
* <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>
|
||||
* bytes have already been successfully decompressed.
|
||||
* The next call with non-zero <code>len</code> will immediately
|
||||
* throw the pending exception.</li>
|
||||
* bytes have already been successfully decompressed. The next call with
|
||||
* non-zero <code>len</code> will immediately throw the pending
|
||||
* exception.</li>
|
||||
* <li>An exception is thrown.</li>
|
||||
* </ul>
|
||||
*
|
||||
@@ -181,8 +171,8 @@ public class XZInputStream extends InputStream {
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len maximum number of uncompressed bytes to read
|
||||
*
|
||||
* @return number of bytes read, or <code>-1</code> to indicate
|
||||
* the end of the compressed stream
|
||||
* @return number of bytes read, or <code>-1</code> to indicate the end of
|
||||
* the compressed stream
|
||||
*
|
||||
* @throws CorruptedInputException
|
||||
* @throws UnsupportedOptionsException
|
||||
@@ -190,8 +180,8 @@ public class XZInputStream extends InputStream {
|
||||
*
|
||||
* @throws XZIOException if the stream has been closed
|
||||
*
|
||||
* @throws EOFException
|
||||
* compressed input is truncated or corrupt
|
||||
* @throws EOFException compressed input is truncated or
|
||||
* corrupt
|
||||
*
|
||||
* @throws IOException may be thrown by <code>in</code>
|
||||
*/
|
||||
@@ -276,15 +266,14 @@ public class XZInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of uncompressed bytes that can be read
|
||||
* without blocking. The value is returned with an assumption
|
||||
* that the compressed input data will be valid. If the compressed
|
||||
* data is corrupt, <code>CorruptedInputException</code> may get
|
||||
* thrown before the number of bytes claimed to be available have
|
||||
* been read from this input stream.
|
||||
* Returns the number of uncompressed bytes that can be read without
|
||||
* blocking. The value is returned with an assumption that the compressed
|
||||
* input data will be valid. If the compressed data is corrupt,
|
||||
* <code>CorruptedInputException</code> may get thrown before the number of
|
||||
* bytes claimed to be available have been read from this input stream.
|
||||
*
|
||||
* @return the number of uncompressed bytes that can be read
|
||||
* without blocking
|
||||
* @return the number of uncompressed bytes that can be read without
|
||||
* blocking
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
if (in == null)
|
||||
@@ -297,8 +286,8 @@ public class XZInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and calls <code>in.close()</code>.
|
||||
* If the stream was already closed, this does nothing.
|
||||
* Closes the stream and calls <code>in.close()</code>. If the stream was
|
||||
* already closed, this does nothing.
|
||||
*
|
||||
* @throws IOException if thrown by <code>in.close()</code>
|
||||
*/
|
||||
|
||||
@@ -20,25 +20,24 @@ import org.tukaani.xz.index.IndexEncoder;
|
||||
*
|
||||
* <h4>Examples</h4>
|
||||
* <p>
|
||||
* Getting an output stream to compress with LZMA2 using the default
|
||||
* settings and the default integrity check type (CRC64):
|
||||
* Getting an output stream to compress with LZMA2 using the default settings
|
||||
* and the default integrity check type (CRC64):
|
||||
* <p>
|
||||
* <blockquote><pre>
|
||||
* FileOutputStream outfile = new FileOutputStream("foo.xz");
|
||||
* XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options());
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* Using the preset level <code>8</code> for LZMA2 (the default
|
||||
* is <code>6</code>) and SHA-256 instead of CRC64 for integrity checking:
|
||||
* Using the preset level <code>8</code> for LZMA2 (the default is
|
||||
* <code>6</code>) and SHA-256 instead of CRC64 for integrity checking:
|
||||
* <p>
|
||||
* <blockquote><pre>
|
||||
* XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options(8),
|
||||
* XZ.CHECK_SHA256);
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* Using the x86 BCJ filter together with LZMA2 to compress x86 executables
|
||||
* and printing the memory usage information before creating the
|
||||
* XZOutputStream:
|
||||
* Using the x86 BCJ filter together with LZMA2 to compress x86 executables and
|
||||
* printing the memory usage information before creating the XZOutputStream:
|
||||
* <p>
|
||||
* <blockquote><pre>
|
||||
* X86Options x86 = new X86Options();
|
||||
@@ -64,9 +63,9 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
private FilterEncoder[] filters;
|
||||
|
||||
/**
|
||||
* True if the current filter chain supports flushing.
|
||||
* If it doesn't support flushing, <code>flush()</code>
|
||||
* will use <code>endBlock()</code> as a fallback.
|
||||
* True if the current filter chain supports flushing. If it doesn't support
|
||||
* flushing, <code>flush()</code> will use <code>endBlock()</code> as a
|
||||
* fallback.
|
||||
*/
|
||||
private boolean filtersSupportFlushing;
|
||||
|
||||
@@ -76,19 +75,17 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
private final byte[] tempBuf = new byte[1];
|
||||
|
||||
/**
|
||||
* Creates a new XZ compressor using one filter and CRC64 as
|
||||
* the integrity check. This constructor is equivalent to passing
|
||||
* a single-member FilterOptions array to
|
||||
* Creates a new XZ compressor using one filter and CRC64 as the integrity
|
||||
* check. This constructor is equivalent to passing a single-member
|
||||
* FilterOptions array to
|
||||
* <code>XZOutputStream(OutputStream, FilterOptions[])</code>.
|
||||
*
|
||||
* @param out output stream to which the compressed data
|
||||
* will be written
|
||||
* @param out output stream to which the compressed data will be
|
||||
* written
|
||||
*
|
||||
* @param filterOptions
|
||||
* filter options to use
|
||||
* @param filterOptions filter options to use
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* invalid filter chain
|
||||
* @throws UnsupportedOptionsException invalid filter chain
|
||||
*
|
||||
* @throws IOException may be thrown from <code>out</code>
|
||||
*/
|
||||
@@ -98,22 +95,20 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XZ compressor using one filter and the specified
|
||||
* integrity check type. This constructor is equivalent to
|
||||
* passing a single-member FilterOptions array to
|
||||
* Creates a new XZ compressor using one filter and the specified integrity
|
||||
* check type. This constructor is equivalent to passing a single-member
|
||||
* FilterOptions array to
|
||||
* <code>XZOutputStream(OutputStream, FilterOptions[], int)</code>.
|
||||
*
|
||||
* @param out output stream to which the compressed data
|
||||
* will be written
|
||||
* @param out output stream to which the compressed data will be
|
||||
* written
|
||||
*
|
||||
* @param filterOptions
|
||||
* filter options to use
|
||||
* @param filterOptions filter options to use
|
||||
*
|
||||
* @param checkType type of the integrity check,
|
||||
* for example XZ.CHECK_CRC32
|
||||
* @param checkType type of the integrity check, for example
|
||||
* XZ.CHECK_CRC32
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* invalid filter chain
|
||||
* @throws UnsupportedOptionsException invalid filter chain
|
||||
*
|
||||
* @throws IOException may be thrown from <code>out</code>
|
||||
*/
|
||||
@@ -123,18 +118,16 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XZ compressor using 1-4 filters and CRC64 as
|
||||
* the integrity check. This constructor is equivalent
|
||||
* Creates a new XZ compressor using 1-4 filters and CRC64 as the integrity
|
||||
* check. This constructor is equivalent
|
||||
* <code>XZOutputStream(out, filterOptions, XZ.CHECK_CRC64)</code>.
|
||||
*
|
||||
* @param out output stream to which the compressed data
|
||||
* will be written
|
||||
* @param out output stream to which the compressed data will be
|
||||
* written
|
||||
*
|
||||
* @param filterOptions
|
||||
* array of filter options to use
|
||||
* @param filterOptions array of filter options to use
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* invalid filter chain
|
||||
* @throws UnsupportedOptionsException invalid filter chain
|
||||
*
|
||||
* @throws IOException may be thrown from <code>out</code>
|
||||
*/
|
||||
@@ -144,20 +137,18 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XZ compressor using 1-4 filters and the specified
|
||||
* integrity check type.
|
||||
* Creates a new XZ compressor using 1-4 filters and the specified integrity
|
||||
* check type.
|
||||
*
|
||||
* @param out output stream to which the compressed data
|
||||
* will be written
|
||||
* @param out output stream to which the compressed data will be
|
||||
* written
|
||||
*
|
||||
* @param filterOptions
|
||||
* array of filter options to use
|
||||
* @param filterOptions array of filter options to use
|
||||
*
|
||||
* @param checkType type of the integrity check,
|
||||
* for example XZ.CHECK_CRC32
|
||||
* @param checkType type of the integrity check, for example
|
||||
* XZ.CHECK_CRC32
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* invalid filter chain
|
||||
* @throws UnsupportedOptionsException invalid filter chain
|
||||
*
|
||||
* @throws IOException may be thrown from <code>out</code>
|
||||
*/
|
||||
@@ -173,16 +164,14 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the filter chain with a single filter.
|
||||
* This is equivalent to passing a single-member FilterOptions array
|
||||
* to <code>updateFilters(FilterOptions[])</code>.
|
||||
* Updates the filter chain with a single filter. This is equivalent to
|
||||
* passing a single-member FilterOptions array to
|
||||
* <code>updateFilters(FilterOptions[])</code>.
|
||||
*
|
||||
* @param filterOptions
|
||||
* new filter to use
|
||||
* @param filterOptions new filter to use
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* unsupported filter chain, or trying to change
|
||||
* the filter chain in the middle of a Block
|
||||
* @throws UnsupportedOptionsException unsupported filter chain, or trying
|
||||
* to change the filter chain in the middle of a Block
|
||||
*/
|
||||
public void updateFilters(FilterOptions filterOptions)
|
||||
throws XZIOException {
|
||||
@@ -194,17 +183,15 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
/**
|
||||
* Updates the filter chain with 1-4 filters.
|
||||
* <p>
|
||||
* Currently this cannot be used to update e.g. LZMA2 options in the
|
||||
* middle of a XZ Block. Use <code>endBlock()</code> to finish the
|
||||
* current XZ Block before calling this function. The new filter chain
|
||||
* will then be used for the next XZ Block.
|
||||
* Currently this cannot be used to update e.g. LZMA2 options in the middle
|
||||
* of a XZ Block. Use <code>endBlock()</code> to finish the current XZ Block
|
||||
* before calling this function. The new filter chain will then be used for
|
||||
* the next XZ Block.
|
||||
*
|
||||
* @param filterOptions
|
||||
* new filter chain to use
|
||||
* @param filterOptions new filter chain to use
|
||||
*
|
||||
* @throws UnsupportedOptionsException
|
||||
* unsupported filter chain, or trying to change
|
||||
* the filter chain in the middle of a Block
|
||||
* @throws UnsupportedOptionsException unsupported filter chain, or trying
|
||||
* to change the filter chain in the middle of a Block
|
||||
*/
|
||||
public void updateFilters(FilterOptions[] filterOptions)
|
||||
throws XZIOException {
|
||||
@@ -230,12 +217,10 @@ public class XZOutputStream extends FinishableOutputStream {
|
||||
/**
|
||||
* Writes one byte to be compressed.
|
||||
*
|
||||
* @throws XZIOException
|
||||
* XZ Stream has grown too big
|
||||
* @throws XZIOException XZ Stream has grown too big
|
||||
*
|
||||
* @throws XZIOException
|
||||
* <code>finish()</code> or <code>close()</code>
|
||||
* was already called
|
||||
* @throws XZIOException <code>finish()</code> or <code>close()</code> was
|
||||
* already called
|
||||
*
|
||||
* @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.
|
||||
* The compressors tend to do internal buffering and thus the written
|
||||
* data won't be readable from the compressed output immediately.
|
||||
* Use <code>flush()</code> to force everything written so far to
|
||||
* be written to the underlaying output stream, but be aware that
|
||||
* flushing reduces compression ratio.
|
||||
* Writes an array of bytes to be compressed. The compressors tend to do
|
||||
* internal buffering and thus the written data won't be readable from the
|
||||
* compressed output immediately. Use <code>flush()</code> to force
|
||||
* everything written so far to be written to the underlaying output stream,
|
||||
* but be aware that flushing reduces compression ratio.
|
||||
*
|
||||
* @param buf buffer of bytes to be written
|
||||
* @param off start offset in <code>buf</code>
|
||||
* @param len number of bytes to write
|
||||
*
|
||||
* @throws XZIOException
|
||||
* XZ Stream has grown too big: total file size
|
||||
* about 8 EiB or the Index field exceeds
|
||||
* 16 GiB; you shouldn't reach these sizes
|
||||
* in practice
|
||||
* @throws XZIOException XZ Stream has grown too big: total file size about
|
||||
* 8 EiB or the Index field exceeds 16 GiB; you shouldn't reach
|
||||
* these sizes in practice
|
||||
*
|
||||
* @throws XZIOException
|
||||
* <code>finish()</code> or <code>close()</code>
|
||||
* was already called and len > 0
|
||||
* @throws XZIOException <code>finish()</code> or <code>close()</code> was
|
||||
* already called and len > 0
|
||||
*
|
||||
* @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).
|
||||
* This doesn't flush the stream so it's possible that not all data will
|
||||
* be decompressible from the output stream when this function returns.
|
||||
* Call also <code>flush()</code> if flushing is wanted in addition to
|
||||
* finishing the current XZ Block.
|
||||
* Finishes the current XZ Block (but not the whole XZ Stream). This doesn't
|
||||
* flush the stream so it's possible that not all data will be
|
||||
* decompressible from the output stream when this function returns. Call
|
||||
* also <code>flush()</code> if flushing is wanted in addition to finishing
|
||||
* the current XZ Block.
|
||||
* <p>
|
||||
* If there is no unfinished Block open, this function will do nothing.
|
||||
* (No empty XZ Block will be created.)
|
||||
* If there is no unfinished Block open, this function will do nothing. (No
|
||||
* empty XZ Block will be created.)
|
||||
* <p>
|
||||
* This function can be useful, for example, to create
|
||||
* random-accessible .xz files.
|
||||
* This function can be useful, for example, to create random-accessible .xz
|
||||
* files.
|
||||
* <p>
|
||||
* Starting a new XZ Block means that the encoder state is reset.
|
||||
* Doing this very often will increase the size of the compressed
|
||||
* file a lot (more than plain <code>flush()</code> would do).
|
||||
* Starting a new XZ Block means that the encoder state is reset. Doing this
|
||||
* very often will increase the size of the compressed file a lot (more than
|
||||
* plain <code>flush()</code> would do).
|
||||
*
|
||||
* @throws XZIOException
|
||||
* XZ Stream has grown too big
|
||||
* @throws XZIOException XZ Stream has grown too big
|
||||
*
|
||||
* @throws XZIOException
|
||||
* stream finished or closed
|
||||
* @throws XZIOException stream finished or closed
|
||||
*
|
||||
* @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>.
|
||||
* All buffered pending data will then be decompressible from
|
||||
* the output stream.
|
||||
* Flushes the encoder and calls <code>out.flush()</code>. All buffered
|
||||
* pending data will then be decompressible from the output stream.
|
||||
* <p>
|
||||
* Calling this function very often may increase the compressed
|
||||
* file size a lot. The filter chain options may affect the size
|
||||
* increase too. For example, with LZMA2 the HC4 match finder has
|
||||
* smaller penalty with flushing than BT4.
|
||||
* Calling this function very often may increase the compressed file size a
|
||||
* lot. The filter chain options may affect the size increase too. For
|
||||
* example, with LZMA2 the HC4 match finder has smaller penalty with
|
||||
* flushing than BT4.
|
||||
* <p>
|
||||
* Some filters don't support flushing. If the filter chain has
|
||||
* such a filter, <code>flush()</code> will call <code>endBlock()</code>
|
||||
* before flushing.
|
||||
* Some filters don't support flushing. If the filter chain has such a
|
||||
* filter, <code>flush()</code> will call <code>endBlock()</code> before
|
||||
* flushing.
|
||||
*
|
||||
* @throws XZIOException
|
||||
* XZ Stream has grown too big
|
||||
* @throws XZIOException XZ Stream has grown too big
|
||||
*
|
||||
* @throws XZIOException
|
||||
* stream finished or closed
|
||||
* @throws XZIOException stream finished or closed
|
||||
*
|
||||
* @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.
|
||||
* No more data can be written to this stream after finishing
|
||||
* (calling <code>write</code> with an empty buffer is OK).
|
||||
* Finishes compression without closing the underlying stream. No more data
|
||||
* can be written to this stream after finishing (calling <code>write</code>
|
||||
* with an empty buffer is OK).
|
||||
* <p>
|
||||
* Repeated calls to <code>finish()</code> do nothing unless
|
||||
* an exception was thrown by this stream earlier. In that case
|
||||
* the same exception is thrown again.
|
||||
* Repeated calls to <code>finish()</code> do nothing unless an exception
|
||||
* was thrown by this stream earlier. In that case the same exception is
|
||||
* thrown again.
|
||||
* <p>
|
||||
* After finishing, the stream may be closed normally with
|
||||
* <code>close()</code>. If the stream will be closed anyway, there
|
||||
* usually is no need to call <code>finish()</code> separately.
|
||||
* <code>close()</code>. If the stream will be closed anyway, there usually
|
||||
* is no need to call <code>finish()</code> separately.
|
||||
*
|
||||
* @throws XZIOException
|
||||
* XZ Stream has grown too big
|
||||
* @throws XZIOException XZ Stream has grown too big
|
||||
*
|
||||
* @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.
|
||||
* The underlying stream <code>out</code> is closed even if finishing
|
||||
* fails. If both finishing and closing fail, the exception thrown
|
||||
* by <code>finish()</code> is thrown and the exception from the failed
|
||||
* <code>out.close()</code> is lost.
|
||||
* Finishes compression and closes the underlying stream. The underlying
|
||||
* stream <code>out</code> is closed even if finishing fails. If both
|
||||
* finishing and closing fail, the exception thrown by <code>finish()</code>
|
||||
* is thrown and the exception from the failed <code>out.close()</code> is
|
||||
* lost.
|
||||
*
|
||||
* @throws XZIOException
|
||||
* XZ Stream has grown too big
|
||||
* @throws XZIOException XZ Stream has grown too big
|
||||
*
|
||||
* @throws IOException may be thrown by the underlying output stream
|
||||
*/
|
||||
|
||||
@@ -28,8 +28,8 @@ final class HC4 extends LZEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LZEncoder with the HC4 match finder.
|
||||
* See <code>LZEncoder.getInstance</code> for parameter descriptions.
|
||||
* Creates a new LZEncoder with the HC4 match finder. See
|
||||
* <code>LZEncoder.getInstance</code> for parameter descriptions.
|
||||
*/
|
||||
HC4(int dictSize, int beforeSizeMin, int readAheadMax,
|
||||
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,
|
||||
* and possibly normalizes the hash tables and the hash chain.
|
||||
* Moves to the next byte, checks that there is enough available space, and
|
||||
* possibly normalizes the hash tables and the hash chain.
|
||||
*
|
||||
* @return number of bytes available, including the current byte
|
||||
*/
|
||||
|
||||
@@ -18,16 +18,16 @@ public abstract class LZEncoder {
|
||||
public static final int MF_BT4 = 0x14;
|
||||
|
||||
/**
|
||||
* Number of bytes to keep available before the current byte
|
||||
* when moving the LZ window.
|
||||
* Number of bytes to keep available before the current byte when moving the
|
||||
* LZ window.
|
||||
*/
|
||||
private final int keepSizeBefore;
|
||||
|
||||
/**
|
||||
* Number of bytes that must be available, the current byte included,
|
||||
* to make hasEnoughData return true. Flushing and finishing are
|
||||
* naturally exceptions to this since there cannot be any data after
|
||||
* the end of the uncompressed input.
|
||||
* Number of bytes that must be available, the current byte included, to
|
||||
* make hasEnoughData return true. Flushing and finishing are naturally
|
||||
* exceptions to this since there cannot be any data after the end of the
|
||||
* uncompressed input.
|
||||
*/
|
||||
private final int keepSizeAfter;
|
||||
|
||||
@@ -63,8 +63,8 @@ public abstract class LZEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets approximate memory usage of the LZEncoder base structure and
|
||||
* the match finder as kibibytes.
|
||||
* Gets approximate memory usage of the LZEncoder base structure and the
|
||||
* match finder as kibibytes.
|
||||
*/
|
||||
public static int getMemoryUsage(
|
||||
int dictSize, int extraSizeBefore, int extraSizeAfter,
|
||||
@@ -94,17 +94,15 @@ public abstract class LZEncoder {
|
||||
* <p>
|
||||
* @param dictSize dictionary size
|
||||
*
|
||||
* @param extraSizeBefore
|
||||
* number of bytes to keep available in the
|
||||
* history in addition to dictSize
|
||||
* @param extraSizeBefore number of bytes to keep available in the history
|
||||
* in addition to dictSize
|
||||
*
|
||||
* @param extraSizeAfter
|
||||
* number of bytes that must be available
|
||||
* after current position + matchLenMax
|
||||
* @param extraSizeAfter number of bytes that must be available after
|
||||
* current position + matchLenMax
|
||||
*
|
||||
* @param niceLen if a match of at least <code>niceLen</code>
|
||||
* bytes is found, be happy with it and don't
|
||||
* stop looking for longer matches
|
||||
* @param niceLen if a match of at least <code>niceLen</code> bytes
|
||||
* is
|
||||
* found, be happy with it and don't stop looking for longer matches
|
||||
*
|
||||
* @param matchLenMax don't test for matches longer than
|
||||
* <code>matchLenMax</code> bytes
|
||||
@@ -145,9 +143,9 @@ public abstract class LZEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a preset dictionary. If a preset dictionary is wanted, this
|
||||
* function must be called immediately after creating the LZEncoder
|
||||
* before any data has been encoded.
|
||||
* Sets a preset dictionary. If a preset dictionary is wanted, this function
|
||||
* must be called immediately after creating the LZEncoder before any data
|
||||
* has been encoded.
|
||||
*/
|
||||
public void setPresetDict(int dictSize, byte[] presetDict) {
|
||||
assert !isStarted();
|
||||
@@ -165,8 +163,8 @@ public abstract class LZEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves data from the end of the buffer to the beginning, discarding
|
||||
* old data and making space for new input.
|
||||
* Moves data from the end of the buffer to the beginning, discarding old
|
||||
* data and making space for new input.
|
||||
*/
|
||||
private void moveWindow() {
|
||||
// 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
|
||||
* or encoder flush operation.
|
||||
* Process pending bytes remaining from preset dictionary initialization or
|
||||
* encoder flush operation.
|
||||
*/
|
||||
private void processPendingBytes() {
|
||||
// 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
|
||||
* the match finder.
|
||||
* Returns true if at least one byte has already been run through the match
|
||||
* finder.
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
return readPos != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks that all the input needs to be made available in
|
||||
* the encoded output.
|
||||
* Marks that all the input needs to be made available in the encoded
|
||||
* output.
|
||||
*/
|
||||
public void setFlushing() {
|
||||
readLimit = writePos - 1;
|
||||
@@ -251,8 +249,8 @@ public abstract class LZEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks that there is no more input remaining. The read position
|
||||
* can be advanced until the end of the data.
|
||||
* Marks that there is no more input remaining. The read position can be
|
||||
* advanced until the end of the data.
|
||||
*/
|
||||
public void setFinishing() {
|
||||
readLimit = writePos - 1;
|
||||
@@ -261,8 +259,8 @@ public abstract class LZEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there is enough input available to let the caller encode
|
||||
* at least one more byte.
|
||||
* Tests if there is enough input available to let the caller encode at
|
||||
* least one more byte.
|
||||
*/
|
||||
public boolean hasEnoughData(int alreadyReadLen) {
|
||||
return readPos - alreadyReadLen < readLimit;
|
||||
@@ -277,8 +275,8 @@ public abstract class LZEncoder {
|
||||
* Get the number of bytes available, including the current byte.
|
||||
* <p>
|
||||
* Note that the result is undefined if <code>getMatches</code> or
|
||||
* <code>skip</code> hasn't been called yet and no preset dictionary
|
||||
* is being used.
|
||||
* <code>skip</code> hasn't been called yet and no preset dictionary is
|
||||
* being used.
|
||||
*/
|
||||
public int getAvail() {
|
||||
assert isStarted();
|
||||
@@ -296,9 +294,8 @@ public abstract class LZEncoder {
|
||||
/**
|
||||
* Gets the byte from the given backward offset.
|
||||
* <p>
|
||||
* The current byte is at <code>0</code>, the previous byte
|
||||
* at <code>1</code> etc. To get a byte at zero-based distance,
|
||||
* use <code>getByte(dist + 1)<code>.
|
||||
* The current byte is at <code>0</code>, the previous byte at
|
||||
* <code>1</code> etc. To get a byte at zero-based distance, use <code>getByte(dist + 1)<code>.
|
||||
* <p>
|
||||
* 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.
|
||||
* The forward offset is added to the current position. This lets
|
||||
* one read bytes ahead of the current byte.
|
||||
* Gets the byte from the given forward minus backward offset. The forward
|
||||
* offset is added to the current position. This lets one read bytes ahead
|
||||
* of the current byte.
|
||||
*/
|
||||
public int getByte(int forward, int backward) {
|
||||
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.
|
||||
* This is meant to be used in an assert statement. This is totally
|
||||
* useless for actual encoding since match finder's results should
|
||||
* naturally always be valid if it isn't broken.
|
||||
* Verifies that the matches returned by the match finder are valid. This is
|
||||
* meant to be used in an assert statement. This is totally useless for
|
||||
* actual encoding since match finder's results should naturally always be
|
||||
* valid if it isn't broken.
|
||||
*
|
||||
* @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,
|
||||
* and returns the amount of input available.
|
||||
* Moves to the next byte, checks if there is enough input available, and
|
||||
* returns the amount of input available.
|
||||
*
|
||||
* @param requiredForFlushing
|
||||
* minimum number of available bytes when
|
||||
* flushing; encoding may be continued with
|
||||
* new input after flushing
|
||||
* @param requiredForFinishing
|
||||
* minimum number of available bytes when
|
||||
* finishing; encoding must not be continued
|
||||
* after finishing or the match finder state
|
||||
* may be corrupt
|
||||
* @param requiredForFlushing minimum number of available bytes when
|
||||
* flushing; encoding may be continued with new input after flushing
|
||||
* @param requiredForFinishing 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
|
||||
* is not enough input available
|
||||
* @return the number of bytes available or zero if there is not enough
|
||||
* input available
|
||||
*/
|
||||
int movePos(int requiredForFlushing, int requiredForFinishing) {
|
||||
assert requiredForFlushing >= requiredForFinishing;
|
||||
|
||||
@@ -37,10 +37,10 @@ public final class LZMADecoder extends LZMACoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if LZMA end marker was detected. It is encoded as
|
||||
* the maximum match distance which with signed ints becomes -1. This
|
||||
* function is needed only for LZMA1. LZMA2 doesn't use the end marker
|
||||
* in the LZMA layer.
|
||||
* Returns true if LZMA end marker was detected. It is encoded as the
|
||||
* maximum match distance which with signed ints becomes -1. This function
|
||||
* is needed only for LZMA1. LZMA2 doesn't use the end marker in the LZMA
|
||||
* layer.
|
||||
*/
|
||||
public boolean endMarkerDetected() {
|
||||
return reps[0] == -1;
|
||||
|
||||
@@ -22,10 +22,10 @@ public abstract class LZMAEncoder extends LZMACoder {
|
||||
* LZMA2 chunk is considered full when its uncompressed size exceeds
|
||||
* <code>LZMA2_UNCOMPRESSED_LIMIT</code>.
|
||||
* <p>
|
||||
* A compressed LZMA2 chunk can hold 2 MiB of uncompressed data.
|
||||
* A single LZMA symbol may indicate up to MATCH_LEN_MAX bytes
|
||||
* of data, so the LZMA2 chunk is considered full when there is
|
||||
* less space than MATCH_LEN_MAX bytes.
|
||||
* A compressed LZMA2 chunk can hold 2 MiB of uncompressed data. A single
|
||||
* LZMA symbol may indicate up to MATCH_LEN_MAX bytes of data, so the LZMA2
|
||||
* chunk is considered full when there is less space than MATCH_LEN_MAX
|
||||
* bytes.
|
||||
*/
|
||||
private static final int LZMA2_UNCOMPRESSED_LIMIT
|
||||
= (2 << 20) - MATCH_LEN_MAX;
|
||||
@@ -34,11 +34,11 @@ public abstract class LZMAEncoder extends LZMACoder {
|
||||
* LZMA2 chunk is considered full when its compressed size exceeds
|
||||
* <code>LZMA2_COMPRESSED_LIMIT</code>.
|
||||
* <p>
|
||||
* The maximum compressed size of a LZMA2 chunk is 64 KiB.
|
||||
* A single LZMA symbol might use 20 bytes of space even though
|
||||
* it usually takes just one byte or so. Two more bytes are needed
|
||||
* for LZMA2 uncompressed chunks (see LZMA2OutputStream.writeChunk).
|
||||
* Leave a little safety margin and use 26 bytes.
|
||||
* The maximum compressed size of a LZMA2 chunk is 64 KiB. A single LZMA
|
||||
* symbol might use 20 bytes of space even though it usually takes just one
|
||||
* byte or so. Two more bytes are needed for LZMA2 uncompressed chunks (see
|
||||
* LZMA2OutputStream.writeChunk). Leave a little safety margin and use 26
|
||||
* bytes.
|
||||
*/
|
||||
private static final int LZMA2_COMPRESSED_LIMIT = (64 << 10) - 26;
|
||||
|
||||
@@ -107,9 +107,9 @@ public abstract class LZMAEncoder extends LZMACoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an integer [0, 63] matching the highest two bits of an integer.
|
||||
* This is like bit scan reverse (BSR) on x86 except that this also
|
||||
* cares about the second highest bit.
|
||||
* Gets an integer [0, 63] matching the highest two bits of an integer. This
|
||||
* is like bit scan reverse (BSR) on x86 except that this also cares about
|
||||
* the second highest bit.
|
||||
*/
|
||||
public static int getDistSlot(int dist) {
|
||||
if (dist <= DIST_MODEL_START)
|
||||
@@ -147,19 +147,18 @@ public abstract class LZMAEncoder extends LZMACoder {
|
||||
/**
|
||||
* Gets the next LZMA symbol.
|
||||
* <p>
|
||||
* There are three types of symbols: literal (a single byte),
|
||||
* repeated match, and normal match. The symbol is indicated
|
||||
* by the return value and by the variable <code>back</code>.
|
||||
* There are three types of symbols: literal (a single byte), repeated
|
||||
* match, and normal match. The symbol is indicated by the return value and
|
||||
* by the variable <code>back</code>.
|
||||
* <p>
|
||||
* Literal: <code>back == -1</code> and return value is <code>1</code>.
|
||||
* The literal itself needs to be read from <code>lz</code> separately.
|
||||
* Literal: <code>back == -1</code> and return value is <code>1</code>. The
|
||||
* literal itself needs to be read from <code>lz</code> separately.
|
||||
* <p>
|
||||
* Repeated match: <code>back</code> is in the range [0, 3] and
|
||||
* the return value is the length of the repeated match.
|
||||
* Repeated match: <code>back</code> is in the range [0, 3] and the return
|
||||
* value is the length of the repeated match.
|
||||
* <p>
|
||||
* Normal match: <code>back - REPS<code> (<code>back - 4</code>)
|
||||
* is the distance of the match and the return value is the length
|
||||
* of the match.
|
||||
* Normal match: <code>back - REPS<code> (<code>back - 4</code>) is the
|
||||
* distance of the match and the return value is the length of the match.
|
||||
*/
|
||||
abstract int getNextSymbol();
|
||||
|
||||
@@ -477,9 +476,9 @@ public abstract class LZMAEncoder extends LZMACoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the lookup tables used for calculating match distance
|
||||
* and length prices. The updating is skipped for performance reasons
|
||||
* if the tables haven't changed much since the previous update.
|
||||
* Updates the lookup tables used for calculating match distance and length
|
||||
* prices. The updating is skipped for performance reasons if the tables
|
||||
* haven't changed much since the previous update.
|
||||
*/
|
||||
void updatePrices() {
|
||||
if (distPriceCount <= 0)
|
||||
@@ -621,8 +620,8 @@ public abstract class LZMAEncoder extends LZMACoder {
|
||||
|
||||
/**
|
||||
* The prices are updated after at least
|
||||
* <code>PRICE_UPDATE_INTERVAL</code> many lengths
|
||||
* have been encoded with the same posState.
|
||||
* <code>PRICE_UPDATE_INTERVAL</code> many lengths have been encoded
|
||||
* with the same posState.
|
||||
*/
|
||||
private static final int PRICE_UPDATE_INTERVAL = 32; // FIXME?
|
||||
|
||||
|
||||
@@ -60,9 +60,9 @@ final class LZMAEncoderNormal extends LZMAEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the opts array from backward indexes to forward indexes.
|
||||
* Then it will be simple to get the next symbol from the array
|
||||
* in later calls to <code>getNextSymbol()</code>.
|
||||
* Converts the opts array from backward indexes to forward indexes. Then it
|
||||
* will be simple to get the next symbol from the array in later calls to
|
||||
* <code>getNextSymbol()</code>.
|
||||
*/
|
||||
private int convertOpts() {
|
||||
optEnd = optCur;
|
||||
|
||||
@@ -58,8 +58,7 @@ final class Optimum {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to indicate three LZMA symbols of which the second one
|
||||
* is a literal.
|
||||
* Sets to indicate three LZMA symbols of which the second one is a literal.
|
||||
*/
|
||||
void set3(int newPrice, int optCur, int back2, int len2, int back) {
|
||||
price = newPrice;
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
*
|
||||
* <h4>Introduction</h4>
|
||||
* <p>
|
||||
* This aims to be a complete implementation of XZ data compression
|
||||
* in pure Java. Features:
|
||||
* This aims to be a complete implementation of XZ data compression in pure
|
||||
* Java. Features:
|
||||
* <ul>
|
||||
* <li>Full support for the .xz file format specification version 1.0.4</li>
|
||||
* <li>Single-threaded streamed compression and decompression</li>
|
||||
* <li>Single-threaded decompression with limited random access support</li>
|
||||
* <li>Raw streams (no .xz headers) for advanced users, including LZMA2
|
||||
* with preset dictionary</li>
|
||||
* <li>Raw streams (no .xz headers) for advanced users, including LZMA2 with
|
||||
* preset dictionary</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Threading is planned but it is unknown when it will be implemented.
|
||||
@@ -21,15 +21,14 @@
|
||||
* <h4>Getting started</h4>
|
||||
* <p>
|
||||
* Start by reading the documentation of {@link org.tukaani.xz.XZOutputStream}
|
||||
* and {@link org.tukaani.xz.XZInputStream}.
|
||||
* If you use XZ inside another file format or protocol,
|
||||
* see also {@link org.tukaani.xz.SingleXZInputStream}.
|
||||
* and {@link org.tukaani.xz.XZInputStream}. If you use XZ inside another file
|
||||
* format or protocol, see also {@link org.tukaani.xz.SingleXZInputStream}.
|
||||
*
|
||||
* <h4>Licensing</h4>
|
||||
* <p>
|
||||
* XZ for Java has been put into the public domain, thus you can do
|
||||
* whatever you want with it. All the files in the package have been
|
||||
* written by Lasse Collin and/or Igor Pavlov.
|
||||
* XZ for Java has been put into the public domain, thus you can do whatever you
|
||||
* want with it. All the files in the package have been written by Lasse Collin
|
||||
* and/or Igor Pavlov.
|
||||
* <p>
|
||||
* This software is provided "as is", without any warranty.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,27 +18,35 @@ package rx;
|
||||
/**
|
||||
* Provides a mechanism for receiving push-based notifications.
|
||||
* <p>
|
||||
* After an Observer calls an {@link Observable}'s <code>Observable.subscribe</code> method, the {@link Observable} calls the Observer's <code>onNext</code> method to provide notifications. A
|
||||
* well-behaved {@link Observable} will
|
||||
* call an Observer's <code>onCompleted</code> closure exactly once or the Observer's <code>onError</code> closure exactly once.
|
||||
* After an Observer calls an {@link Observable}'s
|
||||
* <code>Observable.subscribe</code> method, the {@link Observable} calls the
|
||||
* Observer's <code>onNext</code> method to provide notifications. A
|
||||
* well-behaved {@link Observable} will call an Observer's
|
||||
* <code>onCompleted</code> closure exactly once or the Observer's
|
||||
* <code>onError</code> closure exactly once.
|
||||
* <p>
|
||||
* For more information see the <a href="https://github.com/Netflix/RxJava/wiki/Observable">RxJava Wiki</a>
|
||||
* For more information see the
|
||||
* <a href="https://github.com/Netflix/RxJava/wiki/Observable">RxJava Wiki</a>
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface Observer<T> {
|
||||
|
||||
/**
|
||||
* Notifies the Observer that the {@link Observable} has finished sending push-based notifications.
|
||||
* Notifies the Observer that the {@link Observable} has finished sending
|
||||
* push-based notifications.
|
||||
* <p>
|
||||
* The {@link Observable} will not call this closure if it calls <code>onError</code>.
|
||||
* The {@link Observable} will not call this closure if it calls
|
||||
* <code>onError</code>.
|
||||
*/
|
||||
public void onCompleted();
|
||||
|
||||
/**
|
||||
* Notifies the Observer that the {@link Observable} has experienced an error condition.
|
||||
* Notifies the Observer that the {@link Observable} has experienced an
|
||||
* error condition.
|
||||
* <p>
|
||||
* If the {@link Observable} calls this closure, it will not thereafter call <code>onNext</code> or <code>onCompleted</code>.
|
||||
* If the {@link Observable} calls this closure, it will not thereafter call
|
||||
* <code>onNext</code> or <code>onCompleted</code>.
|
||||
*
|
||||
* @param e
|
||||
*/
|
||||
@@ -47,9 +55,12 @@ public interface Observer<T> {
|
||||
/**
|
||||
* Provides the Observer with new data.
|
||||
* <p>
|
||||
* The {@link Observable} calls this closure 1 or more times, unless it calls <code>onError</code> in which case this closure may never be called.
|
||||
* The {@link Observable} calls this closure 1 or more times, unless it
|
||||
* calls <code>onError</code> in which case this closure may never be
|
||||
* called.
|
||||
* <p>
|
||||
* The {@link Observable} will not call this closure again after it calls either <code>onCompleted</code> or <code>onError</code>.
|
||||
* The {@link Observable} will not call this closure again after it calls
|
||||
* either <code>onCompleted</code> or <code>onError</code>.
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
|
||||
@@ -28,8 +28,8 @@ public interface Scheduler {
|
||||
/**
|
||||
* Schedules a cancelable action to be executed.
|
||||
*
|
||||
* @param action
|
||||
* action
|
||||
* @param action action
|
||||
*
|
||||
* @return a subscription to be able to unsubscribe from action.
|
||||
*/
|
||||
Subscription schedule(Func0<Subscription> action);
|
||||
@@ -37,8 +37,8 @@ public interface Scheduler {
|
||||
/**
|
||||
* Schedules an action to be executed.
|
||||
*
|
||||
* @param action
|
||||
* action
|
||||
* @param action action
|
||||
*
|
||||
* @return a subscription to be able to unsubscribe from action.
|
||||
*/
|
||||
Subscription schedule(Action0 action);
|
||||
@@ -46,8 +46,8 @@ public interface Scheduler {
|
||||
/**
|
||||
* Schedules an action to be executed in dueTime.
|
||||
*
|
||||
* @param action
|
||||
* action
|
||||
* @param action action
|
||||
*
|
||||
* @return a subscription to be able to unsubscribe from action.
|
||||
*/
|
||||
Subscription schedule(Action0 action, long dueTime, TimeUnit unit);
|
||||
@@ -55,8 +55,8 @@ public interface Scheduler {
|
||||
/**
|
||||
* Schedules a cancelable action to be executed in dueTime.
|
||||
*
|
||||
* @param action
|
||||
* action
|
||||
* @param action action
|
||||
*
|
||||
* @return a subscription to be able to unsubscribe from action.
|
||||
*/
|
||||
Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit);
|
||||
|
||||
@@ -18,16 +18,20 @@ package rx;
|
||||
import rx.subscriptions.Subscriptions;
|
||||
|
||||
/**
|
||||
* Subscription returns from {@link Observable#subscribe(Observer)} to allow unsubscribing.
|
||||
* Subscription returns from {@link Observable#subscribe(Observer)} to allow
|
||||
* unsubscribing.
|
||||
* <p>
|
||||
* See utilities in {@link Subscriptions} and implementations in the {@link rx.subscriptions} package.
|
||||
* See utilities in {@link Subscriptions} and implementations in the
|
||||
* {@link rx.subscriptions} package.
|
||||
*/
|
||||
public interface Subscription {
|
||||
|
||||
/**
|
||||
* Stop receiving notifications on the {@link Observer} that was registered when this Subscription was received.
|
||||
* Stop receiving notifications on the {@link Observer} that was registered
|
||||
* when this Subscription was received.
|
||||
* <p>
|
||||
* This allows unregistering an {@link Observer} before it has finished receiving all events (ie. before onCompleted is called).
|
||||
* This allows unregistering an {@link Observer} before it has finished
|
||||
* receiving all events (ie. before onCompleted is called).
|
||||
*/
|
||||
public void unsubscribe();
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ import rx.subscriptions.Subscriptions;
|
||||
import rx.util.functions.Action0;
|
||||
import rx.util.functions.Func0;
|
||||
|
||||
/* package */
|
||||
/*
|
||||
* package
|
||||
*/
|
||||
abstract class AbstractScheduler implements Scheduler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,9 +23,11 @@ import rx.Subscription;
|
||||
import rx.util.functions.Func0;
|
||||
|
||||
/**
|
||||
* Schedules work on the current thread but does not execute immediately. Work is put in a queue and executed after the current unit of work is completed.
|
||||
* Schedules work on the current thread but does not execute immediately. Work
|
||||
* is put in a queue and executed after the current unit of work is completed.
|
||||
*/
|
||||
public class CurrentThreadScheduler extends AbstractScheduler {
|
||||
|
||||
private static final CurrentThreadScheduler INSTANCE = new CurrentThreadScheduler();
|
||||
|
||||
public static CurrentThreadScheduler getInstance() {
|
||||
@@ -61,9 +63,8 @@ public class CurrentThreadScheduler extends AbstractScheduler {
|
||||
queue.add(action);
|
||||
|
||||
if (exec) {
|
||||
while (!queue.isEmpty()) {
|
||||
while (!queue.isEmpty())
|
||||
queue.poll().call();
|
||||
}
|
||||
|
||||
QUEUE.set(null);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,15 @@ import rx.util.AtomicObservableSubscription;
|
||||
import rx.util.functions.Func0;
|
||||
|
||||
/**
|
||||
* Combines standard {@link Subscription#unsubscribe()} functionality with ability to skip execution if an unsubscribe occurs before the {@link #call()} method is invoked.
|
||||
* Combines standard {@link Subscription#unsubscribe()} functionality with
|
||||
* ability to skip execution if an unsubscribe occurs before the {@link #call()}
|
||||
* method is invoked.
|
||||
*/
|
||||
/* package */class DiscardableAction implements Func0<Subscription>, Subscription {
|
||||
/*
|
||||
* package
|
||||
*/
|
||||
class DiscardableAction implements Func0<Subscription>, Subscription {
|
||||
|
||||
private final Func0<Subscription> underlying;
|
||||
|
||||
private final AtomicObservableSubscription wrapper = new AtomicObservableSubscription();
|
||||
|
||||
@@ -27,6 +27,7 @@ import rx.util.functions.Func0;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class EventQueueScheduler extends AbstractScheduler {
|
||||
|
||||
private static final EventQueueScheduler INSTANCE = new EventQueueScheduler();
|
||||
|
||||
public static EventQueueScheduler getInstance() {
|
||||
|
||||
@@ -24,6 +24,7 @@ import rx.util.functions.Func0;
|
||||
* Executes work immediately on the current thread.
|
||||
*/
|
||||
public final class ImmediateScheduler extends AbstractScheduler {
|
||||
|
||||
private static final ImmediateScheduler INSTANCE = new ImmediateScheduler();
|
||||
|
||||
public static ImmediateScheduler getInstance() {
|
||||
|
||||
@@ -24,6 +24,7 @@ import rx.util.functions.Func0;
|
||||
* Schedules work on a new thread.
|
||||
*/
|
||||
public class NewThreadScheduler extends AbstractScheduler {
|
||||
|
||||
private static final NewThreadScheduler INSTANCE = new NewThreadScheduler();
|
||||
|
||||
public static NewThreadScheduler getInstance() {
|
||||
|
||||
@@ -28,6 +28,7 @@ import rx.Scheduler;
|
||||
* Static factory methods for creating Schedulers.
|
||||
*/
|
||||
public class Schedulers {
|
||||
|
||||
private static final ScheduledExecutorService COMPUTATION_EXECUTOR = createComputationExecutor();
|
||||
private static final Executor IO_EXECUTOR = createIOExecutor();
|
||||
|
||||
@@ -45,7 +46,8 @@ public class Schedulers {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Scheduler} that queues work on the current thread to be executed after the current work completes.
|
||||
* {@link Scheduler} that queues work on the current thread to be executed
|
||||
* after the current work completes.
|
||||
*
|
||||
* @return {@link CurrentThreadScheduler} instance
|
||||
*/
|
||||
@@ -54,7 +56,8 @@ public class Schedulers {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Scheduler} that creates a new {@link Thread} for each unit of work.
|
||||
* {@link Scheduler} that creates a new {@link Thread} for each unit of
|
||||
* work.
|
||||
*
|
||||
* @return {@link NewThreadScheduler} instance
|
||||
*/
|
||||
@@ -63,7 +66,8 @@ public class Schedulers {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Scheduler} that queues work on the EventQueue thread to be executed on the Swing UI Thread.
|
||||
* {@link Scheduler} that queues work on the EventQueue thread to be
|
||||
* executed on the Swing UI Thread.
|
||||
*
|
||||
* @return {@link NewThreadScheduler} instance
|
||||
*/
|
||||
@@ -83,7 +87,8 @@ public class Schedulers {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Scheduler} that queues work on an {@link ScheduledExecutorService}.
|
||||
* {@link Scheduler} that queues work on an
|
||||
* {@link ScheduledExecutorService}.
|
||||
*
|
||||
* @return {@link ExecutorScheduler} instance
|
||||
*/
|
||||
@@ -94,11 +99,14 @@ public class Schedulers {
|
||||
/**
|
||||
* {@link Scheduler} intended for computational work.
|
||||
* <p>
|
||||
* The implementation is backed by a {@link ScheduledExecutorService} thread-pool sized to the number of CPU cores.
|
||||
* The implementation is backed by a {@link ScheduledExecutorService}
|
||||
* thread-pool sized to the number of CPU cores.
|
||||
* <p>
|
||||
* This can be used for event-loops, processing callbacks and other computational work.
|
||||
* This can be used for event-loops, processing callbacks and other
|
||||
* computational work.
|
||||
* <p>
|
||||
* Do not perform IO-bound work on this scheduler. Use {@link #threadPoolForComputation()} instead.
|
||||
* Do not perform IO-bound work on this scheduler. Use
|
||||
* {@link #threadPoolForComputation()} instead.
|
||||
*
|
||||
* @return {@link ExecutorScheduler} for computation-bound work.
|
||||
*/
|
||||
@@ -109,11 +117,13 @@ public class Schedulers {
|
||||
/**
|
||||
* {@link Scheduler} intended for IO-bound work.
|
||||
* <p>
|
||||
* The implementation is backed by an {@link Executor} thread-pool that will grow as needed.
|
||||
* The implementation is backed by an {@link Executor} thread-pool that will
|
||||
* grow as needed.
|
||||
* <p>
|
||||
* This can be used for asynchronously performing blocking IO.
|
||||
* <p>
|
||||
* Do not perform computational work on this scheduler. Use {@link #threadPoolForComputation()} instead.
|
||||
* Do not perform computational work on this scheduler. Use
|
||||
* {@link #threadPoolForComputation()} instead.
|
||||
*
|
||||
* @return {@link ExecutorScheduler} for IO-bound work.
|
||||
*/
|
||||
|
||||
@@ -21,7 +21,11 @@ import rx.Scheduler;
|
||||
import rx.Subscription;
|
||||
import rx.util.functions.Func0;
|
||||
|
||||
/* package */class SleepingAction implements Func0<Subscription> {
|
||||
/*
|
||||
* package
|
||||
*/
|
||||
class SleepingAction implements Func0<Subscription> {
|
||||
|
||||
private final Func0<Subscription> underlying;
|
||||
private final Scheduler scheduler;
|
||||
private final long execTime;
|
||||
@@ -34,14 +38,13 @@ import rx.util.functions.Func0;
|
||||
|
||||
@Override
|
||||
public Subscription call() {
|
||||
if (execTime < scheduler.now()) {
|
||||
if (execTime < scheduler.now())
|
||||
try {
|
||||
Thread.sleep(scheduler.now() - execTime);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return underlying.call();
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ import rx.Subscription;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* An {@link Observable} that has been grouped by a key whose value can be obtained using {@link #getKey()} <p>
|
||||
* An {@link Observable} that has been grouped by a key whose value can be
|
||||
* obtained using {@link #getKey()}
|
||||
* <p>
|
||||
*
|
||||
* @see {@link Observable#groupBy(Observable, Func1)}
|
||||
*
|
||||
@@ -29,6 +31,7 @@ import rx.util.functions.Func1;
|
||||
* @param <T>
|
||||
*/
|
||||
public class GroupedObservable<K, T> extends Observable<T> {
|
||||
|
||||
private final K key;
|
||||
|
||||
public GroupedObservable(K key, Func1<Observer<T>, Subscription> onSubscribe) {
|
||||
|
||||
@@ -15,19 +15,18 @@ public class OperationAll {
|
||||
}
|
||||
|
||||
private static class AllObservable<T> implements Func1<Observer<Boolean>, Subscription> {
|
||||
|
||||
private final Observable<T> sequence;
|
||||
private final Func1<T, Boolean> predicate;
|
||||
|
||||
private final AtomicBoolean status = new AtomicBoolean(true);
|
||||
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||
|
||||
|
||||
private AllObservable(Observable<T> sequence, Func1<T, Boolean> predicate) {
|
||||
this.sequence = sequence;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Subscription call(final Observer<Boolean> observer) {
|
||||
return subscription.wrap(sequence.subscribe(new Observer<T>() {
|
||||
|
||||
@@ -36,12 +36,18 @@ import rx.util.functions.Functions;
|
||||
public class OperationCombineLatest {
|
||||
|
||||
/**
|
||||
* Combines the two given observables, emitting an event containing an aggregation of the latest values of each of the source observables
|
||||
* each time an event is received from one of the source observables, where the aggregation is defined by the given function.
|
||||
* Combines the two given observables, emitting an event containing an
|
||||
* aggregation of the latest values of each of the source observables each
|
||||
* time an event is received from one of the source observables, where the
|
||||
* aggregation is defined by the given function.
|
||||
*
|
||||
* @param w0 The first source observable.
|
||||
* @param w1 The second source observable.
|
||||
* @param combineLatestFunction The aggregation function used to combine the source observable values.
|
||||
* @return A function from an observer to a subscription. This can be used to create an observable from.
|
||||
* @param combineLatestFunction The aggregation function used to combine the
|
||||
* source observable values.
|
||||
*
|
||||
* @return A function from an observer to a subscription. This can be used
|
||||
* to create an observable from.
|
||||
*/
|
||||
public static <T0, T1, R> Func1<Observer<R>, Subscription> combineLatest(Observable<T0> w0, Observable<T1> w1, Func2<T0, T1, R> combineLatestFunction) {
|
||||
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(combineLatestFunction));
|
||||
@@ -51,7 +57,8 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #combineLatest(Observable w0, Observable w1, Func2 combineLatestFunction)
|
||||
* @see #combineLatest(Observable w0, Observable w1, Func2
|
||||
* combineLatestFunction)
|
||||
*/
|
||||
public static <T0, T1, T2, R> Func1<Observer<R>, Subscription> combineLatest(Observable<T0> w0, Observable<T1> w1, Observable<T2> w2, Func3<T0, T1, T2, R> combineLatestFunction) {
|
||||
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(combineLatestFunction));
|
||||
@@ -62,7 +69,8 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #combineLatest(Observable w0, Observable w1, Func2 combineLatestFunction)
|
||||
* @see #combineLatest(Observable w0, Observable w1, Func2
|
||||
* combineLatestFunction)
|
||||
*/
|
||||
public static <T0, T1, T2, T3, R> Func1<Observer<R>, Subscription> combineLatest(Observable<T0> w0, Observable<T1> w1, Observable<T2> w2, Observable<T3> w3, Func4<T0, T1, T2, T3, R> combineLatestFunction) {
|
||||
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(combineLatestFunction));
|
||||
@@ -74,6 +82,7 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
private static class CombineObserver<R, T> implements Observer<T> {
|
||||
|
||||
final Observable<T> w;
|
||||
final Aggregator<R> a;
|
||||
private Subscription subscription;
|
||||
@@ -84,9 +93,8 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
public synchronized void startWatching() {
|
||||
if (subscription != null) {
|
||||
if (subscription != null)
|
||||
throw new RuntimeException("This should only be called once.");
|
||||
}
|
||||
subscription = w.subscribe(this);
|
||||
}
|
||||
|
||||
@@ -107,9 +115,10 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive notifications from each of the observables we are reducing and execute the combineLatestFunction
|
||||
* whenever we have received an event from one of the observables, as soon as each Observable has received
|
||||
* at least one event.
|
||||
* Receive notifications from each of the observables we are reducing and
|
||||
* execute the combineLatestFunction whenever we have received an event from
|
||||
* one of the observables, as soon as each Observable has received at least
|
||||
* one event.
|
||||
*/
|
||||
private static class Aggregator<R> implements Func1<Observer<R>, Subscription> {
|
||||
|
||||
@@ -124,27 +133,33 @@ public class OperationCombineLatest {
|
||||
/**
|
||||
* Store when an observer completes.
|
||||
* <p>
|
||||
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject' above.
|
||||
* */
|
||||
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject'
|
||||
* above.
|
||||
*
|
||||
*/
|
||||
private final Set<CombineObserver<R, ?>> completed = new HashSet<>();
|
||||
|
||||
/**
|
||||
* The latest value from each observer
|
||||
* <p>
|
||||
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject' above.
|
||||
* */
|
||||
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject'
|
||||
* above.
|
||||
*
|
||||
*/
|
||||
private final Map<CombineObserver<R, ?>, Object> latestValue = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Whether each observer has a latest value at all.
|
||||
* <p>
|
||||
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject' above.
|
||||
* */
|
||||
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject'
|
||||
* above.
|
||||
*
|
||||
*/
|
||||
private final Set<CombineObserver<R, ?>> hasLatestValue = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Ordered list of observers to combine.
|
||||
* No synchronization is necessary as these can not be added or changed asynchronously.
|
||||
* Ordered list of observers to combine. No synchronization is necessary
|
||||
* as these can not be added or changed asynchronously.
|
||||
*/
|
||||
private final List<CombineObserver<R, ?>> observers = new LinkedList<>();
|
||||
|
||||
@@ -153,7 +168,8 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive notification of a Observer starting (meaning we should require it for aggregation)
|
||||
* Receive notification of a Observer starting (meaning we should
|
||||
* require it for aggregation)
|
||||
*
|
||||
* @param w The observer to add.
|
||||
*/
|
||||
@@ -171,7 +187,7 @@ public class OperationCombineLatest {
|
||||
// store that this CombineLatestObserver is completed
|
||||
completed.add(w);
|
||||
// if all CombineObservers are completed, we mark the whole thing as completed
|
||||
if (completed.size() == observers.size()) {
|
||||
if (completed.size() == observers.size())
|
||||
if (running.get()) {
|
||||
// mark ourselves as done
|
||||
observer.onCompleted();
|
||||
@@ -180,34 +196,39 @@ public class OperationCombineLatest {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive error for a Observer. Throw the error up the chain and stop processing.
|
||||
* Receive error for a Observer. Throw the error up the chain and stop
|
||||
* processing.
|
||||
*/
|
||||
void error(Exception e) {
|
||||
observer.onError(e);
|
||||
/* tell all observers to unsubscribe since we had an error */
|
||||
/*
|
||||
* tell all observers to unsubscribe since we had an error
|
||||
*/
|
||||
stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive the next value from an observer.
|
||||
* <p>
|
||||
* If we have received values from all observers, trigger the combineLatest function, otherwise store the value and keep waiting.
|
||||
* If we have received values from all observers, trigger the
|
||||
* combineLatest function, otherwise store the value and keep waiting.
|
||||
*
|
||||
* @param w
|
||||
* @param arg
|
||||
*/
|
||||
<T> void next(CombineObserver<R, T> w, T arg) {
|
||||
if (observer == null) {
|
||||
if (observer == null)
|
||||
throw new RuntimeException("This shouldn't be running if an Observer isn't registered");
|
||||
}
|
||||
|
||||
/* if we've been 'unsubscribed' don't process anything further even if the things we're watching keep sending (likely because they are not responding to the unsubscribe call) */
|
||||
if (!running.get()) {
|
||||
/*
|
||||
* if we've been 'unsubscribed' don't process anything further even
|
||||
* if the things we're watching keep sending (likely because they
|
||||
* are not responding to the unsubscribe call)
|
||||
*/
|
||||
if (!running.get())
|
||||
return;
|
||||
}
|
||||
|
||||
// define here so the variable is out of the synchronized scope
|
||||
Object[] argsToCombineLatest = new Object[observers.size()];
|
||||
@@ -221,18 +242,15 @@ public class OperationCombineLatest {
|
||||
hasLatestValue.add(w);
|
||||
|
||||
// if all observers in the 'observers' list have a value, invoke the combineLatestFunction
|
||||
for (CombineObserver<R, ?> rw : observers) {
|
||||
if (!hasLatestValue.contains(rw)) {
|
||||
for (CombineObserver<R, ?> rw : observers)
|
||||
if (!hasLatestValue.contains(rw))
|
||||
// we don't have a value yet for each observer to combine, so we don't have a combined value yet either
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if we get to here this means all the queues have data
|
||||
int i = 0;
|
||||
for (CombineObserver<R, ?> _w : observers) {
|
||||
for (CombineObserver<R, ?> _w : observers)
|
||||
argsToCombineLatest[i++] = latestValue.get(_w);
|
||||
}
|
||||
}
|
||||
// if we did not return above from the synchronized block we can now invoke the combineLatestFunction with all of the args
|
||||
// we do this outside the synchronized block as it is now safe to call this concurrently and don't need to block other threads from calling
|
||||
// this 'next' method while another thread finishes calling this combineLatestFunction
|
||||
@@ -241,15 +259,15 @@ public class OperationCombineLatest {
|
||||
|
||||
@Override
|
||||
public Subscription call(Observer<R> observer) {
|
||||
if (this.observer != null) {
|
||||
if (this.observer != null)
|
||||
throw new IllegalStateException("Only one Observer can subscribe to this Observable.");
|
||||
}
|
||||
this.observer = observer;
|
||||
|
||||
/* start the observers */
|
||||
for (CombineObserver<R, ?> rw : observers) {
|
||||
/*
|
||||
* start the observers
|
||||
*/
|
||||
for (CombineObserver<R, ?> rw : observers)
|
||||
rw.startWatching();
|
||||
}
|
||||
|
||||
return new Subscription() {
|
||||
@Override
|
||||
@@ -260,14 +278,16 @@ public class OperationCombineLatest {
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
/* tell ourselves to stop processing onNext events */
|
||||
/*
|
||||
* tell ourselves to stop processing onNext events
|
||||
*/
|
||||
running.set(false);
|
||||
/* propogate to all observers to unsubscribe */
|
||||
for (CombineObserver<R, ?> rw : observers) {
|
||||
if (rw.subscription != null) {
|
||||
/*
|
||||
* propogate to all observers to unsubscribe
|
||||
*/
|
||||
for (CombineObserver<R, ?> rw : observers)
|
||||
if (rw.subscription != null)
|
||||
rw.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,13 @@ import rx.util.functions.Func1;
|
||||
public final class OperationConcat {
|
||||
|
||||
/**
|
||||
* Combine the observable sequences from the list of Observables into one observable sequence without any transformation.
|
||||
* Combine the observable sequences from the list of Observables into one
|
||||
* observable sequence without any transformation.
|
||||
*
|
||||
* @param sequences
|
||||
* An observable sequence of elements to project.
|
||||
* @return An observable sequence whose elements are the result of combining the output from the list of Observables.
|
||||
* @param sequences An observable sequence of elements to project.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of combining
|
||||
* the output from the list of Observables.
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> concat(final Observable<T>... sequences) {
|
||||
return new Func1<Observer<T>, Subscription>() {
|
||||
@@ -66,6 +68,7 @@ public final class OperationConcat {
|
||||
}
|
||||
|
||||
private static class Concat<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Observable<T>[] sequences;
|
||||
private int num = 0;
|
||||
private int count = 0;
|
||||
@@ -94,6 +97,7 @@ public final class OperationConcat {
|
||||
}
|
||||
|
||||
private class ConcatObserver implements Observer<T> {
|
||||
|
||||
private final Observer<T> observer;
|
||||
|
||||
ConcatObserver(Observer<T> observer) {
|
||||
|
||||
@@ -22,17 +22,23 @@ import rx.Subscription;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* Dematerializes the explicit notification values of an observable sequence as implicit notifications.
|
||||
* See http://msdn.microsoft.com/en-us/library/hh229047(v=vs.103).aspx for the Microsoft Rx equivalent.
|
||||
* Dematerializes the explicit notification values of an observable sequence as
|
||||
* implicit notifications. See
|
||||
* http://msdn.microsoft.com/en-us/library/hh229047(v=vs.103).aspx for the
|
||||
* Microsoft Rx equivalent.
|
||||
*/
|
||||
public final class OperationDematerialize {
|
||||
|
||||
/**
|
||||
* Dematerializes the explicit notification values of an observable sequence as implicit notifications.
|
||||
* Dematerializes the explicit notification values of an observable sequence
|
||||
* as implicit notifications.
|
||||
*
|
||||
* @param sequence An observable sequence containing explicit notification
|
||||
* values which have to be turned into implicit notifications.
|
||||
*
|
||||
* @return An observable sequence exhibiting the behavior corresponding to
|
||||
* the source sequence's notification values.
|
||||
*
|
||||
* @param sequence
|
||||
* An observable sequence containing explicit notification values which have to be turned into implicit notifications.
|
||||
* @return An observable sequence exhibiting the behavior corresponding to the source sequence's notification values.
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh229047(v=vs.103).aspx
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> dematerialize(final Observable<Notification<T>> sequence) {
|
||||
|
||||
@@ -44,9 +44,8 @@ public final class OperationFilter<T> {
|
||||
@Override
|
||||
public void onNext(T value) {
|
||||
try {
|
||||
if (predicate.call(value)) {
|
||||
if (predicate.call(value))
|
||||
observer.onNext(value);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
observer.onError(ex);
|
||||
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
|
||||
|
||||
@@ -32,18 +32,24 @@ public final class OperationFinally {
|
||||
* so we use "finallyDo".
|
||||
*
|
||||
* @param sequence An observable sequence of elements
|
||||
* @param action An action to be taken when the sequence is complete or throws an exception
|
||||
* @return An observable sequence with the same elements as the input.
|
||||
* After the last element is consumed (and {@link Observer#onCompleted} has been called),
|
||||
* or after an exception is thrown (and {@link Observer#onError} has been called),
|
||||
* the given action will be called.
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/hh212133(v=vs.103).aspx">MSDN Observable.Finally method</a>
|
||||
* @param action An action to be taken when the sequence is complete or
|
||||
* throws an exception
|
||||
*
|
||||
* @return An observable sequence with the same elements as the input. After
|
||||
* the last element is consumed (and {@link Observer#onCompleted} has been
|
||||
* called), or after an exception is thrown (and {@link Observer#onError}
|
||||
* has been called), the given action will be called.
|
||||
*
|
||||
* @see
|
||||
* <a href="http://msdn.microsoft.com/en-us/library/hh212133(v=vs.103).aspx">MSDN
|
||||
* Observable.Finally method</a>
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> finallyDo(final Observable<T> sequence, final Action0 action) {
|
||||
return new Finally<>(sequence, action)::call;
|
||||
}
|
||||
|
||||
private static class Finally<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Observable<T> sequence;
|
||||
private final Action0 finalAction;
|
||||
|
||||
@@ -58,6 +64,7 @@ public final class OperationFinally {
|
||||
}
|
||||
|
||||
private class FinallyObserver implements Observer<T> {
|
||||
|
||||
private final Observer<T> observer;
|
||||
|
||||
FinallyObserver(Observer<T> observer) {
|
||||
|
||||
@@ -23,52 +23,51 @@ import rx.util.functions.Func1;
|
||||
public final class OperationMap {
|
||||
|
||||
/**
|
||||
* Accepts a sequence and a transformation function. Returns a sequence that is the result of
|
||||
* applying the transformation function to each item in the sequence.
|
||||
* Accepts a sequence and a transformation function. Returns a sequence that
|
||||
* is the result of applying the transformation function to each item in the
|
||||
* sequence.
|
||||
*
|
||||
* @param sequence
|
||||
* the input sequence.
|
||||
* @param func
|
||||
* a function to apply to each item in the sequence.
|
||||
* @param <T>
|
||||
* the type of the input sequence.
|
||||
* @param <R>
|
||||
* the type of the output sequence.
|
||||
* @return a sequence that is the result of applying the transformation function to each item in the input sequence.
|
||||
* @param sequence the input sequence.
|
||||
* @param func a function to apply to each item in the sequence.
|
||||
* @param <T> the type of the input sequence.
|
||||
* @param <R> the type of the output sequence.
|
||||
*
|
||||
* @return a sequence that is the result of applying the transformation
|
||||
* function to each item in the input sequence.
|
||||
*/
|
||||
public static <T, R> Func1<Observer<R>, Subscription> map(Observable<T> sequence, Func1<T, R> func) {
|
||||
return new MapObservable<>(sequence, func);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a sequence of observable sequences and a transformation function. Returns a flattened sequence that is the result of
|
||||
* applying the transformation function to each item in the sequence of each observable sequence.
|
||||
* Accepts a sequence of observable sequences and a transformation function.
|
||||
* Returns a flattened sequence that is the result of applying the
|
||||
* transformation function to each item in the sequence of each observable
|
||||
* sequence.
|
||||
* <p>
|
||||
* The closure should return an Observable which will then be merged.
|
||||
*
|
||||
* @param sequence
|
||||
* the input sequence.
|
||||
* @param func
|
||||
* a function to apply to each item in the sequence.
|
||||
* @param <T>
|
||||
* the type of the input sequence.
|
||||
* @param <R>
|
||||
* the type of the output sequence.
|
||||
* @return a sequence that is the result of applying the transformation function to each item in the input sequence.
|
||||
* @param sequence the input sequence.
|
||||
* @param func a function to apply to each item in the sequence.
|
||||
* @param <T> the type of the input sequence.
|
||||
* @param <R> the type of the output sequence.
|
||||
*
|
||||
* @return a sequence that is the result of applying the transformation
|
||||
* function to each item in the input sequence.
|
||||
*/
|
||||
public static <T, R> Func1<Observer<R>, Subscription> mapMany(Observable<T> sequence, Func1<T, Observable<R>> func) {
|
||||
return OperationMerge.merge(Observable.create(map(sequence, func)));
|
||||
}
|
||||
|
||||
/**
|
||||
* An observable sequence that is the result of applying a transformation to each item in an input sequence.
|
||||
* An observable sequence that is the result of applying a transformation to
|
||||
* each item in an input sequence.
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the input sequence.
|
||||
* @param <R>
|
||||
* the type of the output sequence.
|
||||
* @param <T> the type of the input sequence.
|
||||
* @param <R> the type of the output sequence.
|
||||
*/
|
||||
private static class MapObservable<T, R> implements Func1<Observer<R>, Subscription> {
|
||||
|
||||
public MapObservable(Observable<T> sequence, Func1<T, R> func) {
|
||||
this.sequence = sequence;
|
||||
this.func = func;
|
||||
@@ -85,14 +84,14 @@ public final class OperationMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* An observer that applies a transformation function to each item and forwards the result to an inner observer.
|
||||
* An observer that applies a transformation function to each item and
|
||||
* forwards the result to an inner observer.
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the observer items.
|
||||
* @param <R>
|
||||
* the type of the inner observer items.
|
||||
* @param <T> the type of the observer items.
|
||||
* @param <R> the type of the inner observer items.
|
||||
*/
|
||||
private static class MapObserver<T, R> implements Observer<T> {
|
||||
|
||||
public MapObserver(Observer<R> observer, Func1<T, R> func) {
|
||||
this.observer = observer;
|
||||
this.func = func;
|
||||
|
||||
@@ -22,20 +22,27 @@ import rx.Subscription;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* Materializes the implicit notifications of an observable sequence as explicit notification values.
|
||||
* Materializes the implicit notifications of an observable sequence as explicit
|
||||
* notification values.
|
||||
* <p>
|
||||
* In other words, converts a sequence of OnNext, OnError and OnCompleted events into a sequence of ObservableNotifications containing the OnNext, OnError and OnCompleted values.
|
||||
* In other words, converts a sequence of OnNext, OnError and OnCompleted events
|
||||
* into a sequence of ObservableNotifications containing the OnNext, OnError and
|
||||
* OnCompleted values.
|
||||
* <p>
|
||||
* See http://msdn.microsoft.com/en-us/library/hh229453(v=VS.103).aspx for the Microsoft Rx equivalent.
|
||||
* See http://msdn.microsoft.com/en-us/library/hh229453(v=VS.103).aspx for the
|
||||
* Microsoft Rx equivalent.
|
||||
*/
|
||||
public final class OperationMaterialize {
|
||||
|
||||
/**
|
||||
* Materializes the implicit notifications of an observable sequence as explicit notification values.
|
||||
* Materializes the implicit notifications of an observable sequence as
|
||||
* explicit notification values.
|
||||
*
|
||||
* @param sequence An observable sequence of elements to project.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of
|
||||
* materializing the notifications of the given sequence.
|
||||
*
|
||||
* @param sequence
|
||||
* An observable sequence of elements to project.
|
||||
* @return An observable sequence whose elements are the result of materializing the notifications of the given sequence.
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh229453(v=VS.103).aspx
|
||||
*/
|
||||
public static <T> Func1<Observer<Notification<T>>, Subscription> materialize(final Observable<T> sequence) {
|
||||
|
||||
@@ -30,11 +30,14 @@ import rx.util.functions.Func1;
|
||||
public final class OperationMerge {
|
||||
|
||||
/**
|
||||
* Flattens the observable sequences from the list of Observables into one observable sequence without any transformation.
|
||||
* Flattens the observable sequences from the list of Observables into one
|
||||
* observable sequence without any transformation.
|
||||
*
|
||||
* @param source An observable sequence of elements to project.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of
|
||||
* flattening the output from the list of Observables.
|
||||
*
|
||||
* @param source
|
||||
* An observable sequence of elements to project.
|
||||
* @return An observable sequence whose elements are the result of flattening the output from the list of Observables.
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh229099(v=vs.103).aspx
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> merge(final Observable<Observable<T>> source) {
|
||||
@@ -53,17 +56,14 @@ public final class OperationMerge {
|
||||
|
||||
@Override
|
||||
public Subscription call(Observer<Observable<T>> observer) {
|
||||
for (Observable<T> o : sequences) {
|
||||
if (!unsubscribed) {
|
||||
for (Observable<T> o : sequences)
|
||||
if (!unsubscribed)
|
||||
observer.onNext(o);
|
||||
} else {
|
||||
else
|
||||
// break out of the loop if we are unsubscribed
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!unsubscribed) {
|
||||
if (!unsubscribed)
|
||||
observer.onCompleted();
|
||||
}
|
||||
|
||||
return () -> {
|
||||
unsubscribed = true;
|
||||
@@ -73,17 +73,24 @@ public final class OperationMerge {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times. In other words, don't subscribe to it multiple times from different threads.
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times.
|
||||
* In other words, don't subscribe to it multiple times from different
|
||||
* threads.
|
||||
* <p>
|
||||
* It IS thread-safe from within it while receiving onNext events from multiple threads.
|
||||
* It IS thread-safe from within it while receiving onNext events from
|
||||
* multiple threads.
|
||||
* <p>
|
||||
* This should all be fine as long as it's kept as a private class and a new instance created from static factory method above.
|
||||
* This should all be fine as long as it's kept as a private class and a new
|
||||
* instance created from static factory method above.
|
||||
* <p>
|
||||
* Note how the take() factory method above protects us from a single instance being exposed with the Observable wrapper handling the subscribe flow.
|
||||
* Note how the take() factory method above protects us from a single
|
||||
* instance being exposed with the Observable wrapper handling the subscribe
|
||||
* flow.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private static final class MergeObservable<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Observable<Observable<T>> sequences;
|
||||
private final MergeSubscription ourSubscription = new MergeSubscription();
|
||||
private final AtomicBoolean stopped = new AtomicBoolean(false);
|
||||
@@ -99,7 +106,8 @@ public final class OperationMerge {
|
||||
public Subscription call(Observer<T> actualObserver) {
|
||||
|
||||
/**
|
||||
* We must synchronize a merge because we subscribe to multiple sequences in parallel that will each be emitting.
|
||||
* We must synchronize a merge because we subscribe to multiple
|
||||
* sequences in parallel that will each be emitting.
|
||||
* <p>
|
||||
* The calls from each sequence must be serialized.
|
||||
* <p>
|
||||
@@ -109,18 +117,23 @@ public final class OperationMerge {
|
||||
SynchronizedObserver<T> synchronizedObserver = new SynchronizedObserver<>(actualObserver, subscription);
|
||||
|
||||
/**
|
||||
* Subscribe to the parent Observable to get to the children Observables
|
||||
* Subscribe to the parent Observable to get to the children
|
||||
* Observables
|
||||
*/
|
||||
sequences.subscribe(new ParentObserver(synchronizedObserver));
|
||||
|
||||
/* return our subscription to allow unsubscribing */
|
||||
/*
|
||||
* return our subscription to allow unsubscribing
|
||||
*/
|
||||
return subscription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the internal subscription with a thread-safe means of stopping/unsubscribing so we don't unsubscribe twice.
|
||||
* Manage the internal subscription with a thread-safe means of
|
||||
* stopping/unsubscribing so we don't unsubscribe twice.
|
||||
* <p>
|
||||
* Also has the stop() method returning a boolean so callers know if their thread "won" and should perform further actions.
|
||||
* Also has the stop() method returning a boolean so callers know if
|
||||
* their thread "won" and should perform further actions.
|
||||
*/
|
||||
private class MergeSubscription implements Subscription {
|
||||
|
||||
@@ -134,23 +147,23 @@ public final class OperationMerge {
|
||||
boolean didSet = stopped.compareAndSet(false, true);
|
||||
if (didSet) {
|
||||
// this thread won the race to stop, so unsubscribe from the actualSubscription
|
||||
for (Subscription _s : childSubscriptions.values()) {
|
||||
for (Subscription _s : childSubscriptions.values())
|
||||
_s.unsubscribe();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
} else
|
||||
// another thread beat us
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the top level Observable to receive the sequence of Observable<T> children.
|
||||
* Subscribe to the top level Observable to receive the sequence of
|
||||
* Observable<T> children.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private class ParentObserver implements Observer<Observable<T>> {
|
||||
|
||||
private final Observer<T> actualObserver;
|
||||
|
||||
public ParentObserver(Observer<T> actualObserver) {
|
||||
@@ -164,14 +177,11 @@ public final class OperationMerge {
|
||||
// but will let the child worry about it
|
||||
// if however this completes and there are no children processing, then we will send onCompleted
|
||||
|
||||
if (childObservers.isEmpty()) {
|
||||
if (!stopped.get()) {
|
||||
if (ourSubscription.stop()) {
|
||||
if (childObservers.isEmpty())
|
||||
if (!stopped.get())
|
||||
if (ourSubscription.stop())
|
||||
actualObserver.onCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
@@ -180,20 +190,21 @@ public final class OperationMerge {
|
||||
|
||||
@Override
|
||||
public void onNext(Observable<T> childObservable) {
|
||||
if (stopped.get()) {
|
||||
if (stopped.get())
|
||||
// we won't act on any further items
|
||||
return;
|
||||
}
|
||||
|
||||
if (childObservable == null) {
|
||||
if (childObservable == null)
|
||||
throw new IllegalArgumentException("Observable<T> can not be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* For each child Observable we receive we'll subscribe with a separate Observer
|
||||
* that will each then forward their sequences to the actualObserver.
|
||||
* For each child Observable we receive we'll subscribe with a
|
||||
* separate Observer that will each then forward their sequences
|
||||
* to the actualObserver.
|
||||
* <p>
|
||||
* We use separate child Observers for each sequence to simplify the onComplete/onError handling so each sequence has its own lifecycle.
|
||||
* We use separate child Observers for each sequence to simplify
|
||||
* the onComplete/onError handling so each sequence has its own
|
||||
* lifecycle.
|
||||
*/
|
||||
ChildObserver _w = new ChildObserver(actualObserver);
|
||||
childObservers.put(_w, _w);
|
||||
@@ -204,7 +215,8 @@ public final class OperationMerge {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to each child Observable<T> and forward their sequence of data to the actualObserver
|
||||
* Subscribe to each child Observable<T> and forward their sequence of
|
||||
* data to the actualObserver
|
||||
*
|
||||
*/
|
||||
private class ChildObserver implements Observer<T> {
|
||||
@@ -221,34 +233,28 @@ public final class OperationMerge {
|
||||
childObservers.remove(this);
|
||||
// if there are now 0 Observers left, so if the parent is also completed we send the onComplete to the actualObserver
|
||||
// if the parent is not complete that means there is another sequence (and child Observer) to come
|
||||
if (!stopped.get()) {
|
||||
if (childObservers.isEmpty() && parentCompleted) {
|
||||
if (ourSubscription.stop()) {
|
||||
if (!stopped.get())
|
||||
if (childObservers.isEmpty() && parentCompleted)
|
||||
if (ourSubscription.stop())
|
||||
// this thread 'won' the race to unsubscribe/stop so let's send onCompleted
|
||||
actualObserver.onCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
if (!stopped.get()) {
|
||||
if (ourSubscription.stop()) {
|
||||
if (!stopped.get())
|
||||
if (ourSubscription.stop())
|
||||
// this thread 'won' the race to unsubscribe/stop so let's send the error
|
||||
actualObserver.onError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(T args) {
|
||||
// in case the Observable is poorly behaved and doesn't listen to the unsubscribe request
|
||||
// we'll ignore anything that comes in after we've unsubscribed
|
||||
if (!stopped.get()) {
|
||||
if (!stopped.get())
|
||||
actualObserver.onNext(args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,23 +27,30 @@ import rx.util.CompositeException;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* Same functionality as OperationMerge except that onError events will be skipped so that all onNext calls are passed on until all sequences finish with onComplete or onError, and then the first
|
||||
* onError received (if any) will be passed on.
|
||||
* Same functionality as OperationMerge except that onError events will be
|
||||
* skipped so that all onNext calls are passed on until all sequences finish
|
||||
* with onComplete or onError, and then the first onError received (if any) will
|
||||
* be passed on.
|
||||
* <p>
|
||||
* This allows retrieving all successful onNext calls without being blocked by an onError early in a sequence.
|
||||
* This allows retrieving all successful onNext calls without being blocked by
|
||||
* an onError early in a sequence.
|
||||
* <p>
|
||||
* NOTE: If this is used on an infinite stream it will never call onError and effectively will swallow errors.
|
||||
* NOTE: If this is used on an infinite stream it will never call onError and
|
||||
* effectively will swallow errors.
|
||||
*/
|
||||
public final class OperationMergeDelayError {
|
||||
|
||||
/**
|
||||
* Flattens the observable sequences from the list of Observables into one observable sequence without any transformation and delays any onError calls until after all sequences have called
|
||||
* onError or onComplete so as to allow all successful
|
||||
* onNext calls to be received.
|
||||
* Flattens the observable sequences from the list of Observables into one
|
||||
* observable sequence without any transformation and delays any onError
|
||||
* calls until after all sequences have called onError or onComplete so as
|
||||
* to allow all successful onNext calls to be received.
|
||||
*
|
||||
* @param source An observable sequence of elements to project.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of
|
||||
* flattening the output from the list of Observables.
|
||||
*
|
||||
* @param source
|
||||
* An observable sequence of elements to project.
|
||||
* @return An observable sequence whose elements are the result of flattening the output from the list of Observables.
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh229099(v=vs.103).aspx
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> mergeDelayError(final Observable<Observable<T>> sequences) {
|
||||
@@ -63,17 +70,14 @@ public final class OperationMergeDelayError {
|
||||
|
||||
@Override
|
||||
public Subscription call(Observer<Observable<T>> observer) {
|
||||
for (Observable<T> o : sequences) {
|
||||
if (!unsubscribed) {
|
||||
for (Observable<T> o : sequences)
|
||||
if (!unsubscribed)
|
||||
observer.onNext(o);
|
||||
} else {
|
||||
else
|
||||
// break out of the loop if we are unsubscribed
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!unsubscribed) {
|
||||
if (!unsubscribed)
|
||||
observer.onCompleted();
|
||||
}
|
||||
return new Subscription() {
|
||||
|
||||
@Override
|
||||
@@ -93,17 +97,14 @@ public final class OperationMergeDelayError {
|
||||
|
||||
@Override
|
||||
public Subscription call(Observer<Observable<T>> observer) {
|
||||
for (Observable<T> o : sequences) {
|
||||
if (!unsubscribed) {
|
||||
for (Observable<T> o : sequences)
|
||||
if (!unsubscribed)
|
||||
observer.onNext(o);
|
||||
} else {
|
||||
else
|
||||
// break out of the loop if we are unsubscribed
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!unsubscribed) {
|
||||
if (!unsubscribed)
|
||||
observer.onCompleted();
|
||||
}
|
||||
|
||||
return new Subscription() {
|
||||
|
||||
@@ -118,17 +119,24 @@ public final class OperationMergeDelayError {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times. In other words, don't subscribe to it multiple times from different threads.
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times.
|
||||
* In other words, don't subscribe to it multiple times from different
|
||||
* threads.
|
||||
* <p>
|
||||
* It IS thread-safe from within it while receiving onNext events from multiple threads.
|
||||
* It IS thread-safe from within it while receiving onNext events from
|
||||
* multiple threads.
|
||||
* <p>
|
||||
* This should all be fine as long as it's kept as a private class and a new instance created from static factory method above.
|
||||
* This should all be fine as long as it's kept as a private class and a new
|
||||
* instance created from static factory method above.
|
||||
* <p>
|
||||
* Note how the take() factory method above protects us from a single instance being exposed with the Observable wrapper handling the subscribe flow.
|
||||
* Note how the take() factory method above protects us from a single
|
||||
* instance being exposed with the Observable wrapper handling the subscribe
|
||||
* flow.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private static final class MergeDelayErrorObservable<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Observable<Observable<T>> sequences;
|
||||
private final MergeSubscription ourSubscription = new MergeSubscription();
|
||||
private AtomicBoolean stopped = new AtomicBoolean(false);
|
||||
@@ -144,18 +152,23 @@ public final class OperationMergeDelayError {
|
||||
|
||||
public Subscription call(Observer<T> actualObserver) {
|
||||
/**
|
||||
* Subscribe to the parent Observable to get to the children Observables
|
||||
* Subscribe to the parent Observable to get to the children
|
||||
* Observables
|
||||
*/
|
||||
sequences.subscribe(new ParentObserver(actualObserver));
|
||||
|
||||
/* return our subscription to allow unsubscribing */
|
||||
/*
|
||||
* return our subscription to allow unsubscribing
|
||||
*/
|
||||
return ourSubscription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the internal subscription with a thread-safe means of stopping/unsubscribing so we don't unsubscribe twice.
|
||||
* Manage the internal subscription with a thread-safe means of
|
||||
* stopping/unsubscribing so we don't unsubscribe twice.
|
||||
* <p>
|
||||
* Also has the stop() method returning a boolean so callers know if their thread "won" and should perform further actions.
|
||||
* Also has the stop() method returning a boolean so callers know if
|
||||
* their thread "won" and should perform further actions.
|
||||
*/
|
||||
private class MergeSubscription implements Subscription {
|
||||
|
||||
@@ -169,23 +182,23 @@ public final class OperationMergeDelayError {
|
||||
boolean didSet = stopped.compareAndSet(false, true);
|
||||
if (didSet) {
|
||||
// this thread won the race to stop, so unsubscribe from the actualSubscription
|
||||
for (Subscription _s : childSubscriptions.values()) {
|
||||
for (Subscription _s : childSubscriptions.values())
|
||||
_s.unsubscribe();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
} else
|
||||
// another thread beat us
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the top level Observable to receive the sequence of Observable<T> children.
|
||||
* Subscribe to the top level Observable to receive the sequence of
|
||||
* Observable<T> children.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private class ParentObserver implements Observer<Observable<T>> {
|
||||
|
||||
private final Observer<T> actualObserver;
|
||||
|
||||
public ParentObserver(Observer<T> actualObserver) {
|
||||
@@ -199,23 +212,19 @@ public final class OperationMergeDelayError {
|
||||
// but will let the child worry about it
|
||||
// if however this completes and there are no children processing, then we will send onCompleted
|
||||
|
||||
if (childObservers.size() == 0) {
|
||||
if (!stopped.get()) {
|
||||
if (ourSubscription.stop()) {
|
||||
if (onErrorReceived.size() == 1) {
|
||||
if (childObservers.size() == 0)
|
||||
if (!stopped.get())
|
||||
if (ourSubscription.stop())
|
||||
if (onErrorReceived.size() == 1)
|
||||
// an onError was received from 1 ChildObserver so we now send it as a delayed error
|
||||
actualObserver.onError(onErrorReceived.peek());
|
||||
} else if (onErrorReceived.size() > 1) {
|
||||
else if (onErrorReceived.size() > 1)
|
||||
// an onError was received from more than 1 ChildObserver so we now send it as a delayed error
|
||||
actualObserver.onError(new CompositeException(onErrorReceived));
|
||||
} else {
|
||||
else
|
||||
// no delayed error so send onCompleted
|
||||
actualObserver.onCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
@@ -224,20 +233,21 @@ public final class OperationMergeDelayError {
|
||||
|
||||
@Override
|
||||
public void onNext(Observable<T> childObservable) {
|
||||
if (stopped.get()) {
|
||||
if (stopped.get())
|
||||
// we won't act on any further items
|
||||
return;
|
||||
}
|
||||
|
||||
if (childObservable == null) {
|
||||
if (childObservable == null)
|
||||
throw new IllegalArgumentException("Observable<T> can not be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* For each child Observable we receive we'll subscribe with a separate Observer
|
||||
* that will each then forward their sequences to the actualObserver.
|
||||
* For each child Observable we receive we'll subscribe with a
|
||||
* separate Observer that will each then forward their sequences
|
||||
* to the actualObserver.
|
||||
* <p>
|
||||
* We use separate child Observers for each sequence to simplify the onComplete/onError handling so each sequence has its own lifecycle.
|
||||
* We use separate child Observers for each sequence to simplify
|
||||
* the onComplete/onError handling so each sequence has its own
|
||||
* lifecycle.
|
||||
*/
|
||||
ChildObserver _w = new ChildObserver(actualObserver);
|
||||
childObservers.put(_w, _w);
|
||||
@@ -248,7 +258,8 @@ public final class OperationMergeDelayError {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to each child Observable<T> and forward their sequence of data to the actualObserver
|
||||
* Subscribe to each child Observable<T> and forward their sequence of
|
||||
* data to the actualObserver
|
||||
*
|
||||
*/
|
||||
private class ChildObserver implements Observer<T> {
|
||||
@@ -266,10 +277,9 @@ public final class OperationMergeDelayError {
|
||||
childObservers.remove(this);
|
||||
// if there are now 0 Observers left, so if the parent is also completed we send the onComplete to the actualObserver
|
||||
// if the parent is not complete that means there is another sequence (and child Observer) to come
|
||||
if (!stopped.get()) {
|
||||
if (!stopped.get())
|
||||
finishObserver();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
@@ -289,38 +299,38 @@ public final class OperationMergeDelayError {
|
||||
}
|
||||
|
||||
/**
|
||||
* onComplete and onError when called need to check for the parent being complete and if so send the onCompleted or onError to the actualObserver.
|
||||
* onComplete and onError when called need to check for the parent
|
||||
* being complete and if so send the onCompleted or onError to the
|
||||
* actualObserver.
|
||||
* <p>
|
||||
* This does NOT get invoked if synchronous execution occurs, but will when asynchronously executing.
|
||||
* This does NOT get invoked if synchronous execution occurs, but
|
||||
* will when asynchronously executing.
|
||||
* <p>
|
||||
* TestCase testErrorDelayed4WithThreading specifically tests this use case.
|
||||
* TestCase testErrorDelayed4WithThreading specifically tests this
|
||||
* use case.
|
||||
*/
|
||||
private void finishObserver() {
|
||||
if (childObservers.size() == 0 && parentCompleted) {
|
||||
if (ourSubscription.stop()) {
|
||||
if (childObservers.size() == 0 && parentCompleted)
|
||||
if (ourSubscription.stop())
|
||||
// this thread 'won' the race to unsubscribe/stop so let's send onError or onCompleted
|
||||
if (onErrorReceived.size() == 1) {
|
||||
if (onErrorReceived.size() == 1)
|
||||
// an onError was received from 1 ChildObserver so we now send it as a delayed error
|
||||
actualObserver.onError(onErrorReceived.peek());
|
||||
} else if (onErrorReceived.size() > 1) {
|
||||
else if (onErrorReceived.size() > 1)
|
||||
// an onError was received from more than 1 ChildObserver so we now send it as a delayed error
|
||||
actualObserver.onError(new CompositeException(onErrorReceived));
|
||||
} else {
|
||||
else
|
||||
// no delayed error so send onCompleted
|
||||
actualObserver.onCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(T args) {
|
||||
// in case the Observable is poorly behaved and doesn't listen to the unsubscribe request
|
||||
// we'll ignore anything that comes in after we've unsubscribed or an onError has been received and delayed
|
||||
if (!stopped.get() && !finished) {
|
||||
if (!stopped.get() && !finished)
|
||||
actualObserver.onNext(args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,8 @@ public final class OperationMostRecent {
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (observer.getException() != null) {
|
||||
if (observer.getException() != null)
|
||||
throw Exceptions.propagate(observer.getException());
|
||||
}
|
||||
return observer.getRecentValue();
|
||||
}
|
||||
|
||||
@@ -67,6 +66,7 @@ public final class OperationMostRecent {
|
||||
}
|
||||
|
||||
private static class MostRecentObserver<T> implements Observer<T> {
|
||||
|
||||
private final AtomicBoolean completed = new AtomicBoolean(false);
|
||||
private final AtomicReference<T> value;
|
||||
private final AtomicReference<Exception> exception = new AtomicReference<>();
|
||||
|
||||
@@ -26,7 +26,8 @@ import rx.Observer;
|
||||
import rx.util.Exceptions;
|
||||
|
||||
/**
|
||||
* Samples the next value (blocking without buffering) from in an observable sequence.
|
||||
* Samples the next value (blocking without buffering) from in an observable
|
||||
* sequence.
|
||||
*/
|
||||
public final class OperationNext {
|
||||
|
||||
@@ -56,9 +57,8 @@ public final class OperationNext {
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (observer.isCompleted(true)) {
|
||||
if (observer.isCompleted(true))
|
||||
throw new IllegalStateException("Observable is completed");
|
||||
}
|
||||
|
||||
observer.await();
|
||||
|
||||
@@ -78,6 +78,7 @@ public final class OperationNext {
|
||||
}
|
||||
|
||||
private static class NextObserver<T> implements Observer<Notification<T>> {
|
||||
|
||||
private final BlockingQueue<Notification<T>> buf = new ArrayBlockingQueue<>(1);
|
||||
private final AtomicBoolean waiting = new AtomicBoolean(false);
|
||||
|
||||
@@ -100,11 +101,10 @@ public final class OperationNext {
|
||||
Notification<T> concurrentItem = buf.poll();
|
||||
|
||||
// in case if we won race condition with onComplete/onError method
|
||||
if (!concurrentItem.isOnNext()) {
|
||||
if (!concurrentItem.isOnNext())
|
||||
toOffer = concurrentItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -114,17 +114,14 @@ public final class OperationNext {
|
||||
|
||||
public boolean isCompleted(boolean rethrowExceptionIfExists) {
|
||||
Notification<T> lastItem = buf.peek();
|
||||
if (lastItem == null) {
|
||||
if (lastItem == null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastItem.isOnError()) {
|
||||
if (rethrowExceptionIfExists) {
|
||||
if (lastItem.isOnError())
|
||||
if (rethrowExceptionIfExists)
|
||||
throw Exceptions.propagate(lastItem.getException());
|
||||
} else {
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return lastItem.isOnCompleted();
|
||||
}
|
||||
@@ -132,13 +129,11 @@ public final class OperationNext {
|
||||
public T takeNext() throws InterruptedException {
|
||||
Notification<T> next = buf.take();
|
||||
|
||||
if (next.isOnError()) {
|
||||
if (next.isOnError())
|
||||
throw Exceptions.propagate(next.getException());
|
||||
}
|
||||
|
||||
if (next.isOnCompleted()) {
|
||||
if (next.isOnCompleted())
|
||||
throw new IllegalStateException("Observable is completed");
|
||||
}
|
||||
|
||||
return next.getValue();
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ public class OperationObserveOn {
|
||||
}
|
||||
|
||||
private static class ObserveOn<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Observable<T> source;
|
||||
private final Scheduler scheduler;
|
||||
|
||||
|
||||
@@ -55,31 +55,40 @@ public final class OperationOnErrorResumeNextViaFunction<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instead of passing the onError forward, we intercept and "resume" with the resumeSequence.
|
||||
* Instead of passing the onError forward, we intercept and
|
||||
* "resume" with the resumeSequence.
|
||||
*/
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
/* remember what the current subscription is so we can determine if someone unsubscribes concurrently */
|
||||
/*
|
||||
* remember what the current subscription is so we can
|
||||
* determine if someone unsubscribes concurrently
|
||||
*/
|
||||
AtomicObservableSubscription currentSubscription = subscriptionRef.get();
|
||||
// check that we have not been unsubscribed before we can process the error
|
||||
if (currentSubscription != null) {
|
||||
if (currentSubscription != null)
|
||||
try {
|
||||
Observable<T> resumeSequence = resumeFunction.call(ex);
|
||||
/* error occurred, so switch subscription to the 'resumeSequence' */
|
||||
/*
|
||||
* error occurred, so switch subscription to the
|
||||
* 'resumeSequence'
|
||||
*/
|
||||
AtomicObservableSubscription innerSubscription = new AtomicObservableSubscription(resumeSequence.subscribe(observer));
|
||||
/* we changed the sequence, so also change the subscription to the one of the 'resumeSequence' instead */
|
||||
if (!subscriptionRef.compareAndSet(currentSubscription, innerSubscription)) {
|
||||
/*
|
||||
* we changed the sequence, so also change the
|
||||
* subscription to the one of the 'resumeSequence'
|
||||
* instead
|
||||
*/
|
||||
if (!subscriptionRef.compareAndSet(currentSubscription, innerSubscription))
|
||||
// we failed to set which means 'subscriptionRef' was set to NULL via the unsubscribe below
|
||||
// so we want to immediately unsubscribe from the resumeSequence we just subscribed to
|
||||
innerSubscription.unsubscribe();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// the resume function failed so we need to call onError
|
||||
// I am using CompositeException so that both exceptions can be seen
|
||||
observer.onError(new CompositeException("OnErrorResume function failed", Arrays.asList(ex, e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
|
||||
@@ -54,24 +54,34 @@ public final class OperationOnErrorResumeNextViaObservable<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instead of passing the onError forward, we intercept and "resume" with the resumeSequence.
|
||||
* Instead of passing the onError forward, we intercept and
|
||||
* "resume" with the resumeSequence.
|
||||
*/
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
/* remember what the current subscription is so we can determine if someone unsubscribes concurrently */
|
||||
/*
|
||||
* remember what the current subscription is so we can
|
||||
* determine if someone unsubscribes concurrently
|
||||
*/
|
||||
AtomicObservableSubscription currentSubscription = subscriptionRef.get();
|
||||
// check that we have not been unsubscribed before we can process the error
|
||||
if (currentSubscription != null) {
|
||||
/* error occurred, so switch subscription to the 'resumeSequence' */
|
||||
/*
|
||||
* error occurred, so switch subscription to the
|
||||
* 'resumeSequence'
|
||||
*/
|
||||
AtomicObservableSubscription innerSubscription = new AtomicObservableSubscription(resumeSequence.subscribe(observer));
|
||||
/* we changed the sequence, so also change the subscription to the one of the 'resumeSequence' instead */
|
||||
if (!subscriptionRef.compareAndSet(currentSubscription, innerSubscription)) {
|
||||
/*
|
||||
* we changed the sequence, so also change the
|
||||
* subscription to the one of the 'resumeSequence'
|
||||
* instead
|
||||
*/
|
||||
if (!subscriptionRef.compareAndSet(currentSubscription, innerSubscription))
|
||||
// we failed to set which means 'subscriptionRef' was set to NULL via the unsubscribe below
|
||||
// so we want to immediately unsubscribe from the resumeSequence we just subscribed to
|
||||
innerSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
|
||||
@@ -26,7 +26,8 @@ import rx.util.CompositeException;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* When an onError occurs the resumeFunction will be executed and it's response passed to onNext instead of calling onError.
|
||||
* When an onError occurs the resumeFunction will be executed and it's response
|
||||
* passed to onNext instead of calling onError.
|
||||
*/
|
||||
public final class OperationOnErrorReturn<T> {
|
||||
|
||||
@@ -35,6 +36,7 @@ public final class OperationOnErrorReturn<T> {
|
||||
}
|
||||
|
||||
private static class OnErrorReturn<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Func1<Exception, T> resumeFunction;
|
||||
private final Observable<T> originalSequence;
|
||||
|
||||
@@ -59,28 +61,44 @@ public final class OperationOnErrorReturn<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instead of passing the onError forward, we intercept and "resume" with the resumeSequence.
|
||||
* Instead of passing the onError forward, we intercept and
|
||||
* "resume" with the resumeSequence.
|
||||
*/
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
/* remember what the current subscription is so we can determine if someone unsubscribes concurrently */
|
||||
/*
|
||||
* remember what the current subscription is so we can
|
||||
* determine if someone unsubscribes concurrently
|
||||
*/
|
||||
AtomicObservableSubscription currentSubscription = subscriptionRef.get();
|
||||
// check that we have not been unsubscribed before we can process the error
|
||||
if (currentSubscription != null) {
|
||||
if (currentSubscription != null)
|
||||
try {
|
||||
/* error occurred, so execute the function, give it the exception and call onNext with the response */
|
||||
/*
|
||||
* error occurred, so execute the function, give it
|
||||
* the exception and call onNext with the response
|
||||
*/
|
||||
onNext(resumeFunction.call(ex));
|
||||
/*
|
||||
* we are not handling an exception thrown from this function ... should we do something?
|
||||
* error handling within an error handler is a weird one to determine what we should do
|
||||
* right now I'm going to just let it throw whatever exceptions occur (such as NPE)
|
||||
* but I'm considering calling the original Observer.onError to act as if this OnErrorReturn operator didn't happen
|
||||
* we are not handling an exception thrown from this
|
||||
* function ... should we do something?
|
||||
* error handling within an error handler is a weird
|
||||
* one to determine what we should do
|
||||
* right now I'm going to just let it throw whatever
|
||||
* exceptions occur (such as NPE)
|
||||
* but I'm considering calling the original
|
||||
* Observer.onError to act as if this OnErrorReturn
|
||||
* operator didn't happen
|
||||
*/
|
||||
|
||||
/* we are now completed */
|
||||
/*
|
||||
* we are now completed
|
||||
*/
|
||||
onCompleted();
|
||||
|
||||
/* unsubscribe since it blew up */
|
||||
/*
|
||||
* unsubscribe since it blew up
|
||||
*/
|
||||
currentSubscription.unsubscribe();
|
||||
} catch (Exception e) {
|
||||
// the return function failed so we need to call onError
|
||||
@@ -88,7 +106,6 @@ public final class OperationOnErrorReturn<T> {
|
||||
observer.onError(new CompositeException("OnErrorReturn function failed", Arrays.asList(ex, e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
|
||||
@@ -23,17 +23,19 @@ import rx.util.functions.Func1;
|
||||
import rx.util.functions.Func2;
|
||||
|
||||
public final class OperationScan {
|
||||
|
||||
/**
|
||||
* Applies an accumulator function over an observable sequence and returns each intermediate result with the specified source and accumulator.
|
||||
* Applies an accumulator function over an observable sequence and returns
|
||||
* each intermediate result with the specified source and accumulator.
|
||||
*
|
||||
* @param sequence
|
||||
* An observable sequence of elements to project.
|
||||
* @param initialValue
|
||||
* The initial (seed) accumulator value.
|
||||
* @param accumulator
|
||||
* An accumulator function to be invoked on each element from the sequence.
|
||||
* @param sequence An observable sequence of elements to project.
|
||||
* @param initialValue The initial (seed) accumulator value.
|
||||
* @param accumulator An accumulator function to be invoked on each element
|
||||
* from the sequence.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of
|
||||
* accumulating the output from the list of Observables.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of accumulating the output from the list of Observables.
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> scan(Observable<T> sequence, T initialValue, Func2<T, T, T> accumulator) {
|
||||
@@ -41,14 +43,16 @@ public final class OperationScan {
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an accumulator function over an observable sequence and returns each intermediate result with the specified source and accumulator.
|
||||
* Applies an accumulator function over an observable sequence and returns
|
||||
* each intermediate result with the specified source and accumulator.
|
||||
*
|
||||
* @param sequence
|
||||
* An observable sequence of elements to project.
|
||||
* @param accumulator
|
||||
* An accumulator function to be invoked on each element from the sequence.
|
||||
* @param sequence An observable sequence of elements to project.
|
||||
* @param accumulator An accumulator function to be invoked on each element
|
||||
* from the sequence.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of
|
||||
* accumulating the output from the list of Observables.
|
||||
*
|
||||
* @return An observable sequence whose elements are the result of accumulating the output from the list of Observables.
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> scan(Observable<T> sequence, Func2<T, T, T> accumulator) {
|
||||
@@ -56,6 +60,7 @@ public final class OperationScan {
|
||||
}
|
||||
|
||||
private static class Accumulator<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Observable<T> sequence;
|
||||
private final T initialValue;
|
||||
private final Func2<T, T, T> accumlatorFunction;
|
||||
@@ -75,11 +80,13 @@ public final class OperationScan {
|
||||
private boolean hasSentInitialValue = false;
|
||||
|
||||
/**
|
||||
* We must synchronize this because we can't allow
|
||||
* multiple threads to execute the 'accumulatorFunction' at the same time because
|
||||
* the accumulator code very often will be doing mutation of the 'acc' object such as a non-threadsafe HashMap
|
||||
* We must synchronize this because we can't allow multiple
|
||||
* threads to execute the 'accumulatorFunction' at the same time
|
||||
* because the accumulator code very often will be doing
|
||||
* mutation of the 'acc' object such as a non-threadsafe HashMap
|
||||
*
|
||||
* Because it's synchronized it's using non-atomic variables since everything in this method is single-threaded
|
||||
* Because it's synchronized it's using non-atomic variables
|
||||
* since everything in this method is single-threaded
|
||||
*/
|
||||
@Override
|
||||
public synchronized void onNext(T value) {
|
||||
@@ -119,9 +126,8 @@ public final class OperationScan {
|
||||
@Override
|
||||
public synchronized void onCompleted() {
|
||||
// if only one sequence value existed, we send it without any accumulation
|
||||
if (!hasSentInitialValue) {
|
||||
if (!hasSentInitialValue)
|
||||
observer.onNext(acc);
|
||||
}
|
||||
observer.onCompleted();
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -23,15 +23,18 @@ import rx.Subscription;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* Skips a specified number of contiguous values from the start of a Observable sequence and then returns the remaining values.
|
||||
* Skips a specified number of contiguous values from the start of a Observable
|
||||
* sequence and then returns the remaining values.
|
||||
*/
|
||||
public final class OperationSkip {
|
||||
|
||||
/**
|
||||
* Skips a specified number of contiguous values from the start of a Observable sequence and then returns the remaining values.
|
||||
* Skips a specified number of contiguous values from the start of a
|
||||
* Observable sequence and then returns the remaining values.
|
||||
*
|
||||
* @param items
|
||||
* @param num
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @see http://msdn.microsoft.com/en-us/library/hh229847(v=vs.103).aspx
|
||||
@@ -42,13 +45,17 @@ public final class OperationSkip {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times. In other words, don't subscribe to it multiple times from different threads.
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times.
|
||||
* In other words, don't subscribe to it multiple times from different
|
||||
* threads.
|
||||
* <p>
|
||||
* It IS thread-safe from within it while receiving onNext events from multiple threads.
|
||||
* It IS thread-safe from within it while receiving onNext events from
|
||||
* multiple threads.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private static class Skip<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final int num;
|
||||
private final Observable<T> items;
|
||||
|
||||
@@ -63,7 +70,8 @@ public final class OperationSkip {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to subscribe to the 'items' Observable sequence and forward to the actualObserver up to 'num' count.
|
||||
* Used to subscribe to the 'items' Observable sequence and forward to
|
||||
* the actualObserver up to 'num' count.
|
||||
*/
|
||||
private class ItemObserver implements Observer<T> {
|
||||
|
||||
@@ -87,10 +95,9 @@ public final class OperationSkip {
|
||||
@Override
|
||||
public void onNext(T args) {
|
||||
// skip them until we reach the 'num' value
|
||||
if (counter.incrementAndGet() > num) {
|
||||
if (counter.incrementAndGet() > num)
|
||||
observer.onNext(args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -23,29 +23,32 @@ import rx.util.SynchronizedObserver;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* An observable that wraps an observable of the same type and then enforces the semantics
|
||||
* expected of a well-behaved observable.
|
||||
* An observable that wraps an observable of the same type and then enforces the
|
||||
* semantics expected of a well-behaved observable.
|
||||
* <p>
|
||||
* An observable that ensures onNext, onCompleted, or onError calls on its subscribers are
|
||||
* not interleaved, onCompleted and onError are only called once respectively, and no
|
||||
* onNext calls follow onCompleted and onError calls.
|
||||
* An observable that ensures onNext, onCompleted, or onError calls on its
|
||||
* subscribers are not interleaved, onCompleted and onError are only called once
|
||||
* respectively, and no onNext calls follow onCompleted and onError calls.
|
||||
* <p>
|
||||
* NOTE: {@link Observable#create} already wraps Observables so this is generally redundant.
|
||||
* NOTE: {@link Observable#create} already wraps Observables so this is
|
||||
* generally redundant.
|
||||
*
|
||||
* @param <T>
|
||||
* The type of the observable sequence.
|
||||
* @param <T> The type of the observable sequence.
|
||||
*/
|
||||
public final class OperationSynchronize<T> {
|
||||
|
||||
/**
|
||||
* Accepts an observable and wraps it in another observable which ensures that the resulting observable is well-behaved.
|
||||
* Accepts an observable and wraps it in another observable which ensures
|
||||
* that the resulting observable is well-behaved.
|
||||
*
|
||||
* A well-behaved observable ensures onNext, onCompleted, or onError calls to its subscribers are
|
||||
* not interleaved, onCompleted and onError are only called once respectively, and no
|
||||
* onNext calls follow onCompleted and onError calls.
|
||||
* A well-behaved observable ensures onNext, onCompleted, or onError calls
|
||||
* to its subscribers are not interleaved, onCompleted and onError are only
|
||||
* called once respectively, and no onNext calls follow onCompleted and
|
||||
* onError calls.
|
||||
*
|
||||
* @param observable
|
||||
* @param <T>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> synchronize(Observable<T> observable) {
|
||||
|
||||
@@ -25,15 +25,18 @@ import rx.util.AtomicObservableSubscription;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* Returns a specified number of contiguous values from the start of an observable sequence.
|
||||
* Returns a specified number of contiguous values from the start of an
|
||||
* observable sequence.
|
||||
*/
|
||||
public final class OperationTake {
|
||||
|
||||
/**
|
||||
* Returns a specified number of contiguous values from the start of an observable sequence.
|
||||
* Returns a specified number of contiguous values from the start of an
|
||||
* observable sequence.
|
||||
*
|
||||
* @param items
|
||||
* @param num
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> take(final Observable<T> items, final int num) {
|
||||
@@ -42,17 +45,24 @@ public final class OperationTake {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times. In other words, don't subscribe to it multiple times from different threads.
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times.
|
||||
* In other words, don't subscribe to it multiple times from different
|
||||
* threads.
|
||||
* <p>
|
||||
* It IS thread-safe from within it while receiving onNext events from multiple threads.
|
||||
* It IS thread-safe from within it while receiving onNext events from
|
||||
* multiple threads.
|
||||
* <p>
|
||||
* This should all be fine as long as it's kept as a private class and a new instance created from static factory method above.
|
||||
* This should all be fine as long as it's kept as a private class and a new
|
||||
* instance created from static factory method above.
|
||||
* <p>
|
||||
* Note how the take() factory method above protects us from a single instance being exposed with the Observable wrapper handling the subscribe flow.
|
||||
* Note how the take() factory method above protects us from a single
|
||||
* instance being exposed with the Observable wrapper handling the subscribe
|
||||
* flow.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private static class Take<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
private final Observable<T> items;
|
||||
private final int num;
|
||||
@@ -66,21 +76,17 @@ public final class OperationTake {
|
||||
@Override
|
||||
public Subscription call(Observer<T> observer) {
|
||||
if (num < 1) {
|
||||
items.subscribe(new Observer<T>()
|
||||
{
|
||||
items.subscribe(new Observer<T>() {
|
||||
@Override
|
||||
public void onCompleted()
|
||||
{
|
||||
public void onCompleted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e)
|
||||
{
|
||||
public void onError(Exception e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(T args)
|
||||
{
|
||||
public void onNext(T args) {
|
||||
}
|
||||
}).unsubscribe();
|
||||
observer.onCompleted();
|
||||
@@ -91,6 +97,7 @@ public final class OperationTake {
|
||||
}
|
||||
|
||||
private class ItemObserver implements Observer<T> {
|
||||
|
||||
private final Observer<T> observer;
|
||||
|
||||
public ItemObserver(Observer<T> observer) {
|
||||
@@ -99,32 +106,28 @@ public final class OperationTake {
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
if (counter.getAndSet(num) < num) {
|
||||
if (counter.getAndSet(num) < num)
|
||||
observer.onCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
if (counter.getAndSet(num) < num) {
|
||||
if (counter.getAndSet(num) < num)
|
||||
observer.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(T args) {
|
||||
final int count = counter.incrementAndGet();
|
||||
if (count <= num) {
|
||||
observer.onNext(args);
|
||||
if (count == num) {
|
||||
if (count == num)
|
||||
observer.onCompleted();
|
||||
}
|
||||
}
|
||||
if (count >= num) {
|
||||
if (count >= num)
|
||||
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ import rx.util.AtomicObservableSubscription;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
/**
|
||||
* Returns a specified number of contiguous elements from the end of an observable sequence.
|
||||
* Returns a specified number of contiguous elements from the end of an
|
||||
* observable sequence.
|
||||
*/
|
||||
public final class OperationTakeLast {
|
||||
|
||||
@@ -34,6 +35,7 @@ public final class OperationTakeLast {
|
||||
}
|
||||
|
||||
private static class TakeLast<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final int count;
|
||||
private final Observable<T> items;
|
||||
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||
@@ -60,9 +62,8 @@ public final class OperationTakeLast {
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
Iterator<T> reverse = deque.descendingIterator();
|
||||
while (reverse.hasNext()) {
|
||||
while (reverse.hasNext())
|
||||
observer.onNext(reverse.next());
|
||||
}
|
||||
observer.onCompleted();
|
||||
}
|
||||
|
||||
@@ -73,10 +74,9 @@ public final class OperationTakeLast {
|
||||
|
||||
@Override
|
||||
public void onNext(T args) {
|
||||
while (!deque.offerFirst(args)) {
|
||||
while (!deque.offerFirst(args))
|
||||
deque.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -26,16 +26,18 @@ import rx.util.functions.Func1;
|
||||
import rx.util.functions.Func2;
|
||||
|
||||
/**
|
||||
* Returns values from an observable sequence as long as a specified condition is true, and then skips the remaining values.
|
||||
* Returns values from an observable sequence as long as a specified condition
|
||||
* is true, and then skips the remaining values.
|
||||
*/
|
||||
public final class OperationTakeWhile {
|
||||
|
||||
/**
|
||||
* Returns a specified number of contiguous values from the start of an observable sequence.
|
||||
* Returns a specified number of contiguous values from the start of an
|
||||
* observable sequence.
|
||||
*
|
||||
* @param items
|
||||
* @param predicate
|
||||
* a function to test each source element for a condition
|
||||
* @param predicate a function to test each source element for a condition
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> takeWhile(final Observable<T> items, final Func1<T, Boolean> predicate) {
|
||||
@@ -43,11 +45,14 @@ public final class OperationTakeWhile {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns values from an observable sequence as long as a specified condition is true, and then skips the remaining values.
|
||||
* Returns values from an observable sequence as long as a specified
|
||||
* condition is true, and then skips the remaining values.
|
||||
*
|
||||
* @param items
|
||||
* @param predicate
|
||||
* a function to test each element for a condition; the second parameter of the function represents the index of the source element; otherwise, false.
|
||||
* @param predicate a function to test each element for a condition; the
|
||||
* second parameter of the function represents the index of the source
|
||||
* element; otherwise, false.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Func1<Observer<T>, Subscription> takeWhileWithIndex(final Observable<T> items, final Func2<T, Integer, Boolean> predicate) {
|
||||
@@ -60,17 +65,24 @@ public final class OperationTakeWhile {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times. In other words, don't subscribe to it multiple times from different threads.
|
||||
* This class is NOT thread-safe if invoked and referenced multiple times.
|
||||
* In other words, don't subscribe to it multiple times from different
|
||||
* threads.
|
||||
* <p>
|
||||
* It IS thread-safe from within it while receiving onNext events from multiple threads.
|
||||
* It IS thread-safe from within it while receiving onNext events from
|
||||
* multiple threads.
|
||||
* <p>
|
||||
* This should all be fine as long as it's kept as a private class and a new instance created from static factory method above.
|
||||
* This should all be fine as long as it's kept as a private class and a new
|
||||
* instance created from static factory method above.
|
||||
* <p>
|
||||
* Note how the takeWhileWithIndex() factory method above protects us from a single instance being exposed with the Observable wrapper handling the subscribe flow.
|
||||
* Note how the takeWhileWithIndex() factory method above protects us from a
|
||||
* single instance being exposed with the Observable wrapper handling the
|
||||
* subscribe flow.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private static class TakeWhile<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
private final Observable<T> items;
|
||||
private final Func2<T, Integer, Boolean> predicate;
|
||||
@@ -87,6 +99,7 @@ public final class OperationTakeWhile {
|
||||
}
|
||||
|
||||
private class ItemObserver implements Observer<T> {
|
||||
|
||||
private final Observer<T> observer;
|
||||
|
||||
public ItemObserver(Observer<T> observer) {
|
||||
@@ -115,9 +128,9 @@ public final class OperationTakeWhile {
|
||||
observer.onError(e);
|
||||
return;
|
||||
}
|
||||
if (isSelected) {
|
||||
if (isSelected)
|
||||
observer.onNext(args);
|
||||
} else {
|
||||
else {
|
||||
observer.onCompleted();
|
||||
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
|
||||
subscription.unsubscribe();
|
||||
|
||||
@@ -24,7 +24,9 @@ import rx.subscriptions.Subscriptions;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
public class OperationToObservableFuture {
|
||||
|
||||
private static class ToObservableFuture<T> implements Func1<Observer<T>, Subscription> {
|
||||
|
||||
private final Future<T> that;
|
||||
private final Long time;
|
||||
private final TimeUnit unit;
|
||||
@@ -46,9 +48,8 @@ public class OperationToObservableFuture {
|
||||
try {
|
||||
T value = (time == null) ? that.get() : that.get(time, unit);
|
||||
|
||||
if (!that.isCancelled()) {
|
||||
if (!that.isCancelled())
|
||||
observer.onNext(value);
|
||||
}
|
||||
observer.onCompleted();
|
||||
} catch (Exception e) {
|
||||
observer.onError(e);
|
||||
|
||||
@@ -23,8 +23,7 @@ import rx.util.functions.Func1;
|
||||
/**
|
||||
* Accepts an Iterable object and exposes it as an Observable.
|
||||
*
|
||||
* @param <T>
|
||||
* The type of the Iterable sequence.
|
||||
* @param <T> The type of the Iterable sequence.
|
||||
*/
|
||||
public final class OperationToObservableIterable<T> {
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ public final class OperationToObservableList<T> {
|
||||
|
||||
return that.subscribe(new Observer<T>() {
|
||||
final ConcurrentLinkedQueue<T> list = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@Override
|
||||
public void onNext(T value) {
|
||||
// onNext can be concurrently executed so list must be thread-safe
|
||||
|
||||
@@ -27,7 +27,8 @@ import rx.util.functions.Func1;
|
||||
import rx.util.functions.Func2;
|
||||
|
||||
/**
|
||||
* Similar to toList in that it converts a sequence<T> into a List<T> except that it accepts a Function that will provide an implementation of Comparator.
|
||||
* Similar to toList in that it converts a sequence<T> into a List<T> except
|
||||
* that it accepts a Function that will provide an implementation of Comparator.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@@ -37,8 +38,8 @@ public final class OperationToObservableSortedList<T> {
|
||||
* Sort T objects by their natural order (object must implement Comparable).
|
||||
*
|
||||
* @param sequence
|
||||
* @throws ClassCastException
|
||||
* if T objects do not implement Comparable
|
||||
*
|
||||
* @throws ClassCastException if T objects do not implement Comparable
|
||||
* @return
|
||||
*/
|
||||
public static <T> Func1<Observer<List<T>>, Subscription> toSortedList(Observable<T> sequence) {
|
||||
@@ -50,6 +51,7 @@ public final class OperationToObservableSortedList<T> {
|
||||
*
|
||||
* @param sequence
|
||||
* @param sortFunction
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Func1<Observer<List<T>>, Subscription> toSortedList(Observable<T> sequence, Func2<T, T, Integer> sortFunction) {
|
||||
@@ -92,9 +94,8 @@ public final class OperationToObservableSortedList<T> {
|
||||
try {
|
||||
// copy from LinkedQueue to List since ConcurrentLinkedQueue does not implement the List interface
|
||||
ArrayList<T> l = new ArrayList<>(list.size());
|
||||
for (T t : list) {
|
||||
for (T t : list)
|
||||
l.add(t);
|
||||
}
|
||||
|
||||
// sort the list before delivery
|
||||
Collections.sort(l, (T o1, T o2) -> sortFunction.call(o1, o2));
|
||||
|
||||
@@ -61,6 +61,7 @@ public final class OperationZip {
|
||||
* ThreadSafe
|
||||
*/
|
||||
private static class ZipObserver<R, T> implements Observer<T> {
|
||||
|
||||
final Observable<T> w;
|
||||
final Aggregator<R> a;
|
||||
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||
@@ -72,11 +73,10 @@ public final class OperationZip {
|
||||
}
|
||||
|
||||
public void startWatching() {
|
||||
if (subscribed.compareAndSet(false, true)) {
|
||||
if (subscribed.compareAndSet(false, true))
|
||||
// only subscribe once even if called more than once
|
||||
subscription.wrap(w.subscribe(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
@@ -99,7 +99,9 @@ public final class OperationZip {
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive notifications from each of the Observables we are reducing and execute the zipFunction whenever we have received events from all Observables.
|
||||
* Receive notifications from each of the Observables we are reducing and
|
||||
* execute the zipFunction whenever we have received events from all
|
||||
* Observables.
|
||||
*
|
||||
* This class is thread-safe.
|
||||
*
|
||||
@@ -113,9 +115,17 @@ public final class OperationZip {
|
||||
private final AtomicBoolean running = new AtomicBoolean(true);
|
||||
private final ConcurrentHashMap<ZipObserver<T, ?>, Boolean> completed = new ConcurrentHashMap<>();
|
||||
|
||||
/* we use ConcurrentHashMap despite synchronization of methods because stop() does NOT use synchronization and this map is used by it and can be called by other threads */
|
||||
/*
|
||||
* we use ConcurrentHashMap despite synchronization of methods because
|
||||
* stop() does NOT use synchronization and this map is used by it and
|
||||
* can be called by other threads
|
||||
*/
|
||||
private final ConcurrentHashMap<ZipObserver<T, ?>, ConcurrentLinkedQueue<Object>> receivedValuesPerObserver = new ConcurrentHashMap<>();
|
||||
/* we use a ConcurrentLinkedQueue to retain ordering (I'd like to just use a ConcurrentLinkedHashMap for 'receivedValuesPerObserver' but that doesn't exist in standard java */
|
||||
/*
|
||||
* we use a ConcurrentLinkedQueue to retain ordering (I'd like to just
|
||||
* use a ConcurrentLinkedHashMap for 'receivedValuesPerObserver' but
|
||||
* that doesn't exist in standard java
|
||||
*/
|
||||
private final ConcurrentLinkedQueue<ZipObserver<T, ?>> observers = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public Aggregator(FuncN<T> zipFunction) {
|
||||
@@ -123,9 +133,12 @@ public final class OperationZip {
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive notification of a Observer starting (meaning we should require it for aggregation)
|
||||
* Receive notification of a Observer starting (meaning we should
|
||||
* require it for aggregation)
|
||||
*
|
||||
* Thread Safety => Invoke ONLY from the static factory methods at top of this class which are always an atomic execution by a single thread.
|
||||
* Thread Safety => Invoke ONLY from the static factory methods at top
|
||||
* of this class which are always an atomic execution by a single
|
||||
* thread.
|
||||
*
|
||||
* @param w
|
||||
*/
|
||||
@@ -144,17 +157,16 @@ public final class OperationZip {
|
||||
// store that this ZipObserver is completed
|
||||
completed.put(w, Boolean.TRUE);
|
||||
// if all ZipObservers are completed, we mark the whole thing as completed
|
||||
if (completed.size() == observers.size()) {
|
||||
if (running.compareAndSet(true, false)) {
|
||||
if (completed.size() == observers.size())
|
||||
if (running.compareAndSet(true, false))
|
||||
// this thread succeeded in setting running=false so let's propagate the completion
|
||||
// mark ourselves as done
|
||||
observer.onCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive error for a Observer. Throw the error up the chain and stop processing.
|
||||
* Receive error for a Observer. Throw the error up the chain and stop
|
||||
* processing.
|
||||
*
|
||||
* @param w
|
||||
*/
|
||||
@@ -162,7 +174,9 @@ public final class OperationZip {
|
||||
if (running.compareAndSet(true, false)) {
|
||||
// this thread succeeded in setting running=false so let's propagate the error
|
||||
observer.onError(e);
|
||||
/* since we receive an error we want to tell everyone to stop */
|
||||
/*
|
||||
* since we receive an error we want to tell everyone to stop
|
||||
*/
|
||||
stop();
|
||||
}
|
||||
}
|
||||
@@ -170,20 +184,23 @@ public final class OperationZip {
|
||||
/**
|
||||
* Receive the next value from a Observer.
|
||||
* <p>
|
||||
* If we have received values from all Observers, trigger the zip function, otherwise store the value and keep waiting.
|
||||
* If we have received values from all Observers, trigger the zip
|
||||
* function, otherwise store the value and keep waiting.
|
||||
*
|
||||
* @param w
|
||||
* @param arg
|
||||
*/
|
||||
void next(ZipObserver<T, ?> w, Object arg) {
|
||||
if (observer == null) {
|
||||
if (observer == null)
|
||||
throw new RuntimeException("This shouldn't be running if a Observer isn't registered");
|
||||
}
|
||||
|
||||
/* if we've been 'unsubscribed' don't process anything further even if the things we're watching keep sending (likely because they are not responding to the unsubscribe call) */
|
||||
if (!running.get()) {
|
||||
/*
|
||||
* if we've been 'unsubscribed' don't process anything further even
|
||||
* if the things we're watching keep sending (likely because they
|
||||
* are not responding to the unsubscribe call)
|
||||
*/
|
||||
if (!running.get())
|
||||
return;
|
||||
}
|
||||
|
||||
// store the value we received and below we'll decide if we are to send it to the Observer
|
||||
receivedValuesPerObserver.get(w).add(arg);
|
||||
@@ -191,21 +208,22 @@ public final class OperationZip {
|
||||
// define here so the variable is out of the synchronized scope
|
||||
Object[] argsToZip = new Object[observers.size()];
|
||||
|
||||
/* we have to synchronize here despite using concurrent data structures because the compound logic here must all be done atomically */
|
||||
/*
|
||||
* we have to synchronize here despite using concurrent data
|
||||
* structures because the compound logic here must all be done
|
||||
* atomically
|
||||
*/
|
||||
synchronized (this) {
|
||||
// if all ZipObservers in 'receivedValues' map have a value, invoke the zipFunction
|
||||
for (ZipObserver<T, ?> rw : receivedValuesPerObserver.keySet()) {
|
||||
if (receivedValuesPerObserver.get(rw).peek() == null) {
|
||||
for (ZipObserver<T, ?> rw : receivedValuesPerObserver.keySet())
|
||||
if (receivedValuesPerObserver.get(rw).peek() == null)
|
||||
// we have a null meaning the queues aren't all populated so won't do anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if we get to here this means all the queues have data
|
||||
int i = 0;
|
||||
for (ZipObserver<T, ?> rw : observers) {
|
||||
for (ZipObserver<T, ?> rw : observers)
|
||||
argsToZip[i++] = receivedValuesPerObserver.get(rw).remove();
|
||||
}
|
||||
}
|
||||
// if we did not return above from the synchronized block we can now invoke the zipFunction with all of the args
|
||||
// we do this outside the synchronized block as it is now safe to call this concurrently and don't need to block other threads from calling
|
||||
// this 'next' method while another thread finishes calling this zipFunction
|
||||
@@ -217,23 +235,27 @@ public final class OperationZip {
|
||||
if (started.compareAndSet(false, true)) {
|
||||
AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||
this.observer = new SynchronizedObserver<>(observer, subscription);
|
||||
/* start the Observers */
|
||||
for (ZipObserver<T, ?> rw : observers) {
|
||||
/*
|
||||
* start the Observers
|
||||
*/
|
||||
for (ZipObserver<T, ?> rw : observers)
|
||||
rw.startWatching();
|
||||
}
|
||||
|
||||
return subscription.wrap(this::stop);
|
||||
} else {
|
||||
/* a Observer already has subscribed so blow up */
|
||||
} else
|
||||
/*
|
||||
* a Observer already has subscribed so blow up
|
||||
*/
|
||||
throw new IllegalStateException("Only one Observer can subscribe to this Observable.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do NOT synchronize this because it gets called via unsubscribe which can occur on other threads
|
||||
* Do NOT synchronize this because it gets called via unsubscribe which
|
||||
* can occur on other threads
|
||||
* and result in deadlocks. (http://jira/browse/API-4060)
|
||||
*
|
||||
* AtomicObservableSubscription uses compareAndSet instead of locking to avoid deadlocks but ensure single-execution.
|
||||
* AtomicObservableSubscription uses compareAndSet instead of locking to
|
||||
* avoid deadlocks but ensure single-execution.
|
||||
*
|
||||
* We do the same in the implementation of this method.
|
||||
*
|
||||
@@ -243,16 +265,19 @@ public final class OperationZip {
|
||||
* - ZipObserver.subscription being an AtomicObservableSubscription
|
||||
*/
|
||||
private void stop() {
|
||||
/* tell ourselves to stop processing onNext events by setting running=false */
|
||||
if (running.compareAndSet(true, false)) {
|
||||
/* propogate to all Observers to unsubscribe if this thread succeeded in setting running=false */
|
||||
for (ZipObserver<T, ?> o : observers) {
|
||||
if (o.subscription != null) {
|
||||
/*
|
||||
* tell ourselves to stop processing onNext events by setting
|
||||
* running=false
|
||||
*/
|
||||
if (running.compareAndSet(true, false))
|
||||
/*
|
||||
* propogate to all Observers to unsubscribe if this thread
|
||||
* succeeded in setting running=false
|
||||
*/
|
||||
for (ZipObserver<T, ?> o : observers)
|
||||
if (o.subscription != null)
|
||||
o.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public final class OperatorGroupBy {
|
||||
}
|
||||
|
||||
private static class GroupBy<K, V> implements Func1<Observer<GroupedObservable<K, V>>, Subscription> {
|
||||
|
||||
private final Observable<KeyValue<K, V>> source;
|
||||
private final ConcurrentHashMap<K, Boolean> keys = new ConcurrentHashMap<K, Boolean>();
|
||||
|
||||
@@ -72,10 +73,9 @@ public final class OperatorGroupBy {
|
||||
public void onNext(final KeyValue<K, V> args) {
|
||||
K key = args.key;
|
||||
boolean newGroup = keys.putIfAbsent(key, true) == null;
|
||||
if (newGroup) {
|
||||
if (newGroup)
|
||||
observer.onNext(buildObservableFor(source, key));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
@@ -104,6 +104,7 @@ public final class OperatorGroupBy {
|
||||
}
|
||||
|
||||
private static class KeyValue<K, V> {
|
||||
|
||||
private final K key;
|
||||
private final V value;
|
||||
|
||||
|
||||
@@ -23,17 +23,18 @@ import rx.util.functions.Func1;
|
||||
public class OperatorTakeUntil {
|
||||
|
||||
/**
|
||||
* Returns the values from the source observable sequence until the other observable sequence produces a value.
|
||||
* Returns the values from the source observable sequence until the other
|
||||
* observable sequence produces a value.
|
||||
*
|
||||
* @param source
|
||||
* the source sequence to propagate elements for.
|
||||
* @param other
|
||||
* the observable sequence that terminates propagation of elements of the source sequence.
|
||||
* @param <T>
|
||||
* the type of source.
|
||||
* @param <E>
|
||||
* the other type.
|
||||
* @return An observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation.
|
||||
* @param source the source sequence to propagate elements for.
|
||||
* @param other the observable sequence that terminates propagation of
|
||||
* elements of the source sequence.
|
||||
* @param <T> the type of source.
|
||||
* @param <E> the other type.
|
||||
*
|
||||
* @return An observable sequence containing the elements of the source
|
||||
* sequence up to the point the other sequence interrupted further
|
||||
* propagation.
|
||||
*/
|
||||
public static <T, E> Observable<T> takeUntil(final Observable<T> source, final Observable<E> other) {
|
||||
Observable<Notification<T>> s = Observable.create(new SourceObservable<T>(source));
|
||||
@@ -41,8 +42,8 @@ public class OperatorTakeUntil {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
/**
|
||||
* In JDK 7 we could use 'varargs' instead of 'unchecked'.
|
||||
* See http://stackoverflow.com/questions/1445233/is-it-possible-to-solve-the-a-generic-array-of-t-is-created-for-a-varargs-param
|
||||
* In JDK 7 we could use 'varargs' instead of 'unchecked'. See
|
||||
* http://stackoverflow.com/questions/1445233/is-it-possible-to-solve-the-a-generic-array-of-t-is-created-for-a-varargs-param
|
||||
* and http://hg.openjdk.java.net/jdk7/tl/langtools/rev/46cf751559ae
|
||||
*/
|
||||
Observable<Notification<T>> result = Observable.merge(s, o);
|
||||
@@ -61,6 +62,7 @@ public class OperatorTakeUntil {
|
||||
}
|
||||
|
||||
private static class Notification<T> {
|
||||
|
||||
private final boolean halt;
|
||||
private final T value;
|
||||
|
||||
@@ -80,6 +82,7 @@ public class OperatorTakeUntil {
|
||||
}
|
||||
|
||||
private static class SourceObservable<T> implements Func1<Observer<Notification<T>>, Subscription> {
|
||||
|
||||
private final Observable<T> sequence;
|
||||
|
||||
private SourceObservable(Observable<T> sequence) {
|
||||
@@ -108,6 +111,7 @@ public class OperatorTakeUntil {
|
||||
}
|
||||
|
||||
private static class OtherObservable<T, E> implements Func1<Observer<Notification<T>>, Subscription> {
|
||||
|
||||
private final Observable<E> sequence;
|
||||
|
||||
private OtherObservable(Observable<E> sequence) {
|
||||
|
||||
@@ -17,11 +17,11 @@ public class OperatorToIterator {
|
||||
/**
|
||||
* Returns an iterator that iterates all values of the observable.
|
||||
*
|
||||
* @param that
|
||||
* an observable sequence to get an iterator for.
|
||||
* @param <T>
|
||||
* the type of source.
|
||||
* @return the iterator that could be used to iterate over the elements of the observable.
|
||||
* @param that an observable sequence to get an iterator for.
|
||||
* @param <T> the type of source.
|
||||
*
|
||||
* @return the iterator that could be used to iterate over the elements of
|
||||
* the observable.
|
||||
*/
|
||||
public static <T> Iterator<T> toIterator(Observable<T> that) {
|
||||
final BlockingQueue<Notification<T>> notifications = new LinkedBlockingQueue<Notification<T>>();
|
||||
@@ -48,20 +48,17 @@ public class OperatorToIterator {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (buf == null) {
|
||||
if (buf == null)
|
||||
buf = take();
|
||||
}
|
||||
return !buf.isOnCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (buf == null) {
|
||||
if (buf == null)
|
||||
buf = take();
|
||||
}
|
||||
if (buf.isOnError()) {
|
||||
if (buf.isOnError())
|
||||
throw Exceptions.propagate(buf.getException());
|
||||
}
|
||||
|
||||
T result = buf.getValue();
|
||||
buf = null;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user