Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Backport new zlib impl with JZlib

Just for performance comparison with old implementation.
  • Loading branch information...
commit 3bcb9ad17fad12561f2143f71d0f1c1199f308a6 1 parent 78a5fa7
Hiroshi Nakamura nahi authored
1  .classpath
@@ -38,5 +38,6 @@
38 38 <classpathentry kind="lib" path="build_lib/jnr-netdb.jar"/>
39 39 <classpathentry kind="lib" path="build_lib/org.osgi.core-4.2.0.jar"/>
40 40 <classpathentry kind="lib" path="build_lib/snakeyaml-1.9.jar"/>
  41 + <classpathentry kind="lib" path="build_lib/jzlib-1.1.0.jar"/>
41 42 <classpathentry kind="output" path="build.eclipse"/>
42 43 </classpath>
62 bench/bench_zlib.rb
... ... @@ -0,0 +1,62 @@
  1 +require 'benchmark'
  2 +require 'zlib'
  3 +require 'stringio'
  4 +
  5 +FILES = Dir.glob(File.expand_path('*.rb', File.dirname(__FILE__)))
  6 +
  7 +Benchmark.bmbm do |bm|
  8 + bm.report('Zlib::Deflate') do
  9 + z = Zlib::Deflate.new
  10 + 300.times do
  11 + FILES.each do |file|
  12 + z << File.read(file)
  13 + end
  14 + z.flush
  15 + end
  16 + z.finish
  17 + end
  18 +
  19 + bm.report('Zlib::Inflate') do
  20 + # prepare
  21 + z = Zlib::Deflate.new
  22 + FILES.each do |file|
  23 + z << File.read(file)
  24 + end
  25 + src = z.finish
  26 +
  27 + 3000.times do
  28 + z = Zlib::Inflate.new
  29 + z << src
  30 + z.finish
  31 + end
  32 + end
  33 +
  34 + bm.report('Zlib::GzipWriter') do
  35 + s = StringIO.new
  36 + Zlib::GzipWriter.wrap(s) do |gz|
  37 + 300.times do
  38 + FILES.each do |file|
  39 + gz.write File.read(file)
  40 + end
  41 + s.truncate(0)
  42 + end
  43 + end
  44 + end
  45 +
  46 + bm.report('Zlib::GzipReader') do
  47 + # prepare
  48 + s = StringIO.new
  49 + Zlib::GzipWriter.wrap(s) do |gz|
  50 + FILES.each do |file|
  51 + gz.write File.read(file)
  52 + end
  53 + end
  54 + src = s.string
  55 +
  56 + 3000.times do
  57 + Zlib::GzipReader.wrap(StringIO.new(src)) do |gz|
  58 + gz.read
  59 + end
  60 + end
  61 + end
  62 +end
3  build.xml
@@ -369,6 +369,7 @@
369 369 <zipfileset src="${build.lib.dir}/yecht.jar"/>
370 370 <zipfileset src="${build.lib.dir}/yydebug.jar"/>
371 371 <zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
  372 + <zipfileset src="${build.lib.dir}/jzlib-1.1.0.jar"/>
372 373 <metainf dir="spi">
373 374 <include name="services/**"/>
374 375 </metainf>
@@ -469,6 +470,7 @@
469 470 <zipfileset src="${build.lib.dir}/yecht.jar"/>
470 471 <zipfileset src="${build.lib.dir}/yydebug.jar"/>
471 472 <zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
  473 + <zipfileset src="${build.lib.dir}/jzlib-1.1.0.jar"/>
472 474 <metainf dir="spi">
473 475 <include name="services/**"/>
474 476 </metainf>
@@ -627,6 +629,7 @@
627 629 <zipfileset src="${build.lib.dir}/yecht.jar"/>
628 630 <zipfileset src="${build.lib.dir}/yydebug.jar"/>
629 631 <zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
  632 + <zipfileset src="${build.lib.dir}/jzlib-1.1.0.jar"/>
630 633 <metainf dir="spi">
631 634 <include name="services/**"/>
632 635 </metainf>
BIN  build_lib/jzlib-1.1.0.jar
Binary file not shown
1  spec/tags/1.8/ruby/library/zlib/deflate/params_tags.txt
... ... @@ -1 +0,0 @@
1   -fails(JRUBY-3775):Zlib::Deflate#params changes the deflate parameters
1  spec/tags/1.8/ruby/library/zlib/gzipwriter/mtime_tags.txt
... ... @@ -0,0 +1 @@
  1 +fails:Zlib::GzipWriter#mtime= raises if the header was written
1  spec/tags/1.9/ruby/library/zlib/gzipwriter/mtime_tags.txt
... ... @@ -0,0 +1 @@
  1 +fails:Zlib::GzipWriter#mtime= raises if the header was written
1,096 src/org/jruby/RubyZlib.java
@@ -33,23 +33,28 @@
33 33 package org.jruby;
34 34
35 35 import java.io.BufferedInputStream;
36   -import java.io.ByteArrayInputStream;
37   -import java.io.EOFException;
38 36 import java.io.IOException;
39 37 import java.io.InputStream;
40 38
41 39 import java.util.ArrayList;
42 40 import java.util.List;
43 41
44   -import java.util.zip.CRC32;
45   -import java.util.zip.DataFormatException;
46   -import java.util.zip.Deflater;
47   -import java.util.zip.DeflaterOutputStream;
48   -import java.util.zip.Inflater;
49   -import java.util.zip.InflaterInputStream;
50   -
51 42 import org.jcodings.Encoding;
52 43 import org.joda.time.DateTime;
  44 +import org.jruby.Ruby;
  45 +import org.jruby.RubyBasicObject;
  46 +import org.jruby.RubyClass;
  47 +import org.jruby.RubyFixnum;
  48 +import org.jruby.RubyIO;
  49 +import org.jruby.RubyKernel;
  50 +import org.jruby.RubyModule;
  51 +import org.jruby.RubyNumeric;
  52 +import org.jruby.RubyObject;
  53 +import org.jruby.RubyString;
  54 +import org.jruby.RubyStringIO;
  55 +import org.jruby.RubyTime;
  56 +import org.jruby.RubyBoolean;
  57 +import org.jruby.RubyException;
53 58
54 59 import org.jruby.anno.FrameField;
55 60 import org.jruby.anno.JRubyClass;
@@ -77,8 +82,9 @@
77 82 import org.jruby.util.TypeConverter;
78 83 import org.jruby.util.io.Stream;
79 84
  85 +import com.jcraft.jzlib.JZlib;
  86 +
80 87 import static org.jruby.CompatVersion.*;
81   -import org.jruby.ext.zlib.Util;
82 88
83 89 @JRubyModule(name="Zlib")
84 90 public class RubyZlib {
@@ -117,12 +123,12 @@ public static RubyModule createZlibModule(Ruby runtime) {
117 123 cGzFile.defineClassUnder("NoFooter", cGzError, cGzError.getAllocator());
118 124 cGzFile.defineClassUnder("LengthError", cGzError, cGzError.getAllocator());
119 125
120   - RubyClass cGzReader = mZlib.defineClassUnder("GzipReader", cGzFile, RubyGzipReader.GZIPREADER_ALLOCATOR);
  126 + RubyClass cGzReader = mZlib.defineClassUnder("GzipReader", cGzFile, JZlibRubyGzipReader.GZIPREADER_ALLOCATOR);
121 127 cGzReader.includeModule(runtime.getEnumerable());
122   - cGzReader.defineAnnotatedMethods(RubyGzipReader.class);
  128 + cGzReader.defineAnnotatedMethods(JZlibRubyGzipReader.class);
123 129
124   - RubyClass cGzWriter = mZlib.defineClassUnder("GzipWriter", cGzFile, RubyGzipWriter.GZIPWRITER_ALLOCATOR);
125   - cGzWriter.defineAnnotatedMethods(RubyGzipWriter.class);
  130 + RubyClass cGzWriter = mZlib.defineClassUnder("GzipWriter", cGzFile, JZlibRubyGzipWriter.GZIPWRITER_ALLOCATOR);
  131 + cGzWriter.defineAnnotatedMethods(JZlibRubyGzipWriter.class);
126 132
127 133 mZlib.defineConstant("ZLIB_VERSION", runtime.newString(ZLIB_VERSION));
128 134 mZlib.defineConstant("VERSION", runtime.newString(VERSION));
@@ -151,32 +157,32 @@ public static RubyModule createZlibModule(Ruby runtime) {
151 157 mZlib.defineConstant("OS_CPM", runtime.newFixnum(OS_CPM));
152 158 mZlib.defineConstant("OS_TOPS20", runtime.newFixnum(OS_TOPS20));
153 159
154   - mZlib.defineConstant("DEFAULT_STRATEGY", runtime.newFixnum(Z_DEFAULT_STRATEGY));
155   - mZlib.defineConstant("FILTERED", runtime.newFixnum(Z_FILTERED));
156   - mZlib.defineConstant("HUFFMAN_ONLY", runtime.newFixnum(Z_HUFFMAN_ONLY));
  160 + mZlib.defineConstant("DEFAULT_STRATEGY", runtime.newFixnum(JZlib.Z_DEFAULT_STRATEGY));
  161 + mZlib.defineConstant("FILTERED", runtime.newFixnum(JZlib.Z_FILTERED));
  162 + mZlib.defineConstant("HUFFMAN_ONLY", runtime.newFixnum(JZlib.Z_HUFFMAN_ONLY));
157 163
158   - mZlib.defineConstant("NO_FLUSH", runtime.newFixnum(Z_NO_FLUSH));
159   - mZlib.defineConstant("SYNC_FLUSH", runtime.newFixnum(Z_SYNC_FLUSH));
160   - mZlib.defineConstant("FULL_FLUSH", runtime.newFixnum(Z_FULL_FLUSH));
161   - mZlib.defineConstant("FINISH", runtime.newFixnum(Z_FINISH));
  164 + mZlib.defineConstant("NO_FLUSH", runtime.newFixnum(JZlib.Z_NO_FLUSH));
  165 + mZlib.defineConstant("SYNC_FLUSH", runtime.newFixnum(JZlib.Z_SYNC_FLUSH));
  166 + mZlib.defineConstant("FULL_FLUSH", runtime.newFixnum(JZlib.Z_FULL_FLUSH));
  167 + mZlib.defineConstant("FINISH", runtime.newFixnum(JZlib.Z_FINISH));
162 168
163   - mZlib.defineConstant("NO_COMPRESSION", runtime.newFixnum(Z_NO_COMPRESSION));
164   - mZlib.defineConstant("BEST_SPEED", runtime.newFixnum(Z_BEST_SPEED));
165   - mZlib.defineConstant("DEFAULT_COMPRESSION", runtime.newFixnum(Z_DEFAULT_COMPRESSION));
166   - mZlib.defineConstant("BEST_COMPRESSION", runtime.newFixnum(Z_BEST_COMPRESSION));
  169 + mZlib.defineConstant("NO_COMPRESSION", runtime.newFixnum(JZlib.Z_NO_COMPRESSION));
  170 + mZlib.defineConstant("BEST_SPEED", runtime.newFixnum(JZlib.Z_BEST_SPEED));
  171 + mZlib.defineConstant("DEFAULT_COMPRESSION", runtime.newFixnum(JZlib.Z_DEFAULT_COMPRESSION));
  172 + mZlib.defineConstant("BEST_COMPRESSION", runtime.newFixnum(JZlib.Z_BEST_COMPRESSION));
167 173
168   - mZlib.defineConstant("MAX_WBITS", runtime.newFixnum(MAX_WBITS));
  174 + mZlib.defineConstant("MAX_WBITS", runtime.newFixnum(JZlib.MAX_WBITS));
169 175
170 176 // ZStream actually *isn't* allocatable
171 177 RubyClass cZStream = mZlib.defineClassUnder("ZStream", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
172 178 cZStream.defineAnnotatedMethods(ZStream.class);
173 179 cZStream.undefineMethod("new");
174 180
175   - RubyClass cInflate = mZlib.defineClassUnder("Inflate", cZStream, Inflate.INFLATE_ALLOCATOR);
176   - cInflate.defineAnnotatedMethods(Inflate.class);
  181 + RubyClass cInflate = mZlib.defineClassUnder("Inflate", cZStream, JZlibInflate.INFLATE_ALLOCATOR);
  182 + cInflate.defineAnnotatedMethods(JZlibInflate.class);
177 183
178   - RubyClass cDeflate = mZlib.defineClassUnder("Deflate", cZStream, Deflate.DEFLATE_ALLOCATOR);
179   - cDeflate.defineAnnotatedMethods(Deflate.class);
  184 + RubyClass cDeflate = mZlib.defineClassUnder("Deflate", cZStream, JZlibDeflate.DEFLATE_ALLOCATOR);
  185 + cDeflate.defineAnnotatedMethods(JZlibDeflate.class);
180 186
181 187 runtime.getKernel().callMethod(runtime.getCurrentContext(), "require", runtime.newString("stringio"));
182 188
@@ -202,9 +208,9 @@ public static RubyModule createZlibModule(Ruby runtime) {
202 208
203 209 @JRubyMethod(name = "zlib_version", module = true, visibility = PRIVATE)
204 210 public static IRubyObject zlib_version(IRubyObject recv) {
205   - RubyBasicObject res = (RubyBasicObject) ((RubyModule)recv).fastGetConstant("ZLIB_VERSION");
  211 + RubyBasicObject res = (RubyBasicObject) ((RubyModule)recv).getConstant("ZLIB_VERSION");
206 212 // MRI behavior, enforced by tests
207   - res.taint(recv.getRuntime());
  213 + res.setTaint(true);
208 214 return res;
209 215 }
210 216
@@ -240,6 +246,7 @@ public static IRubyObject adler32(IRubyObject recv, IRubyObject[] args) {
240 246 return recv.getRuntime().newFixnum(ext.getValue());
241 247 }
242 248
  249 + // TODO: com.jcraft.jzlib.CRC32 has this table...
243 250 private final static long[] crctab = new long[]{
244 251 0L, 1996959894L, 3993919788L, 2567524794L, 124634137L, 1886057615L, 3915621685L, 2657392035L, 249268274L, 2044508324L, 3772115230L, 2547177864L, 162941995L,
245 252 2125561021L, 3887607047L, 2428444049L, 498536548L, 1789927666L, 4089016648L, 2227061214L, 450548861L, 1843258603L, 4107580753L, 2211677639L, 325883990L,
@@ -273,6 +280,32 @@ public static IRubyObject crc_table(IRubyObject recv) {
273 280 return recv.getRuntime().newArray(ll);
274 281 }
275 282
  283 + @JRubyMethod(name = "crc32_combine", required = 3, module = true, visibility = PRIVATE)
  284 + public static IRubyObject crc32_combine(IRubyObject recv,
  285 + IRubyObject arg0,
  286 + IRubyObject arg1,
  287 + IRubyObject arg2) {
  288 + long crc1 = RubyNumeric.num2long(arg0);
  289 + long crc2 = RubyNumeric.num2long(arg1);
  290 + long len2 = RubyNumeric.num2long(arg2);
  291 +
  292 + long crc3 = com.jcraft.jzlib.JZlib.crc32_combine(crc1, crc2, len2);
  293 + return recv.getRuntime().newFixnum(crc3);
  294 + }
  295 +
  296 + @JRubyMethod(name = "adler32_combine", required = 3, module = true, visibility = PRIVATE)
  297 + public static IRubyObject adler32_combine(IRubyObject recv,
  298 + IRubyObject arg0,
  299 + IRubyObject arg1,
  300 + IRubyObject arg2) {
  301 + long adler1 = RubyNumeric.num2long(arg0);
  302 + long adler2 = RubyNumeric.num2long(arg1);
  303 + long len2 = RubyNumeric.num2long(arg2);
  304 +
  305 + long adler3 = com.jcraft.jzlib.JZlib.adler32_combine(adler1, adler2, len2);
  306 + return recv.getRuntime().newFixnum(adler3);
  307 + }
  308 +
276 309 @JRubyClass(name="Zlib::ZStream")
277 310 public static abstract class ZStream extends RubyObject {
278 311 protected boolean closed = false;
@@ -316,7 +349,7 @@ public IRubyObject stream_end_p() {
316 349 @JRubyMethod(name = "data_type")
317 350 public IRubyObject data_type() {
318 351 checkClosed();
319   - return getRuntime().fastGetModule("Zlib").fastGetConstant("UNKNOWN");
  352 + return getRuntime().getModule("Zlib").getConstant("UNKNOWN");
320 353 }
321 354
322 355 @JRubyMethod(name = { "closed?", "ended?"})
@@ -388,13 +421,14 @@ public IRubyObject close() {
388 421
389 422 void checkClosed() {
390 423 if (closed) {
391   - throw Util.newZlibError(getRuntime(), "stream is not ready");
  424 + throw newZlibError(getRuntime(), "stream is not ready");
392 425 }
393 426 }
394 427
  428 + // TODO: remove when JZlib checks the given level
395 429 static void checkLevel(Ruby runtime, int level) {
396   - if ((level < 0 || level > 9) && level != Deflater.DEFAULT_COMPRESSION) {
397   - throw Util.newStreamError(runtime, "stream error: invalid level");
  430 + if ((level < 0 || level > 9) && level != JZlib.Z_DEFAULT_COMPRESSION) {
  431 + throw newStreamError(runtime, "stream error: invalid level");
398 432 }
399 433 }
400 434
@@ -403,62 +437,63 @@ static void checkLevel(Ruby runtime, int level) {
403 437 * NOTE: deflateInit2 of zlib.c also accepts MAX_WBITS + 16(gzip compression).
404 438 * inflateInit2 also accepts MAX_WBITS + 16(gzip decompression) and MAX_WBITS + 32(automatic detection of gzip and LZ77).
405 439 */
  440 + // TODO: remove when JZlib checks the given windowBits
406 441 static void checkWindowBits(Ruby runtime, int wbits, boolean forInflate) {
407 442 wbits = Math.abs(wbits);
408   - if ((wbits & 0xf) < MIN_WBITS) {
409   - throw Util.newStreamError(runtime, "stream error: invalid window bits");
  443 + if ((wbits & 0xf) < 8) {
  444 + throw newStreamError(runtime, "stream error: invalid window bits");
410 445 }
411 446 if ((wbits & 0xf) != 0xf) {
412 447 // windowBits < 15 for reducing memory is meaningless on Java platform.
413 448 runtime.getWarnings().warn("windowBits < 15 is ignored on this platform");
414 449 // continue
415 450 }
416   - if (forInflate && wbits > MAX_WBITS + 32) {
417   - throw Util.newStreamError(runtime, "stream error: invalid window bits");
418   - } else if (!forInflate && wbits > MAX_WBITS + 16) {
419   - throw Util.newStreamError(runtime, "stream error: invalid window bits");
  451 + if (forInflate && wbits > JZlib.MAX_WBITS + 32) {
  452 + throw newStreamError(runtime, "stream error: invalid window bits");
  453 + } else if (!forInflate && wbits > JZlib.MAX_WBITS + 16) {
  454 + throw newStreamError(runtime, "stream error: invalid window bits");
420 455 }
421 456 }
422 457
  458 + // TODO: remove when JZlib checks the given strategy
423 459 static void checkStrategy(Ruby runtime, int strategy) {
424 460 switch (strategy) {
425   - case Deflater.DEFAULT_STRATEGY:
426   - case Deflater.FILTERED:
427   - case Deflater.HUFFMAN_ONLY:
  461 + case JZlib.Z_DEFAULT_STRATEGY:
  462 + case JZlib.Z_FILTERED:
  463 + case JZlib.Z_HUFFMAN_ONLY:
428 464 break;
429 465 default:
430   - throw Util.newStreamError(runtime, "stream error: invalid strategy");
  466 + throw newStreamError(runtime, "stream error: invalid strategy");
431 467 }
432 468 }
433 469 }
434 470
435 471 @JRubyClass(name = "Zlib::Inflate", parent = "Zlib::ZStream")
436   - public static class Inflate extends ZStream {
  472 + public static class JZlibInflate extends ZStream {
437 473
438 474 public static final int BASE_SIZE = 100;
439   - private Inflater flater;
440 475 private int windowBits;
441   - private boolean readHeaderNeeded = false;
442   - private boolean readTrailerNeeded = false;
443   - private CRC32 checksum;
444 476 private ByteList collected;
445 477 private ByteList input;
  478 +
  479 + private com.jcraft.jzlib.Inflater flater = null;
  480 +
446 481 protected static final ObjectAllocator INFLATE_ALLOCATOR = new ObjectAllocator() {
447 482
448 483 public IRubyObject allocate(Ruby runtime, RubyClass klass) {
449   - return new Inflate(runtime, klass);
  484 + return new JZlibInflate(runtime, klass);
450 485 }
451 486 };
452 487
453   - public Inflate(Ruby runtime, RubyClass type) {
  488 + public JZlibInflate(Ruby runtime, RubyClass type) {
454 489 super(runtime, type);
455 490 }
456 491
457 492 @JRubyMethod(name = "inflate", required = 1, meta = true, backtrace = true)
458 493 public static IRubyObject s_inflate(ThreadContext context, IRubyObject recv, IRubyObject string) {
459 494 RubyClass klass = (RubyClass) recv;
460   - Inflate inflate = (Inflate) klass.allocate();
461   - inflate.init(MAX_WBITS);
  495 + JZlibInflate inflate = (JZlibInflate) klass.allocate();
  496 + inflate.init(JZlib.DEF_WBITS);
462 497
463 498 IRubyObject result;
464 499 try {
@@ -472,7 +507,7 @@ public static IRubyObject s_inflate(ThreadContext context, IRubyObject recv, IRu
472 507
473 508 @JRubyMethod(name = "initialize", optional = 1, visibility = PRIVATE)
474 509 public IRubyObject _initialize(IRubyObject[] args) {
475   - windowBits = MAX_WBITS;
  510 + windowBits = JZlib.DEF_WBITS;
476 511
477 512 if (args.length > 0 && !args[0].isNil()) {
478 513 windowBits = RubyNumeric.fix2int(args[0]);
@@ -484,19 +519,8 @@ public IRubyObject _initialize(IRubyObject[] args) {
484 519 }
485 520
486 521 private void init(int windowBits) {
487   - boolean nowrap = false;
488   - if (windowBits < 0) {
489   - nowrap = true;
490   - } else if ((windowBits & 0x10) != 0) {
491   - nowrap = true; // gzip wrapper
492   - readHeaderNeeded = true;
493   - checksum = new CRC32();
494   - } else if ((windowBits & 0x20) != 0) {
495   - nowrap = true; // automatic detection
496   - readHeaderNeeded = true;
497   - checksum = new CRC32();
498   - }
499   - flater = new Inflater(nowrap);
  522 + flater = new com.jcraft.jzlib.Inflater();
  523 + flater.init(windowBits);
500 524 collected = new ByteList(BASE_SIZE);
501 525 input = new ByteList();
502 526 }
@@ -511,7 +535,7 @@ private RubyString flushOutput(Ruby runtime) {
511 535 if (collected.getRealSize() > 0) {
512 536 RubyString res = RubyString.newString(runtime, collected.getUnsafeBytes(),
513 537 collected.getBegin(), collected.getRealSize());
514   - Util.resetBuffer(collected);
  538 + resetBuffer(collected);
515 539 return res;
516 540 }
517 541 return RubyString.newEmptyString(runtime);
@@ -530,30 +554,7 @@ public IRubyObject append(ThreadContext context, IRubyObject arg) {
530 554
531 555 public void append(ByteList obj) {
532 556 if (!internalFinished()) {
533   - if (readHeaderNeeded) {
534   - input.append(obj);
535   - byte[] bytes = input.bytes();
536   - int size = parseHeader(bytes);
537   - switch (size) {
538   - case -1:
539   - // not in gzip format; reinitialize Inflater
540   - init(windowBits & 0xf);
541   - flater.setInput(obj.bytes());
542   - input = new ByteList(bytes, false);
543   - break;
544   - case 0:
545   - // buffer is short
546   - return;
547   - default:
548   - flater.setInput(bytes, size, bytes.length - size);
549   - input = new ByteList(bytes, size, bytes.length - size, false);
550   - break;
551   - }
552   - } else {
553   - byte[] bytes = obj.bytes();
554   - flater.setInput(bytes);
555   - input = new ByteList(bytes, false);
556   - }
  557 + flater.setInput(obj.bytes(), true);
557 558 } else {
558 559 input.append(obj);
559 560 }
@@ -566,7 +567,15 @@ public IRubyObject sync_point_p() {
566 567 }
567 568
568 569 public IRubyObject sync_point() {
569   - return getRuntime().getFalse();
  570 + int ret = flater.syncPoint();
  571 + switch(ret){
  572 + case 1:
  573 + return getRuntime().getTrue();
  574 + case com.jcraft.jzlib.JZlib.Z_DATA_ERROR:
  575 + throw newStreamError(getRuntime(), "stream error");
  576 + default:
  577 + return getRuntime().getFalse();
  578 + }
570 579 }
571 580
572 581 @JRubyMethod(name = "set_dictionary", required = 1, backtrace = true)
@@ -574,12 +583,20 @@ public IRubyObject set_dictionary(ThreadContext context, IRubyObject arg) {
574 583 try {
575 584 return set_dictionary(arg);
576 585 } catch (IllegalArgumentException iae) {
577   - throw Util.newStreamError(context.getRuntime(), "stream error: " + iae.getMessage());
  586 + throw newStreamError(context.getRuntime(), "stream error: " + iae.getMessage());
578 587 }
579 588 }
580 589
581 590 private IRubyObject set_dictionary(IRubyObject str) {
582   - flater.setDictionary(str.convertToString().getBytes());
  591 + byte [] tmp = str.convertToString().getBytes();
  592 + int ret = flater.setDictionary(tmp, tmp.length);
  593 + switch(ret){
  594 + case com.jcraft.jzlib.JZlib.Z_STREAM_ERROR:
  595 + throw newStreamError(getRuntime(), "stream error");
  596 + case com.jcraft.jzlib.JZlib.Z_DATA_ERROR:
  597 + throw newDataError(getRuntime(), "wrong dictionary");
  598 + default:
  599 + }
583 600 run(false);
584 601 return str;
585 602 }
@@ -604,14 +621,29 @@ public IRubyObject inflate(ThreadContext context, ByteList str) {
604 621
605 622 @JRubyMethod(name = "sync", required = 1)
606 623 public IRubyObject sync(ThreadContext context, IRubyObject string) {
607   - try {
608   - append(context, string);
609   - } catch (RaiseException re) {
610   - if (!re.getException().getMetaClass().getRealClass().getName().equals("Zlib::DataError")) {
611   - throw re;
  624 + if(flater.avail_in>0){
  625 + switch(flater.sync()){
  626 + case com.jcraft.jzlib.JZlib.Z_OK:
  627 + flater.setInput(string.convertToString().getByteList().bytes(),
  628 + true);
  629 + return getRuntime().getTrue();
  630 + case com.jcraft.jzlib.JZlib.Z_DATA_ERROR:
  631 + break;
  632 + default:
  633 + throw newStreamError(getRuntime(), "stream error");
612 634 }
613 635 }
614   - return context.getRuntime().getFalse();
  636 + if(string.convertToString().getByteList().length()<=0)
  637 + return getRuntime().getFalse();
  638 + flater.setInput(string.convertToString().getByteList().bytes(), true);
  639 + switch(flater.sync()){
  640 + case com.jcraft.jzlib.JZlib.Z_OK:
  641 + return getRuntime().getTrue();
  642 + case com.jcraft.jzlib.JZlib.Z_DATA_ERROR:
  643 + return getRuntime().getFalse();
  644 + default:
  645 + throw newStreamError(getRuntime(), "stream error");
  646 + }
615 647 }
616 648
617 649 private void run(boolean finish) {
@@ -621,57 +653,62 @@ private void run(boolean finish) {
621 653
622 654 while (!internalFinished() && resultLength != 0) {
623 655 // MRI behavior
624   - if (finish && flater.needsInput()) {
625   - throw Util.newBufError(runtime, "buffer error");
  656 + boolean needsInput = flater.avail_in<0;
  657 + if (finish && needsInput) {
  658 + throw newBufError(runtime, "buffer error");
626 659 }
627 660
628   - try {
629   - resultLength = flater.inflate(outp);
630   - if (flater.needsDictionary()) {
631   - throw Util.newDictError(runtime, "need dictionary");
632   - } else {
633   - if (input.getRealSize() > 0) {
634   - int remaining = flater.getRemaining();
635   - if (remaining > 0) {
636   - input.view(input.getRealSize() - remaining, remaining);
637   - } else {
638   - Util.resetBuffer(input);
639   - }
  661 + flater.setOutput(outp);
  662 +
  663 + int ret = flater.inflate(com.jcraft.jzlib.JZlib.Z_NO_FLUSH);
  664 + switch(ret){
  665 + case com.jcraft.jzlib.JZlib.Z_DATA_ERROR:
  666 + resultLength = flater.next_out_index;
  667 + if(resultLength>0){
  668 + // error has been occurred,
  669 + // but some data has been inflated successfully.
  670 + collected.append(outp, 0, resultLength);
640 671 }
641   - }
642   - } catch (DataFormatException ex) {
643   - throw Util.newDataError(runtime, "data error: " + ex.getMessage());
  672 + throw newDataError(runtime, flater.getMessage());
  673 + case com.jcraft.jzlib.JZlib.Z_NEED_DICT:
  674 + throw newDictError(runtime, "need dictionary");
  675 + case com.jcraft.jzlib.JZlib.Z_STREAM_END:
  676 + if(flater.avail_in>0){
  677 + // MRI behavior: pass-through
  678 + input.append(flater.next_in,
  679 + flater.next_in_index, flater.avail_in);
  680 + flater.setInput("".getBytes());
  681 + }
  682 + case com.jcraft.jzlib.JZlib.Z_OK:
  683 + resultLength = flater.next_out_index;
  684 + break;
  685 + default:
  686 + resultLength = 0;
644 687 }
645 688
646   - if (checksum != null) {
647   - checksum.update(outp, 0, resultLength);
648   - }
649 689 collected.append(outp, 0, resultLength);
650 690 if (resultLength == outp.length) {
651 691 outp = new byte[outp.length * 2];
652 692 }
653 693 }
654   - // process trailer if needed
655   - if (internalFinished() && readTrailerNeeded) {
656   - if (input.getRealSize() >= 8) {
657   - readTrailer(input.bytes(), flater.getBytesWritten() & 0xffffffffL,
658   - checksum.getValue());
659   - input.view(8, input.getRealSize() - 8);
660   - } else if (finish) {
661   - throw Util.newBufError(runtime, "buffer error");
  694 + if(finish){
  695 + if(!internalFinished()){
  696 + int err = flater.inflate(com.jcraft.jzlib.JZlib.Z_FINISH);
  697 + if(err != com.jcraft.jzlib.JZlib.Z_OK){
  698 + throw newBufError(getRuntime(), "buffer error");
  699 + }
662 700 }
663 701 }
664   - if (finish) flater.end();
665 702 }
666 703
667 704 @Override
668 705 protected int internalTotalIn() {
669   - return flater.getTotalIn();
  706 + return (int)flater.total_in;
670 707 }
671 708
672 709 @Override
673 710 protected int internalTotalOut() {
674   - return flater.getTotalOut();
  711 + return (int)flater.total_out;
675 712 }
676 713
677 714 @Override
@@ -691,7 +728,7 @@ protected boolean internalFinished() {
691 728
692 729 @Override
693 730 protected long internalAdler() {
694   - return (checksum != null) ? checksum.getValue() : flater.getAdler() & 0xffffffffL;
  731 + return flater.getAdler();
695 732 }
696 733
697 734 @Override
@@ -701,7 +738,7 @@ protected IRubyObject internalFinish() {
701 738 if (internalFinished()) {
702 739 if (input.getRealSize() > 0) {
703 740 collected.append(input);
704   - Util.resetBuffer(input);
  741 + resetBuffer(input);
705 742 }
706 743 }
707 744 return flushOutput(getRuntime());
@@ -712,76 +749,52 @@ protected void internalClose() {
712 749 flater.end();
713 750 }
714 751
715   - private int parseHeader(byte[] bytes) {
716   - ByteArrayInputStream is = new ByteArrayInputStream(bytes);
717   - try {
718   - // parsed Gzip header is not used
719   - Util.GzipHeader header = Util.readHeader(getRuntime(), is);
720   - if (header == null) {
721   - // Not a gzip format
722   - return -1;
723   - }
724   - readHeaderNeeded = false;
725   - readTrailerNeeded = true;
726   - return header.length;
727   - } catch (RaiseException re) {
728   - return 0;
729   - }
  752 + @Override
  753 + public IRubyObject avail_in() {
  754 + return getRuntime().newFixnum(flater.avail_in);
730 755 }
731 756
732   - private void readTrailer(byte[] trailer, long bytesWritten, long checksum) {
733   - Ruby runtime = getRuntime();
734   - try {
735   - Util.checkTrailer(runtime, trailer, bytesWritten, checksum);
736   - readTrailerNeeded = false;
737   - } catch (RaiseException re) {
738   - /*
739   - * uglish exception conversion. zlib.c returns Z_DATA_ERROR for
740   - * gzip footer error so Zlib::Inflate raises DataError for any
741   - * footer error. Unlike Zlib::Inflate, GZipReader raises
742   - * NoFooter, CRCError or LengthError for footer error (ext/zlib
743   - * parses by itself.)
744   - */
745   - throw Util.newDataError(runtime, re.getMessage());
746   - }
  757 + private static void resetBuffer(ByteList l) {
  758 + l.setBegin(0);
  759 + l.setRealSize(0);
  760 + l.invalidate();
747 761 }
748 762 }
749 763
750 764 @JRubyClass(name = "Zlib::Deflate", parent = "Zlib::ZStream")
751   - public static class Deflate extends ZStream {
  765 + public static class JZlibDeflate extends ZStream {
752 766
753 767 public static final int BASE_SIZE = 100;
754   - private Deflater flater;
755 768 private int level;
756 769 private int windowBits;
757 770 private int strategy;
758   - private boolean dumpHeaderNeeded = false;
759   - private boolean dumpTrailerNeeded = false;
760   - private CRC32 checksum;
761 771 private ByteList collected;
762 772 protected static final ObjectAllocator DEFLATE_ALLOCATOR = new ObjectAllocator() {
763 773
764 774 public IRubyObject allocate(Ruby runtime, RubyClass klass) {
765   - return new Deflate(runtime, klass);
  775 + return new JZlibDeflate(runtime, klass);
766 776 }
767 777 };
768 778
  779 + private com.jcraft.jzlib.Deflater flater = null;
  780 + private int flush = JZlib.Z_NO_FLUSH;
  781 +
769 782 @JRubyMethod(name = "deflate", required = 1, optional = 1, meta = true, backtrace = true)
770 783 public static IRubyObject s_deflate(IRubyObject recv, IRubyObject[] args) {
771 784 Ruby runtime = recv.getRuntime();
772 785 args = Arity.scanArgs(runtime, args, 1, 1);
773   - int level = Deflater.DEFAULT_COMPRESSION;
  786 + int level = JZlib.Z_DEFAULT_COMPRESSION;
774 787 if (!args[1].isNil()) {
775 788 level = RubyNumeric.fix2int(args[1]);
776 789 checkLevel(runtime, level);
777 790 }
778 791
779 792 RubyClass klass = (RubyClass) recv;
780   - Deflate deflate = (Deflate) klass.allocate();
781   - deflate.init(level, MAX_WBITS, 8, Deflater.DEFAULT_STRATEGY);
  793 + JZlibDeflate deflate = (JZlibDeflate) klass.allocate();
  794 + deflate.init(level, JZlib.DEF_WBITS, 8, JZlib.Z_DEFAULT_STRATEGY);
782 795
783 796 try {
784   - IRubyObject result = deflate.deflate(args[0].convertToString().getByteList(), Z_FINISH);
  797 + IRubyObject result = deflate.deflate(args[0].convertToString().getByteList(), JZlib.Z_FINISH);
785 798 deflate.close();
786 799 return result;
787 800 } catch (IOException ioe) {
@@ -789,7 +802,7 @@ public static IRubyObject s_deflate(IRubyObject recv, IRubyObject[] args) {
789 802 }
790 803 }
791 804
792   - public Deflate(Ruby runtime, RubyClass type) {
  805 + public JZlibDeflate(Ruby runtime, RubyClass type) {
793 806 super(runtime, type);
794 807 }
795 808
@@ -797,7 +810,7 @@ public Deflate(Ruby runtime, RubyClass type) {
797 810 public IRubyObject _initialize(IRubyObject[] args) {
798 811 args = Arity.scanArgs(getRuntime(), args, 0, 4);
799 812 level = -1;
800   - windowBits = MAX_WBITS;
  813 + windowBits = JZlib.MAX_WBITS;
801 814 int memlevel = 8;
802 815 strategy = 0;
803 816 if (!args[0].isNil()) {
@@ -820,28 +833,49 @@ public IRubyObject _initialize(IRubyObject[] args) {
820 833 }
821 834
822 835 private void init(int level, int windowBits, int memlevel, int strategy) {
823   - // Zlib behavior: negative win_bits means no header and no checksum.
824   - boolean nowrap = false;
825   - if (windowBits < 0) {
826   - nowrap = true;
827   - } else if ((windowBits & 0x10) != 0) {
828   - nowrap = true; // gzip wrapper
829   - dumpHeaderNeeded = true;
830   - checksum = new CRC32();
831   - }
832   - flater = new Deflater(level, nowrap);
833   - flater.setStrategy(strategy);
  836 + flush = JZlib.Z_NO_FLUSH;
  837 + flater = new com.jcraft.jzlib.Deflater();
  838 +
  839 + // TODO: Can we expect JZlib to check level, windowBits, and strategy here?
  840 + // Then we should remove checkLevel, checkWindowsBits and checkStrategy.
  841 + int err = flater.init(level, windowBits, memlevel);
  842 + if(err == com.jcraft.jzlib.JZlib.Z_STREAM_ERROR){
  843 + throw newStreamError(getRuntime(), "stream error");
  844 + }
  845 + err = flater.params(level, strategy);
  846 + if(err == com.jcraft.jzlib.JZlib.Z_STREAM_ERROR){
  847 + throw newStreamError(getRuntime(), "stream error");
  848 + }
  849 +
834 850 collected = new ByteList(BASE_SIZE);
835 851 }
836 852
837 853 @Override
838 854 @JRubyMethod(visibility = PRIVATE)
839   - public IRubyObject initialize_copy(IRubyObject other) {
840   - if (this == other) {
  855 + public IRubyObject initialize_copy(IRubyObject _other) {
  856 + if (!(_other instanceof JZlibDeflate)) {
  857 + throw getRuntime().newTypeError("Expecting an instance of class JZlibDeflate");
  858 + }
  859 +
  860 + if (this == _other) {
841 861 return this;
842 862 }
843   - // TODO: we cannot implement Deflate#dup as long as we use java.util.zip.Deflater...
844   - throw getRuntime().newNotImplementedError("Zlib::Deflate#dup is not supported");
  863 +
  864 + JZlibDeflate other = (JZlibDeflate)_other;
  865 +
  866 + this.level = other.level;
  867 + this.windowBits = other.windowBits;
  868 + this.strategy = other.strategy;
  869 + this.collected = (ByteList)other.collected.clone();
  870 +
  871 + this.flush = other.flush;
  872 + this.flater = new com.jcraft.jzlib.Deflater();
  873 + int ret = this.flater.copy(other.flater);
  874 + if(ret != com.jcraft.jzlib.JZlib.Z_OK){
  875 + throw newStreamError(getRuntime(), "stream error");
  876 + }
  877 +
  878 + return (IRubyObject)this;
845 879 }
846 880
847 881 @JRubyMethod(name = "<<", required = 1)
@@ -861,8 +895,16 @@ public IRubyObject params(ThreadContext context, IRubyObject level, IRubyObject
861 895 checkLevel(getRuntime(), l);
862 896 int s = RubyNumeric.fix2int(strategy);
863 897 checkStrategy(getRuntime(), s);
864   - flater.setLevel(l);
865   - flater.setStrategy(s);
  898 + if(flater.next_out==null)
  899 + flater.next_out=new byte[0];
  900 + flater.avail_out = flater.next_out.length;
  901 + flater.next_out_index = 0;
  902 + int err = flater.params(l, s);
  903 + if(err == com.jcraft.jzlib.JZlib.Z_STREAM_ERROR){
  904 + throw newStreamError(getRuntime(), "stream error");
  905 + }
  906 + if(flater.next_out_index>0)
  907 + collected.append(flater.next_out, 0, flater.next_out_index);
866 908 run();
867 909 return getRuntime().getNil();
868 910 }
@@ -870,11 +912,15 @@ public IRubyObject params(ThreadContext context, IRubyObject level, IRubyObject
870 912 @JRubyMethod(name = "set_dictionary", required = 1, backtrace = true)
871 913 public IRubyObject set_dictionary(ThreadContext context, IRubyObject arg) {
872 914 try {
873   - flater.setDictionary(arg.convertToString().getBytes());
  915 + byte [] tmp = arg.convertToString().getBytes();
  916 + int err = flater.setDictionary(tmp, tmp.length);
  917 + if(err == com.jcraft.jzlib.JZlib.Z_STREAM_ERROR){
  918 + throw newStreamError(context.getRuntime(), "stream error: ");
  919 + }
874 920 run();
875 921 return arg;
876 922 } catch (IllegalArgumentException iae) {
877   - throw Util.newStreamError(context.getRuntime(), "stream error: " + iae.getMessage());
  923 + throw newStreamError(context.getRuntime(), "stream error: " + iae.getMessage());
878 924 }
879 925 }
880 926
@@ -893,13 +939,13 @@ public IRubyObject flush(IRubyObject[] args) {
893 939 public IRubyObject deflate(IRubyObject[] args) {
894 940 args = Arity.scanArgs(getRuntime(), args, 1, 1);
895 941 if (internalFinished()) {
896   - throw Util.newStreamError(getRuntime(), "stream error");
  942 + throw newStreamError(getRuntime(), "stream error");
897 943 }
898 944 ByteList data = null;
899 945 if (!args[0].isNil()) {
900 946 data = args[0].convertToString().getByteList();
901 947 }
902   - int flush = Z_NO_FLUSH;
  948 + int flush = JZlib.Z_NO_FLUSH;
903 949 if (!args[1].isNil()) {
904 950 flush = RubyNumeric.fix2int(args[1]);
905 951 }
@@ -912,12 +958,12 @@ public IRubyObject deflate(IRubyObject[] args) {
912 958
913 959 @Override
914 960 protected int internalTotalIn() {
915   - return flater.getTotalIn();
  961 + return (int)flater.total_in;
916 962 }
917 963
918 964 @Override
919 965 protected int internalTotalOut() {
920   - return flater.getTotalOut();
  966 + return (int)flater.total_out;
921 967 }
922 968
923 969 @Override
@@ -937,7 +983,7 @@ public boolean internalFinished() {
937 983
938 984 @Override
939 985 protected long internalAdler() {
940   - return (checksum != null) ? checksum.getValue() : flater.getAdler() & 0xffffffffL;
  986 + return flater.getAdler();
941 987 }
942 988
943 989 @Override
@@ -951,29 +997,18 @@ protected void internalClose() {
951 997 }
952 998
953 999 private void append(ByteList obj) throws IOException {
954   - if (checksum != null) {
955   - if (dumpHeaderNeeded) {
956   - writeHeader();
957   - }
958   - checksum.update(obj.getUnsafeBytes(), obj.getBegin(), obj.getRealSize());
959   - }
960   - flater.setInput(obj.getUnsafeBytes(), obj.getBegin(), obj.getRealSize());
  1000 + flater.setInput(obj.getUnsafeBytes(),
  1001 + obj.getBegin(),
  1002 + obj.getRealSize(), true);
961 1003 run();
962 1004 }
963 1005
964 1006 private IRubyObject flush(int flush) {
965   - if (flush == Z_NO_FLUSH) {
  1007 + this.flush=flush;
  1008 + if (flush == JZlib.Z_NO_FLUSH) {
966 1009 return RubyString.newEmptyString(getRuntime());
967 1010 }
968   - if (flush == Z_FINISH) {
969   - flater.finish();
970   - run();
971   - if (dumpTrailerNeeded) {
972   - writeTrailer();
973   - }
974   - } else {
975   - run();
976   - }
  1011 + run();
977 1012 IRubyObject obj = RubyString.newString(getRuntime(), collected);
978 1013 collected = new ByteList(BASE_SIZE);
979 1014 return obj;
@@ -987,37 +1022,30 @@ private IRubyObject deflate(ByteList str, int flush) throws IOException {
987 1022 }
988 1023
989 1024 private IRubyObject finish() {
990   - return flush(Z_FINISH);
  1025 + return flush(JZlib.Z_FINISH);
991 1026 }
992 1027
993 1028 private void run() {
994   - if (flater.finished()) {
  1029 + if(internalFinished())
995 1030 return;
996   - }
997 1031 byte[] outp = new byte[1024];
998   - while (!flater.finished()) {
999   - int resultLength = flater.deflate(outp);
1000   - if (resultLength == 0) {
1001   - break;
  1032 + while (!internalFinished()){
  1033 + flater.setOutput(outp);
  1034 + int err = flater.deflate(flush);
  1035 + switch(err){
  1036 + case com.jcraft.jzlib.JZlib.Z_STREAM_ERROR:
  1037 + throw newStreamError(getRuntime(), "stream error: ");
  1038 + default:
1002 1039 }
1003   - collected.append(outp, 0, resultLength);
1004   - if (resultLength == outp.length) {
1005   - outp = new byte[outp.length * 2];
  1040 + int resultLength = flater.next_out_index;
  1041 + if(resultLength == 0)
  1042 + break;
  1043 + collected.append(flater.next_out, 0, resultLength);
  1044 + if (resultLength == flater.next_out.length && !internalFinished()) {
  1045 + outp = new byte[flater.next_out.length * 2];
1006 1046 }
1007 1047 }
1008 1048 }
1009   -
1010   - private void writeHeader() throws IOException {
1011   - collected.append(Util.dumpHeader(null, null, Z_DEFAULT_COMPRESSION, OS_CODE,
1012   - System.currentTimeMillis()));
1013   - dumpHeaderNeeded = false;
1014   - dumpTrailerNeeded = true;
1015   - }
1016   -
1017   - private void writeTrailer() {
1018   - collected.append(Util.dumpTrailer(flater.getTotalIn(), (int) checksum.getValue()));
1019   - dumpTrailerNeeded = false;
1020   - }
1021 1049 }
1022 1050
1023 1051 @JRubyClass(name="Zlib::GzipFile")
@@ -1061,9 +1089,9 @@ public static IRubyObject wrap(ThreadContext context, IRubyObject recv, IRubyObj
1061 1089
1062 1090 // TODO: People extending GzipWriter/reader will break. Find better way here.
1063 1091 if (recv == runtime.getModule("Zlib").getClass("GzipWriter")) {
1064   - instance = RubyGzipWriter.newInstance(recv, new IRubyObject[] { io }, block);
  1092 + instance = JZlibRubyGzipWriter.newInstance(recv, new IRubyObject[] { io }, block);
1065 1093 } else {
1066   - instance = RubyGzipReader.newInstance(recv, new IRubyObject[] { io }, block);
  1094 + instance = JZlibRubyGzipReader.newInstance(recv, new IRubyObject[] { io }, block);
1067 1095 }
1068 1096
1069 1097 return wrapBlock(context, instance, block);
@@ -1096,6 +1124,7 @@ public static RubyGzipFile newInstance(IRubyObject recv, Block block) {
1096 1124 protected RubyTime mtime;
1097 1125 protected Encoding externalEncoding;
1098 1126 protected Encoding internalEncoding;
  1127 + protected boolean sync = false;
1099 1128
1100 1129 public RubyGzipFile(Ruby runtime, RubyClass type) {
1101 1130 super(runtime, type);
@@ -1135,7 +1164,7 @@ protected boolean isClosed() {
1135 1164 @JRubyMethod(name = "orig_name")
1136 1165 public IRubyObject orig_name() {
1137 1166 if(closed) {
1138   - throw Util.newGzipFileError(getRuntime(), "closed gzip stream");
  1167 + throw newGzipFileError(getRuntime(), "closed gzip stream");
1139 1168 }
1140 1169 return nullFreeOrigName == null ? getRuntime().getNil() : nullFreeOrigName;
1141 1170 }
@@ -1148,7 +1177,7 @@ public IRubyObject to_io() {
1148 1177 @JRubyMethod(name = "comment")
1149 1178 public IRubyObject comment() {
1150 1179 if(closed) {
1151   - throw Util.newGzipFileError(getRuntime(), "closed gzip stream");
  1180 + throw newGzipFileError(getRuntime(), "closed gzip stream");
1152 1181 }
1153 1182 return nullFreeComment == null ? getRuntime().getNil() : nullFreeComment;
1154 1183 }
@@ -1165,7 +1194,7 @@ public IRubyObject mtime() {
1165 1194
1166 1195 @JRubyMethod(name = "sync")
1167 1196 public IRubyObject sync() {
1168   - return getRuntime().getNil();
  1197 + return sync ? getRuntime().getTrue() : getRuntime().getFalse();
1169 1198 }
1170 1199
1171 1200 @JRubyMethod(name = "finish")
@@ -1188,27 +1217,28 @@ public IRubyObject level() {
1188 1217 }
1189 1218
1190 1219 @JRubyMethod(name = "sync=", required = 1)
1191   - public IRubyObject set_sync(IRubyObject ignored) {
1192   - return getRuntime().getNil();
  1220 + public IRubyObject set_sync(IRubyObject arg) {
  1221 + sync = ((RubyBoolean)arg).isTrue();
  1222 + return sync ? getRuntime().getTrue() : getRuntime().getFalse();
1193 1223 }
1194 1224 }
1195 1225
1196 1226 @JRubyClass(name="Zlib::GzipReader", parent="Zlib::GzipFile", include="Enumerable")
1197   - public static class RubyGzipReader extends RubyGzipFile {
  1227 + public static class JZlibRubyGzipReader extends RubyGzipFile {
1198 1228
1199 1229 @JRubyClass(name="Zlib::GzipReader::Error", parent="Zlib::GzipReader")
1200 1230 public static class Error {}
1201 1231
1202 1232 protected static final ObjectAllocator GZIPREADER_ALLOCATOR = new ObjectAllocator() {
1203 1233 public IRubyObject allocate(Ruby runtime, RubyClass klass) {
1204   - return new RubyGzipReader(runtime, klass);
  1234 + return new JZlibRubyGzipReader(runtime, klass);
1205 1235 }
1206 1236 };
1207   -
  1237 +
1208 1238 @JRubyMethod(name = "new", rest = true, meta = true)
1209   - public static RubyGzipReader newInstance(IRubyObject recv, IRubyObject[] args, Block block) {
  1239 + public static JZlibRubyGzipReader newInstance(IRubyObject recv, IRubyObject[] args, Block block) {
1210 1240 RubyClass klass = (RubyClass)recv;
1211   - RubyGzipReader result = (RubyGzipReader)klass.allocate();
  1241 + JZlibRubyGzipReader result = (JZlibRubyGzipReader)klass.allocate();
1212 1242 result.callInit(args, block);
1213 1243 return result;
1214 1244 }
@@ -1217,7 +1247,7 @@ public static RubyGzipReader newInstance(IRubyObject recv, IRubyObject[] args, B
1217 1247 public static IRubyObject open18(final ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
1218 1248 Ruby runtime = recv.getRuntime();
1219 1249 IRubyObject io = RuntimeHelpers.invoke(context, runtime.getFile(), "open", args[0], runtime.newString("rb"));
1220   - RubyGzipReader gzio = newInstance(recv, new IRubyObject[] { io }, block);
  1250 + JZlibRubyGzipReader gzio = newInstance(recv, new IRubyObject[] { io }, block);
1221 1251 return RubyGzipFile.wrapBlock(context, gzio, block);
1222 1252 }
1223 1253
@@ -1225,216 +1255,46 @@ public static IRubyObject open18(final ThreadContext context, IRubyObject recv,
1225 1255 public static IRubyObject open19(final ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
1226 1256 Ruby runtime = recv.getRuntime();
1227 1257 IRubyObject io = RuntimeHelpers.invoke(context, runtime.getFile(), "open", args[0], runtime.newString("rb"));
1228   - RubyGzipReader gzio = newInstance(recv, argsWithIo(io, args), block);
  1258 + JZlibRubyGzipReader gzio = newInstance(recv, argsWithIo(io, args), block);
1229 1259 return RubyGzipFile.wrapBlock(context, gzio, block);
1230 1260 }
1231   -
1232   - public RubyGzipReader(Ruby runtime, RubyClass type) {
  1261 +
  1262 + public JZlibRubyGzipReader(Ruby runtime, RubyClass type) {
1233 1263 super(runtime, type);
1234 1264 }
1235 1265
1236 1266 private int line;
1237 1267 private long position;
1238   - private HeaderReadableGZIPInputStream io;
  1268 + private com.jcraft.jzlib.GZIPInputStream io;
1239 1269 private InputStream bufferedStream;
1240 1270
1241   - /**
1242   - * IOInputStream wrapper for counting and keeping reading position.
1243   - */
1244   - private static class CountingIOInputStream extends IOInputStream {
1245   -
1246   - private int position;
1247   - IRubyObject io;
1248   -
1249   - public CountingIOInputStream(IRubyObject io) {
1250   - super(io);
1251   - this.io = io;
1252   - position = 0;
1253   - }
1254   -
1255   - @Override
1256   - public int read() throws IOException {
1257   - int ret = super.read();
1258   - if (ret != -1) {
1259   - position++;
1260   - }
1261   - return ret;
1262   - }
1263   -
1264   - @Override
1265   - public int read(byte[] b) throws IOException {
1266   - int ret = super.read(b);
1267   - if (ret != -1) {
1268   - position += ret;
1269   - }
1270   - return ret;
1271   - }
1272   -
1273   - @Override
1274   - public int read(byte[] b, int off, int len) throws IOException {
1275   - int ret = super.read(b, off, len);
1276   - if (ret != -1) {
1277   - position += ret;
1278   - }
1279   - return ret;
1280   - }
1281   -
1282   - int pos() {
1283   - return position;