From 9239bca48cad7653b43f89f71c49b3d0be682c51 Mon Sep 17 00:00:00 2001 From: Nico Kruber Date: Fri, 25 Jan 2013 16:12:41 +0100 Subject: jinterface: don't return compressed external term if bigger than uncompressed Now, OtpOutputStream#write_compressed() uses the same mechanism as erts_term_to_binary() in external.c: it tries to compress the given term into a buffer of the size of the uncompressed term and if this is not possible, i.e. the compression plus headers is bigger, it uses the uncompressed external term format instead. --- .../com/ericsson/otp/erlang/OtpOutputStream.java | 43 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'lib/jinterface/java_src') diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java index 8c3f48968e..541df20369 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java @@ -48,6 +48,8 @@ public class OtpOutputStream extends ByteArrayOutputStream { private static final BigDecimal ten = new BigDecimal(10.0); private static final BigDecimal one = new BigDecimal(1.0); + private boolean fixedSize = false; + /** * Create a stream with the default initial size (2048 bytes). */ @@ -101,10 +103,16 @@ public class OtpOutputStream extends ByteArrayOutputStream { * the storage of an OtpOutputStream instance. */ public void trimToSize() { - if (super.count < super.buf.length) { - final byte[] tmp = new byte[super.count]; - System.arraycopy(super.buf, 0, tmp, 0, super.count); + resize(super.count); + } + + private void resize(int size) { + if (size < super.buf.length) { + final byte[] tmp = new byte[size]; + System.arraycopy(super.buf, 0, tmp, 0, size); super.buf = tmp; + } else if (size > super.buf.length) { + ensureCapacity(size); } } @@ -118,6 +126,9 @@ public class OtpOutputStream extends ByteArrayOutputStream { public void ensureCapacity(int minCapacity) { int oldCapacity = super.buf.length; if (minCapacity > oldCapacity) { + if (fixedSize) { + throw new IllegalArgumentException("Trying to increase fixed-size buffer"); + } int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < oldCapacity + defaultIncrement) newCapacity = oldCapacity + defaultIncrement; @@ -796,6 +807,7 @@ public class OtpOutputStream extends ByteArrayOutputStream { * compress if the original term is smaller. */ if (oos.size() < 5) { + // fast path for small terms try { oos.writeTo(this); // if the term is written as a compressed term, the output @@ -806,16 +818,37 @@ public class OtpOutputStream extends ByteArrayOutputStream { "Intermediate stream failed for Erlang object " + o); } } else { - write1(OtpExternal.compressedTag); - write4BE(oos.size()); + int startCount = super.count; + // we need destCount bytes for an uncompressed term + // -> if compression uses more, use the uncompressed term! + int destCount = startCount + oos.size(); + this.resize(destCount); + this.fixedSize = true; final java.util.zip.DeflaterOutputStream dos = new java.util.zip.DeflaterOutputStream( this); try { + write1(OtpExternal.compressedTag); + write4BE(oos.size()); oos.writeTo(dos); dos.close(); // note: closes this, too! + } catch (final IllegalArgumentException e) { + // could not make the value smaller than originally + // -> reset to starting count, write uncompressed + super.count = startCount; + try { + oos.writeTo(this); + // if the term is written as a compressed term, the output + // stream is closed, so we do this here, too + this.close(); + } catch (IOException e2) { + throw new java.lang.IllegalArgumentException( + "Intermediate stream failed for Erlang object " + o); + } } catch (final IOException e) { throw new java.lang.IllegalArgumentException( "Intermediate stream failed for Erlang object " + o); + } finally { + this.fixedSize = false; } } } -- cgit v1.2.3