Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: cd91e4662d13
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 15899bb21396
Choose a head ref
  • 5 commits
  • 4 files changed
  • 2 contributors

Commits on Jun 1, 2017

  1. Copy the full SHA
    8d5a5a4 View commit details
  2. Copy the full SHA
    f4305a4 View commit details
  3. Copy the full SHA
    414fe36 View commit details
  4. Copy the full SHA
    4bd6888 View commit details

Commits on Jun 2, 2017

  1. Merge pull request #4636 from haines/gzip_reader_unget

    Implement Zlib::GzipReader #ungetbyte and #ungetc
    headius authored Jun 2, 2017
    Copy the full SHA
    15899bb View commit details
72 changes: 62 additions & 10 deletions core/src/main/java/org/jruby/ext/zlib/JZlibRubyGzipReader.java
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@
import org.jruby.RubyClass;
import org.jruby.RubyEnumerator;
import org.jruby.RubyException;
import org.jruby.RubyIO;
import org.jruby.RubyInteger;
import org.jruby.RubyNumeric;
import org.jruby.RubyString;
import org.jruby.anno.FrameField;
@@ -42,22 +42,23 @@
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Block;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.JavaSites;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import org.jruby.util.IOInputStream;
import org.jruby.util.StringSupport;
import org.jruby.util.TypeConverter;
import org.jruby.util.io.EncodingUtils;
import org.jruby.util.io.PosixShim;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.ArrayList;
import java.util.List;

import static org.jruby.RubyIO.PARAGRAPH_SEPARATOR;
import static org.jruby.runtime.Visibility.PRIVATE;

/**
@@ -133,7 +134,7 @@ public IRubyObject initialize(ThreadContext context, IRubyObject stream) {

position = 0;
line = 0;
bufferedStream = new BufferedInputStream(io);
bufferedStream = new PushbackInputStream(new BufferedInputStream(io), 512);

return this;
}
@@ -248,8 +249,14 @@ private ByteList newReadByteList(int size) {

private IRubyObject internalSepGets(ByteList sep, int limit) throws IOException {
ByteList result = newReadByteList();
boolean stripNewlines = false;

if (sep.getRealSize() == 0) sep = RubyIO.PARAGRAPH_SEPARATOR;
if (sep.getRealSize() == 0) {
sep = PARAGRAPH_SEPARATOR;
stripNewlines = true;
}

if (stripNewlines) skipNewlines();

int ce = -1;

@@ -266,6 +273,8 @@ private IRubyObject internalSepGets(ByteList sep, int limit) throws IOException

fixBrokenTrailingCharacter(result);

if (stripNewlines) skipNewlines();

// io.available() only returns 0 after EOF is encountered
// so we need to differentiate between the empty string and EOF
if (0 == result.length() && -1 == ce) return getRuntime().getNil();
@@ -276,6 +285,20 @@ private IRubyObject internalSepGets(ByteList sep, int limit) throws IOException
return newStr(getRuntime(), result);
}

private static final int NEWLINE = '\n';

private void skipNewlines() throws IOException {
while (true) {
int b = bufferedStream.read();
if (b == -1) break;

if (b != NEWLINE) {
bufferedStream.unread(b);
break;
}
}
}

public IRubyObject gets_18(ThreadContext context, IRubyObject[] args) {
return gets(context, args);
}
@@ -502,9 +525,9 @@ private boolean isEof() throws IOException {
// encountered the actual EOF during the reading.
// So, we compensate for that to provide MRI
// compatible behavior.
bufferedStream.mark(16);
bufferedStream.read();
bufferedStream.reset();
byte[] bytes = new byte[16];
int read = bufferedStream.read(bytes, 0, bytes.length);
bufferedStream.unread(bytes, 0, read);

return bufferedStream.available() == 0;
}
@@ -634,7 +657,36 @@ public IRubyObject each_line(ThreadContext context, IRubyObject[] args, Block bl
}

@JRubyMethod
public IRubyObject ungetc(IRubyObject arg) {
public IRubyObject ungetc(ThreadContext context, IRubyObject c) {
if (c.isNil()) return c;
if (c instanceof RubyInteger) {
c = EncodingUtils.encUintChr(context, ((RubyInteger) c).getIntValue(), getReadEncoding());
} else {
c = c.convertToString();
}

try {
byte[] bytes = ((RubyString) c).getBytes();
bufferedStream.unread(bytes);
position -= bytes.length;
} catch (IOException ioe) {
throw getRuntime().newIOErrorFromException(ioe);
}

return getRuntime().getNil();
}

@JRubyMethod
public IRubyObject ungetbyte(IRubyObject b) {
if (b.isNil()) return b;

try {
bufferedStream.unread(b.convertToInteger().getIntValue());
position--;
} catch (IOException ioe) {
throw getRuntime().newIOErrorFromException(ioe);
}

return getRuntime().getNil();
}

@@ -697,5 +749,5 @@ private void fixBrokenTrailingCharacter(ByteList result) throws IOException {
private long position = 0;
private IOInputStream ioInputStream;
private GZIPInputStream io;
private InputStream bufferedStream;
private PushbackInputStream bufferedStream;
}
21 changes: 21 additions & 0 deletions spec/ruby/library/zlib/gzipreader/gets_spec.rb
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
require File.expand_path('../../../../spec_helper', __FILE__)
require 'zlib'
require 'stringio'

describe 'GzipReader#gets' do
describe 'with "" separator' do
it 'reads paragraphs skipping newlines' do
# gz contains "\n\n\n\n\n123\n45\n\n\n\n\nabc\nde\n\n\n\n\n"
gz = Zlib::GzipReader.new(
StringIO.new(
[31, 139, 8, 0, 223, 152, 48, 89, 0, 3, 227, 226, 2, 2, 67, 35,
99, 46, 19, 83, 16, 139, 43, 49, 41, 153, 43, 37, 21, 204, 4, 0,
32, 119, 45, 184, 27, 0, 0, 0].pack('C*')
)
)

gz.gets('').should == "123\n45\n\n"
gz.gets('').should == "abc\nde\n\n"
gz.eof?.should be_true
end
end
end
114 changes: 114 additions & 0 deletions spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
require File.expand_path('../../../../spec_helper', __FILE__)
require 'stringio'
require 'zlib'

describe 'GzipReader#ungetbyte' do
before :each do
@data = '12345abcde'
@zip = [31, 139, 8, 0, 44, 220, 209, 71, 0, 3, 51, 52, 50, 54, 49, 77,
76, 74, 78, 73, 5, 0, 157, 5, 0, 36, 10, 0, 0, 0].pack('C*')
@io = StringIO.new @zip
end

describe 'at the start of the stream' do
before :each do
@gz = Zlib::GzipReader.new(@io)
end

describe 'with an integer' do
it 'prepends the byte to the stream' do
@gz.ungetbyte 0x21
@gz.read.should == '!12345abcde'
end

it 'decrements pos' do
@gz.ungetbyte 0x21
@gz.pos.should == -1
end
end

describe 'with nil' do
it 'does not prepend anything to the stream' do
@gz.ungetbyte nil
@gz.read.should == '12345abcde'
end

it 'does not decrement pos' do
@gz.ungetbyte nil
@gz.pos.should == 0
end
end
end

describe 'in the middle of the stream' do
before :each do
@gz = Zlib::GzipReader.new(@io)
@gz.read 5
end

describe 'with an integer' do
it 'inserts the corresponding character into the stream' do
@gz.ungetbyte 0x21
@gz.read.should == '!abcde'
end

it 'decrements pos' do
@gz.ungetbyte 0x21
@gz.pos.should == 4
end
end

describe 'with nil' do
it 'does not insert anything into the stream' do
@gz.ungetbyte nil
@gz.read.should == 'abcde'
end

it 'does not decrement pos' do
@gz.ungetbyte nil
@gz.pos.should == 5
end
end
end

describe 'at the end of the stream' do
before :each do
@gz = Zlib::GzipReader.new(@io)
@gz.read
end

describe 'with an integer' do
it 'appends the corresponding character to the stream' do
@gz.ungetbyte 0x21
@gz.read.should == '!'
end

it 'decrements pos' do
@gz.ungetbyte 0x21
@gz.pos.should == 9
end

it 'makes eof? false' do
@gz.ungetbyte 0x21
@gz.eof?.should be_false
end
end

describe 'with nil' do
it 'does not append anything to the stream' do
@gz.ungetbyte nil
@gz.read.should == ''
end

it 'does not decrement pos' do
@gz.ungetbyte nil
@gz.pos.should == 10
end

it 'does not make eof? false' do
@gz.ungetbyte nil
@gz.eof?.should be_true
end
end
end
end
277 changes: 277 additions & 0 deletions spec/ruby/library/zlib/gzipreader/ungetc_spec.rb
Original file line number Diff line number Diff line change
@@ -1 +1,278 @@
require File.expand_path('../../../../spec_helper', __FILE__)
require 'stringio'
require 'zlib'

describe 'GzipReader#ungetc' do
before :each do
@data = '12345abcde'
@zip = [31, 139, 8, 0, 44, 220, 209, 71, 0, 3, 51, 52, 50, 54, 49, 77,
76, 74, 78, 73, 5, 0, 157, 5, 0, 36, 10, 0, 0, 0].pack('C*')
@io = StringIO.new @zip
end

describe 'at the start of the stream' do
before :each do
@gz = Zlib::GzipReader.new(@io)
end

describe 'with a single-byte character' do
it 'prepends the character to the stream' do
@gz.ungetc 'x'
@gz.read.should == 'x12345abcde'
end

it 'decrements pos' do
@gz.ungetc 'x'
@gz.pos.should == -1
end
end

describe 'with a multi-byte character' do
it 'prepends the character to the stream' do
@gz.ungetc 'ŷ'
@gz.read.should == 'ŷ12345abcde'
end

it 'decrements pos' do
@gz.ungetc 'ŷ'
@gz.pos.should == -2
end
end

describe 'with a multi-character string' do
it 'prepends the characters to the stream' do
@gz.ungetc 'xŷž'
@gz.read.should == 'xŷž12345abcde'
end

it 'decrements pos' do
@gz.ungetc 'xŷž'
@gz.pos.should == -5
end
end

describe 'with an integer' do
it 'prepends the corresponding character to the stream' do
@gz.ungetc 0x21
@gz.read.should == '!12345abcde'
end

it 'decrements pos' do
@gz.ungetc 0x21
@gz.pos.should == -1
end
end

describe 'with an empty string' do
it 'does not prepend anything to the stream' do
@gz.ungetc ''
@gz.read.should == '12345abcde'
end

it 'does not decrement pos' do
@gz.ungetc ''
@gz.pos.should == 0
end
end

describe 'with nil' do
it 'does not prepend anything to the stream' do
@gz.ungetc nil
@gz.read.should == '12345abcde'
end

it 'does not decrement pos' do
@gz.ungetc nil
@gz.pos.should == 0
end
end
end

describe 'in the middle of the stream' do
before :each do
@gz = Zlib::GzipReader.new(@io)
@gz.read 5
end

describe 'with a single-byte character' do
it 'inserts the character into the stream' do
@gz.ungetc 'x'
@gz.read.should == 'xabcde'
end

it 'decrements pos' do
@gz.ungetc 'x'
@gz.pos.should == 4
end
end

describe 'with a multi-byte character' do
it 'inserts the character into the stream' do
@gz.ungetc 'ŷ'
@gz.read.should == 'ŷabcde'
end

it 'decrements pos' do
@gz.ungetc 'ŷ'
@gz.pos.should == 3
end
end

describe 'with a multi-character string' do
it 'inserts the characters into the stream' do
@gz.ungetc 'xŷž'
@gz.read.should == 'xŷžabcde'
end

it 'decrements pos' do
@gz.ungetc 'xŷž'
@gz.pos.should == 0
end
end

describe 'with an integer' do
it 'inserts the corresponding character into the stream' do
@gz.ungetc 0x21
@gz.read.should == '!abcde'
end

it 'decrements pos' do
@gz.ungetc 0x21
@gz.pos.should == 4
end
end

describe 'with an empty string' do
it 'does not insert anything into the stream' do
@gz.ungetc ''
@gz.read.should == 'abcde'
end

it 'does not decrement pos' do
@gz.ungetc ''
@gz.pos.should == 5
end
end

describe 'with nil' do
it 'does not insert anything into the stream' do
@gz.ungetc nil
@gz.read.should == 'abcde'
end

it 'does not decrement pos' do
@gz.ungetc nil
@gz.pos.should == 5
end
end
end

describe 'at the end of the stream' do
before :each do
@gz = Zlib::GzipReader.new(@io)
@gz.read
end

describe 'with a single-byte character' do
it 'appends the character to the stream' do
@gz.ungetc 'x'
@gz.read.should == 'x'
end

it 'decrements pos' do
@gz.ungetc 'x'
@gz.pos.should == 9
end

it 'makes eof? false' do
@gz.ungetc 'x'
@gz.eof?.should be_false
end
end

describe 'with a multi-byte character' do
it 'appends the character to the stream' do
@gz.ungetc 'ŷ'
@gz.read.should == 'ŷ'
end

it 'decrements pos' do
@gz.ungetc 'ŷ'
@gz.pos.should == 8
end

it 'makes eof? false' do
@gz.ungetc 'ŷ'
@gz.eof?.should be_false
end
end

describe 'with a multi-character string' do
it 'appends the characters to the stream' do
@gz.ungetc 'xŷž'
@gz.read.should == 'xŷž'
end

it 'decrements pos' do
@gz.ungetc 'xŷž'
@gz.pos.should == 5
end

it 'makes eof? false' do
@gz.ungetc 'xŷž'
@gz.eof?.should be_false
end
end

describe 'with an integer' do
it 'appends the corresponding character to the stream' do
@gz.ungetc 0x21
@gz.read.should == '!'
end

it 'decrements pos' do
@gz.ungetc 0x21
@gz.pos.should == 9
end

it 'makes eof? false' do
@gz.ungetc 0x21
@gz.eof?.should be_false
end
end

describe 'with an empty string' do
it 'does not append anything to the stream' do
@gz.ungetc ''
@gz.read.should == ''
end

it 'does not decrement pos' do
@gz.ungetc ''
@gz.pos.should == 10
end

it 'does not make eof? false' do
@gz.ungetc ''
@gz.eof?.should be_true
end
end

describe 'with nil' do
it 'does not append anything to the stream' do
@gz.ungetc nil
@gz.read.should == ''
end

it 'does not decrement pos' do
@gz.ungetc nil
@gz.pos.should == 10
end

it 'does not make eof? false' do
@gz.ungetc nil
@gz.eof?.should be_true
end
end
end
end