Merge changes Id2848c16,I7621c434
* changes:
Rescale "Compressing objects" progress meter by size
Split delta search buckets by byte weight
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
index d0b363b..8c5066a 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
@@ -97,7 +97,7 @@ public void testMerge() throws Exception {
git.add().addFilepattern("side").call();
git.commit().setMessage("side commit").call();
- assertEquals("Merge made by the '" + MergeStrategy.RESOLVE.getName()
+ assertEquals("Merge made by the '" + MergeStrategy.RECURSIVE.getName()
+ "' strategy.", execute("git merge master")[0]);
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index 0a14901..24794e7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -75,7 +75,7 @@ class Merge extends TextBuiltin {
@Option(name = "--no-commit", usage = "usage_noCommit")
private boolean noCommit = false;
- private MergeStrategy mergeStrategy = MergeStrategy.RESOLVE;
+ private MergeStrategy mergeStrategy = MergeStrategy.RECURSIVE;
@Argument(required = true)
private String ref;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java
index b370468..df17519 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2011, 2013 Robin Rosenberg
+ * Copyright (C) 2013 Robin Stocker
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -67,6 +68,29 @@ public void test() throws IOException {
assertNoCrLf("\r\n\r\n\r", "\n\r\n\r");
}
+ @Test
+ public void testBoundary() throws IOException {
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE - 5);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE - 4);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE - 3);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE - 2);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE - 1);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE + 1);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE + 2);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE + 3);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE + 4);
+ assertBoundaryCorrect(AutoCRLFOutputStream.BUFFER_SIZE + 5);
+ }
+
+ private void assertBoundaryCorrect(int size) throws IOException {
+ StringBuilder sb = new StringBuilder(size);
+ for (int i = 0; i < size; i++)
+ sb.append('a');
+ String s = sb.toString();
+ assertNoCrLf(s, s);
+ }
+
private void assertNoCrLf(String string, String string2) throws IOException {
assertNoCrLfHelper(string, string2);
// \u00e5 = LATIN SMALL LETTER A WITH RING ABOVE
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index dca7197..d5d9559 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -150,7 +150,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
String cherryPickName = srcCommit.getId().abbreviate(7).name()
+ " " + srcCommit.getShortMessage(); //$NON-NLS-1$
- ResolveMerger merger = (ResolveMerger) MergeStrategy.RESOLVE
+ ResolveMerger merger = (ResolveMerger) MergeStrategy.RECURSIVE
.newMerger(repo);
merger.setWorkingTreeIterator(new FileTreeIterator(repo));
merger.setBase(srcParent.getTree());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index 35bf75d..65af216 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -155,12 +155,10 @@ private FetchResult fetch(Repository clonedRepo, URIish u)
config.addURI(u);
final String dst = (bare ? Constants.R_HEADS : Constants.R_REMOTES
- + config.getName() + "/") + "*";
+ + config.getName() + "/") + "*"; //$NON-NLS-1$//$NON-NLS-2$
RefSpec refSpec = new RefSpec();
refSpec = refSpec.setForceUpdate(true);
- refSpec = refSpec.setSourceDestination(
- Constants.R_HEADS + "*", dst); //$NON-NLS-1$ //$NON-NLS-2$
-
+ refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", dst); //$NON-NLS-1$
config.addFetchRefSpec(refSpec);
config.update(clonedRepo.getConfig());
@@ -183,7 +181,7 @@ private FetchResult fetch(Repository clonedRepo, URIish u)
private List<RefSpec> calculateRefSpecs(final String dst) {
RefSpec wcrs = new RefSpec();
wcrs = wcrs.setForceUpdate(true);
- wcrs = wcrs.setSourceDestination(Constants.R_HEADS + "*", dst); //$NON-NLS-1$ //$NON-NLS-2$
+ wcrs = wcrs.setSourceDestination(Constants.R_HEADS + "*", dst); //$NON-NLS-1$
List<RefSpec> specs = new ArrayList<RefSpec>();
if (cloneAllBranches)
specs.add(wcrs);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index 8f6e9cb..509203e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -95,7 +95,7 @@
*/
public class MergeCommand extends GitCommand<MergeResult> {
- private MergeStrategy mergeStrategy = MergeStrategy.RESOLVE;
+ private MergeStrategy mergeStrategy = MergeStrategy.RECURSIVE;
private List<Ref> commits = new LinkedList<Ref>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
index 4789fbe..95a1f35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
@@ -103,7 +103,7 @@ public String toString() {
if (tip != null)
sb.append(format());
else
- sb.append(String.valueOf(null));
+ sb.append((Object) null);
sb.append(',').append(cost).append(']').append(' ')
.append(super.toString()).toString();
return sb.toString();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
index 16522b7..c392209 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -160,11 +160,12 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
String revertName = srcCommit.getId().abbreviate(7).name()
+ " " + srcCommit.getShortMessage(); //$NON-NLS-1$
- ResolveMerger merger = (ResolveMerger) MergeStrategy.RESOLVE
+ ResolveMerger merger = (ResolveMerger) MergeStrategy.RECURSIVE
.newMerger(repo);
merger.setWorkingTreeIterator(new FileTreeIterator(repo));
merger.setBase(srcCommit.getTree());
- merger.setCommitNames(new String[] { "BASE", ourName, revertName }); //$NON-NLS-1$ //$NON-NLS-2$
+ merger.setCommitNames(new String[] {
+ "BASE", ourName, revertName }); //$NON-NLS-1$
String shortMessage = "Revert \"" + srcCommit.getShortMessage() //$NON-NLS-1$
+ "\""; //$NON-NLS-1$
@@ -193,14 +194,15 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
merger.getBaseCommit(0, 1),
new ObjectId[] { headCommit.getId(),
srcParent.getId() },
- MergeStatus.FAILED, MergeStrategy.RESOLVE,
+ MergeStatus.FAILED, MergeStrategy.RECURSIVE,
merger.getMergeResults(), failingPaths, null);
else
failingResult = new MergeResult(null,
merger.getBaseCommit(0, 1),
new ObjectId[] { headCommit.getId(),
srcParent.getId() },
- MergeStatus.CONFLICTING, MergeStrategy.RESOLVE,
+ MergeStatus.CONFLICTING,
+ MergeStrategy.RECURSIVE,
merger.getMergeResults(), failingPaths, null);
if (!merger.failed() && !unmergedPaths.isEmpty()) {
String message = new MergeMessageFormatter()
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index f515609..b1fde1d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -168,7 +168,7 @@ public ObjectId call() throws GitAPIException,
.getParent(1));
ObjectId stashHeadCommit = stashCommit.getParent(0);
- ResolveMerger merger = (ResolveMerger) MergeStrategy.RESOLVE
+ ResolveMerger merger = (ResolveMerger) MergeStrategy.RECURSIVE
.newMerger(repo);
merger.setCommitNames(new String[] { "stashed HEAD", "HEAD",
"stash" });
@@ -181,7 +181,7 @@ public ObjectId call() throws GitAPIException,
dco.setFailOnConflict(true);
dco.checkout(); // Ignoring failed deletes....
if (applyIndex) {
- ResolveMerger ixMerger = (ResolveMerger) MergeStrategy.RESOLVE
+ ResolveMerger ixMerger = (ResolveMerger) MergeStrategy.RECURSIVE
.newMerger(repo, true);
ixMerger.setCommitNames(new String[] { "stashed HEAD",
"HEAD", "stashed index" });
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index ddd6ff7..ea56392 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -46,6 +46,7 @@
import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT;
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
+import static org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation.PACK_DELTA;
import java.io.IOException;
import java.util.ArrayList;
@@ -56,6 +57,7 @@
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.PackIndex;
+import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
import org.eclipse.jgit.internal.storage.pack.PackWriter;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -88,12 +90,18 @@ public class DfsPackCompactor {
private final List<DfsPackFile> srcPacks;
+ private final List<PackWriter.ObjectIdSet> exclude;
+
private final List<DfsPackDescription> newPacks;
private final List<PackWriter.Statistics> newStats;
private int autoAddSize;
+ private RevWalk rw;
+ private RevFlag added;
+ private RevFlag isBase;
+
/**
* Initialize a pack compactor.
*
@@ -104,6 +112,7 @@ public DfsPackCompactor(DfsRepository repository) {
repo = repository;
autoAddSize = 5 * 1024 * 1024; // 5 MiB
srcPacks = new ArrayList<DfsPackFile>();
+ exclude = new ArrayList<PackWriter.ObjectIdSet>(4);
newPacks = new ArrayList<DfsPackDescription>(1);
newStats = new ArrayList<PackWriter.Statistics>(1);
}
@@ -141,11 +150,49 @@ public DfsPackCompactor autoAdd() throws IOException {
DfsPackDescription d = pack.getPackDescription();
if (d.getFileSize(PACK) < autoAddSize)
add(pack);
+ else
+ exclude(pack);
}
return this;
}
/**
+ * Exclude objects from the compacted pack.
+ *
+ * @param set
+ * objects to not include.
+ * @return {@code this}.
+ */
+ public DfsPackCompactor exclude(PackWriter.ObjectIdSet set) {
+ exclude.add(set);
+ return this;
+ }
+
+ /**
+ * Exclude objects from the compacted pack.
+ *
+ * @param pack
+ * objects to not include.
+ * @return {@code this}.
+ * @throws IOException
+ * pack index cannot be loaded.
+ */
+ public DfsPackCompactor exclude(DfsPackFile pack) throws IOException {
+ final PackIndex idx;
+ DfsReader ctx = (DfsReader) repo.newObjectReader();
+ try {
+ idx = pack.getPackIndex(ctx);
+ } finally {
+ ctx.release();
+ }
+ return exclude(new PackWriter.ObjectIdSet() {
+ public boolean contains(AnyObjectId id) {
+ return idx.hasObject(id);
+ }
+ });
+ }
+
+ /**
* Compact the pack files together.
*
* @param pm
@@ -200,6 +247,7 @@ public void compact(ProgressMonitor pm) throws IOException {
pw.release();
}
} finally {
+ rw = null;
ctx.release();
}
}
@@ -239,50 +287,73 @@ public int compare(DfsPackFile a, DfsPackFile b) {
}
});
- RevWalk rw = new RevWalk(ctx);
- RevFlag added = rw.newFlag("ADDED"); //$NON-NLS-1$
+ rw = new RevWalk(ctx);
+ added = rw.newFlag("ADDED"); //$NON-NLS-1$
+ isBase = rw.newFlag("IS_BASE"); //$NON-NLS-1$
+ List<RevObject> baseObjects = new BlockList<RevObject>();
pm.beginTask(JGitText.get().countingObjects, ProgressMonitor.UNKNOWN);
for (DfsPackFile src : srcPacks) {
- List<ObjectIdWithOffset> want = new BlockList<ObjectIdWithOffset>();
- for (PackIndex.MutableEntry ent : src.getPackIndex(ctx)) {
- ObjectId id = ent.toObjectId();
- RevObject obj = rw.lookupOrNull(id);
- if (obj == null || !obj.has(added))
- want.add(new ObjectIdWithOffset(id, ent.getOffset()));
- }
+ List<ObjectIdWithOffset> want = toInclude(src, ctx);
+ if (want.isEmpty())
+ continue;
- // Sort objects by the order they appear in the pack file, for
- // two benefits. Scanning object type information is faster when
- // the pack is traversed in order, and this allows the PackWriter
- // to be given the new objects in a relatively sane newest-first
- // ordering without additional logic, like unpacking commits and
- // walking a commit queue.
- Collections.sort(want, new Comparator<ObjectIdWithOffset>() {
- public int compare(ObjectIdWithOffset a, ObjectIdWithOffset b) {
- return Long.signum(a.offset - b.offset);
- }
- });
-
- // Only pack each object at most once into the output file. The
- // PackWriter will later select a representation to reuse, which
- // may be the version in this pack, or may be from another pack if
- // the object was copied here to complete a thin pack and is larger
- // than a delta from another pack. This is actually somewhat common
- // if an object is modified frequently, such as the top level tree.
+ PackReverseIndex rev = src.getReverseIdx(ctx);
+ DfsObjectRepresentation rep = new DfsObjectRepresentation(src);
for (ObjectIdWithOffset id : want) {
int type = src.getObjectType(ctx, id.offset);
RevObject obj = rw.lookupAny(id, type);
- if (!obj.has(added)) {
- pm.update(1);
- pw.addObject(obj);
- obj.add(added);
+ if (obj.has(added))
+ continue;
+
+ pm.update(1);
+ pw.addObject(obj);
+ obj.add(added);
+
+ src.representation(rep, id.offset, ctx, rev);
+ if (rep.getFormat() != PACK_DELTA)
+ continue;
+
+ RevObject base = rw.lookupAny(rep.getDeltaBase(), type);
+ if (!base.has(added) && !base.has(isBase)) {
+ baseObjects.add(base);
+ base.add(isBase);
}
}
}
+ for (RevObject obj : baseObjects) {
+ if (!obj.has(added)) {
+ pm.update(1);
+ pw.addObject(obj);
+ obj.add(added);
+ }
+ }
pm.endTask();
}
+ private List<ObjectIdWithOffset> toInclude(DfsPackFile src, DfsReader ctx)
+ throws IOException {
+ PackIndex srcIdx = src.getPackIndex(ctx);
+ List<ObjectIdWithOffset> want = new BlockList<ObjectIdWithOffset>(
+ (int) srcIdx.getObjectCount());
+ SCAN: for (PackIndex.MutableEntry ent : srcIdx) {
+ ObjectId id = ent.toObjectId();
+ RevObject obj = rw.lookupOrNull(id);
+ if (obj != null && (obj.has(added) || obj.has(isBase)))
+ continue;
+ for (PackWriter.ObjectIdSet e : exclude)
+ if (e.contains(id))
+ continue SCAN;
+ want.add(new ObjectIdWithOffset(id, ent.getOffset()));
+ }
+ Collections.sort(want, new Comparator<ObjectIdWithOffset>() {
+ public int compare(ObjectIdWithOffset a, ObjectIdWithOffset b) {
+ return Long.signum(a.offset - b.offset);
+ }
+ });
+ return want;
+ }
+
private static void writePack(DfsObjDatabase objdb,
DfsPackDescription pack,
PackWriter pw, ProgressMonitor pm) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
index d498123..d3e1990 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
@@ -45,6 +45,7 @@
import java.util.Collections;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import javaewah.EWAHCompressedBitmap;
import javaewah.IntIterator;
@@ -142,13 +143,24 @@ public Iterator<Entry> iterator() {
final Iterator<StoredBitmap> it = oldPackIndex.getBitmaps().iterator();
return new Iterator<Entry>() {
+ private Entry entry;
+
public boolean hasNext() {
- return it.hasNext();
+ while (entry == null && it.hasNext()) {
+ StoredBitmap sb = it.next();
+ if (newPackIndex.findPosition(sb) != -1)
+ entry = new Entry(sb, sb.getFlags());
+ }
+ return entry != null;
}
public Entry next() {
- StoredBitmap sb = it.next();
- return new Entry(sb, sb.getFlags());
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ Entry res = entry;
+ entry = null;
+ return res;
}
public void remove() {
@@ -171,6 +183,9 @@ public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) {
if (oldBitmap == null)
return null;
+ if (newPackIndex.findPosition(objectId) == -1)
+ return null;
+
inflated.clear();
for (IntIterator i = oldBitmap.getBitmap().intIterator(); i.hasNext();)
inflated.set(prevToNewMapping[i.next()]);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
index fe073d8..1ce2774 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2011, 2013 Robin Rosenberg
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -55,11 +55,15 @@
*/
public class AutoCRLFOutputStream extends OutputStream {
+ static final int BUFFER_SIZE = 8000;
+
private final OutputStream out;
private int buf = -1;
- private byte[] binbuf = new byte[8000];
+ private byte[] binbuf = new byte[BUFFER_SIZE];
+
+ private byte[] onebytebuf = new byte[1];
private int binbufcnt = 0;
@@ -74,29 +78,8 @@ public AutoCRLFOutputStream(OutputStream out) {
@Override
public void write(int b) throws IOException {
- int overflow = buffer((byte) b);
- if (overflow >= 0)
- return;
- if (isBinary) {
- out.write(b);
- return;
- }
- if (b == '\n') {
- if (buf == '\r') {
- out.write('\n');
- buf = -1;
- } else if (buf == -1) {
- out.write('\r');
- out.write('\n');
- buf = -1;
- }
- } else if (b == '\r') {
- out.write(b);
- buf = '\r';
- } else {
- out.write(b);
- buf = -1;
- }
+ onebytebuf[0] = (byte) b;
+ write(onebytebuf, 0, 1);
}
@Override
@@ -144,15 +127,6 @@ public void write(byte[] b, int off, int len) throws IOException {
buf = '\r';
}
- private int buffer(byte b) throws IOException {
- if (binbufcnt > binbuf.length)
- return 1;
- binbuf[binbufcnt++] = b;
- if (binbufcnt == binbuf.length)
- decideMode();
- return 0;
- }
-
private int buffer(byte[] b, int off, int len) throws IOException {
if (binbufcnt > binbuf.length)
return len;
@@ -174,7 +148,7 @@ private void decideMode() throws IOException {
@Override
public void flush() throws IOException {
- if (binbufcnt < binbuf.length)
+ if (binbufcnt <= binbuf.length)
decideMode();
buf = -1;
out.flush();