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