Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial revision.

  • Loading branch information...
commit 98b1855d35779343052103332dc3f615494c5f16 0 parents
@lucsky authored
1  .gitignore
@@ -0,0 +1 @@
+.DS_Store
3  README
@@ -0,0 +1,3 @@
+= ffi-zlib
+
+A ruby-ffi wrapper for the zlib library.
6 Rakefile
@@ -0,0 +1,6 @@
+require "test/unit"
+
+task :test do
+ $LOAD_PATH << "lib"
+ Dir[File.join("tests", "test_*.rb")].each { |t| require t }
+end
250 lib/ffi/zlib.rb
@@ -0,0 +1,250 @@
+# =============================================================================
+
+require "rubygems"
+require "ffi"
+
+# =============================================================================
+
+module FFI::Zlib
+ extend FFI::Library
+ ffi_lib("z")
+
+ # -------------------------------------------------------------------------
+
+ attach_function :zlibVersion, [ ], :string
+
+ # -------------------------------------------------------------------------
+
+ ZLIB_VERSION = zlibVersion()
+
+ # Allowed flush values.
+
+ Z_NO_FLUSH = 0
+ Z_PARTIAL_FLUSH = 1
+ Z_SYNC_FLUSH = 2
+ Z_FULL_FLUSH = 3
+ Z_FINISH = 4
+ Z_BLOCK = 5
+
+ # Return codes for the compression/decompression functions.
+ # Negative values are errors, positive values are used for special but
+ # normal events.
+
+ Z_OK = 0
+ Z_STREAM_END = 1
+ Z_NEED_DICT = 2
+ Z_ERRNO = -1
+ Z_STREAM_ERROR = -2
+ Z_DATA_ERROR = -3
+ Z_MEM_ERROR = -4
+ Z_BUF_ERROR = -5
+ Z_VERSION_ERROR = -6
+
+ # Compression levels.
+
+ Z_NO_COMPRESSION = 0
+ Z_BEST_SPEED = 1
+ Z_BEST_COMPRESSION = 9
+ Z_DEFAULT_COMPRESSION = -1
+
+ # Compression strategies.
+
+ Z_FILTERED = 1
+ Z_HUFFMAN_ONLY = 2
+ Z_RLE = 3
+ Z_FIXED = 4
+ Z_DEFAULT_STRATEGY = 0
+
+ # Possible values of the data_type field.
+
+ Z_BINARY = 0
+ Z_TEXT = 1
+ Z_UNKNOWN = 2
+
+ # The deflate compression method (the only one supported).
+
+ Z_DEFLATED = 8
+
+ # -------------------------------------------------------------------------
+
+ class Z_stream < FFI::Struct
+ layout :next_in, :pointer,
+ :avail_in, :uint,
+ :total_in, :ulong,
+
+ :next_out, :pointer,
+ :avail_out, :uint,
+ :total_out, :ulong,
+
+ :msg, :string,
+ :state, :pointer,
+
+ :alloc_func, :pointer,
+ :free_func, :pointer,
+ :opaque, :pointer,
+
+ :data_type, :int,
+ :adler, :ulong,
+ :reserved, :ulong
+ end
+
+ # -------------------------------------------------------------------------
+
+ class GZ_header < FFI::Struct
+ layout :text, :int,
+ :time, :ulong,
+ :xflags, :int,
+ :os, :int,
+
+ :extra, :pointer,
+ :extra_len, :uint,
+ :extra_max, :uint,
+
+ :name, :string,
+ :name_max, :uint,
+ :comment, :string,
+ :comm_max, :uint,
+
+ :hcrc, :int,
+ :done, :int
+ end
+
+ # -------------------------------------------------------------------------
+
+ def self.deflateInit(zstream, level)
+ deflateInit_(zstream, level, ZLIB_VERSION, zstream.size)
+ end
+
+ def self.deflateInit2(zstream, level, method, window_bits, mem_level, strategy)
+ deflateInit2_(zstream, level, method, window_bits, mem_level, strategy, ZLIB_VERSION, zstream.size)
+ end
+
+ attach_function :deflateInit_, [:pointer, :int, :string, :int], :int
+ attach_function :deflateInit2_, [:pointer, :int, :int, :int, :int, :int, :string, :int], :int
+ attach_function :deflate, [:pointer, :int], :int
+ attach_function :deflateEnd, [:pointer], :int
+
+ attach_function :deflateSetDictionary, [:pointer, :pointer, :uint], :int
+ attach_function :deflateCopy, [:pointer, :pointer], :int
+ attach_function :deflateReset, [:pointer], :int
+ attach_function :deflateParams, [:pointer, :int, :int], :int
+ attach_function :deflateTune, [:pointer, :int, :int, :int, :int], :int
+ attach_function :deflateBound, [:pointer, :ulong], :ulong
+ attach_function :deflatePrime, [:pointer, :int, :int], :int
+ attach_function :deflateSetHeader, [:pointer, :pointer], :int
+
+ # -------------------------------------------------------------------------
+
+ def self.inflateInit(zstream)
+ inflateInit_(zstream, ZLIB_VERSION, zstream.size)
+ end
+
+ def self.inflateInit2(zstream, window_bits)
+ inflateInit2_(zstream, window_bits, ZLIB_VERSION, zstream.size)
+ end
+
+ attach_function :inflateInit_, [:pointer, :string, :int], :int
+ attach_function :inflateInit2_, [:pointer, :int, :string, :int], :int
+ attach_function :inflate, [:pointer, :int], :int
+ attach_function :inflateEnd, [:pointer], :int
+
+ attach_function :inflateSetDictionary, [:pointer, :pointer, :uint], :int
+ attach_function :inflateSync, [:pointer], :int
+ attach_function :inflateCopy, [:pointer, :pointer], :int
+ attach_function :inflateReset, [:pointer], :int
+ attach_function :inflatePrime, [:pointer, :int, :int], :int
+ attach_function :inflateGetHeader, [:pointer, :pointer], :int
+
+ callback :in_func, [:pointer, :pointer], :uint
+ callback :out_func, [:pointer, :pointer, :uint], :int
+
+ attach_function :inflateBackInit_, [:pointer, :int, :pointer], :int
+ attach_function :inflateBack, [:pointer, :in_func, :pointer, :out_func, :pointer], :int
+ attach_function :inflateBackEnd, [:pointer], :int
+
+ # -------------------------------------------------------------------------
+
+ attach_function :compress, [:pointer, :buffer_inout, :pointer, :ulong], :int
+ attach_function :compress2, [:pointer, :pointer, :pointer, :ulong, :int], :int
+ attach_function :compressBound, [:ulong], :ulong
+
+ attach_function :uncompress, [:pointer, :buffer_inout, :pointer, :ulong], :int
+
+ # -------------------------------------------------------------------------
+
+ attach_function :gzopen, [:string, :string], :pointer
+ attach_function :gzdopen, [:int, :string], :pointer
+ attach_function :gzsetparams, [:pointer, :int, :int], :int
+ attach_function :gzread, [:pointer, :pointer, :uint], :int
+ attach_function :gzwrite, [:pointer, :pointer, :uint], :int
+ attach_function :gzprintf, [:pointer, :string, :varargs], :int
+ attach_function :gzputs, [:pointer, :string], :int
+ attach_function :gzgets, [:pointer, :pointer, :int], :pointer
+ attach_function :gzputc, [:pointer, :int], :int
+ attach_function :gzgetc, [:pointer, :pointer], :int
+ attach_function :gzungetc, [:int, :pointer], :int
+ attach_function :gzflush, [:pointer, :int], :int
+ attach_function :gzseek, [:pointer, :long, :int], :long
+ attach_function :gzrewind, [:pointer], :int
+ attach_function :gztell, [:pointer], :long
+ attach_function :gzeof, [:pointer], :int
+ attach_function :gzdirect, [:pointer], :int
+ attach_function :gzclose, [:pointer], :int
+ attach_function :gzerror, [:pointer, :buffer_out], :string
+ attach_function :gzclearerr, [:pointer], :void
+
+ # -------------------------------------------------------------------------
+
+ attach_function :adler32, [:ulong, :pointer, :uint], :ulong
+ attach_function :adler32_combine, [:ulong, :ulong, :long], :ulong
+ attach_function :crc32, [:ulong, :pointer, :uint], :ulong
+ attach_function :crc32_combine, [:ulong, :ulong, :long], :ulong
+
+ # -------------------------------------------------------------------------
+
+ attach_function :zlibCompileFlags, [ ], :ulong
+ attach_function :zError, [:int], :string
+ attach_function :inflateSyncPoint, [:pointer], :int
+ attach_function :get_crc_table, [ ], :pointer
+
+ # -------------------------------------------------------------------------
+end
+
+# =============================================================================
+
+#str = "toto tata titi tutu toto tata titi tutu toto tata titi tutu toto tata titi tutu toto tata titi tutu toto tata titi tutu"
+#inp = FFI::MemoryPointer.new(1024)
+#inp.put_string(0, str)
+#out = FFI::MemoryPointer.new(1024)
+#
+#zstream = FFI::Zlib::Z_stream.new
+#zstream[:next_in] = inp
+#zstream[:avail_in] = str.length
+#zstream[:next_out] = out
+#zstream[:avail_out] = 1024
+#
+#FFI::Zlib.deflateInit(zstream, FFI::Zlib::Z_DEFAULT_COMPRESSION)
+#FFI::Zlib.deflate(zstream, FFI::Zlib::Z_FINISH)
+#FFI::Zlib.deflateEnd(zstream)
+#
+#p zstream[:total_out]
+#compressed = out.get_bytes(0, zstream[:total_out])
+
+# ==============================================================================
+
+#out2 = FFI::MemoryPointer.new(1024)
+#zstream = FFI::Zlib::Z_stream.new
+#zstream[:next_in] = out
+#zstream[:avail_in] = compressed.length
+#zstream[:next_out] = out2
+#zstream[:avail_out] = 1024
+#
+#FFI::Zlib.inflateInit(zstream)
+#FFI::Zlib.inflate(zstream, FFI::Zlib::Z_FINISH)
+#FFI::Zlib.inflateEnd(zstream)
+#
+#p zstream[:total_out]
+#initial = out2.get_bytes(0, zstream[:total_out])
+#p initial
+
+# ==============================================================================
6 tests/helper.rb
@@ -0,0 +1,6 @@
+module Setup
+ def setup
+ @data = File.read(File.join("tests", "support", "pale_blue_dot.txt"))
+ @buffer = FFI::Buffer.alloc_in(4096)
+ end
+end
35 tests/support/pale_blue_dot.txt
@@ -0,0 +1,35 @@
+Look again at that dot. That's here. That's home. That's us. On it everyone you
+love, everyone you know, everyone you ever heard of, every human being who ever
+was, lived out their lives. The aggregate of our joy and suffering, thousands of
+confident religions, ideologies, and economic doctrines, every hunter and
+forager, every hero and coward, every creator and destroyer of civilization,
+every king and peasant, every young couple in love, every mother and father,
+hopeful child, inventor and explorer, every teacher of morals, every corrupt
+politician, every "superstar," every "supreme leader," every saint and sinner in
+the history of our species lived there – on a mote of dust suspended in a
+sunbeam.
+
+The Earth is a very small stage in a vast cosmic arena. Think of the rivers of
+blood spilled by all those generals and emperors so that, in glory and triumph,
+they could become the momentary masters of a fraction of a dot. Think of the
+endless cruelties visited by the inhabitants of one corner of this pixel on the
+scarcely distinguishable inhabitants of some other corner, how frequent their
+misunderstandings, how eager they are to kill one another, how fervent their
+hatreds.
+
+Our posturings, our imagined self-importance, the delusion that we have some
+privileged position in the Universe, are challenged by this point of pale light.
+Our planet is a lonely speck in the great enveloping cosmic dark. In our
+obscurity, in all this vastness, there is no hint that help will come from
+elsewhere to save us from ourselves.
+
+The Earth is the only world known so far to harbor life. There is nowhere else,
+at least in the near future, to which our species could migrate. Visit, yes.
+Settle, not yet. Like it or not, for the moment the Earth is where we make our
+stand.
+
+It has been said that astronomy is a humbling and character-building experience.
+There is perhaps no better demonstration of the folly of human conceits than
+this distant image of our tiny world. To me, it underscores our responsibility
+to deal more kindly with one another, and to preserve and cherish the pale blue
+dot, the only home we've ever known.
92 tests/test_checksums.rb
@@ -0,0 +1,92 @@
+require "test/unit"
+require "ffi/zlib"
+require "tests/helper.rb"
+
+class TestAdler32 < Test::Unit::TestCase
+ include Setup
+
+ EXPECTED_ADLER32_1 = 3874980441
+ EXPECTED_ADLER32_2 = 1707704336
+ EXPECTED_ADLER32_FULL = 869204599
+
+ def adler32(data)
+ @buffer.put_string(0, data)
+ checksum = FFI::Zlib.adler32(0, nil, 0)
+ FFI::Zlib.adler32(checksum, @buffer, data.length)
+ end
+
+ def test_adler32
+ checksum = self.adler32(@data)
+ assert_equal checksum, EXPECTED_ADLER32_FULL
+ end
+
+ def test_running_adler32
+ checksum = FFI::Zlib.adler32(0, nil, 0)
+ @data.each_line do |line|
+ @buffer.put_string(0, line)
+ checksum = FFI::Zlib.adler32(checksum, @buffer, line.length)
+ end
+
+ assert_equal checksum, EXPECTED_ADLER32_FULL
+ end
+
+ def test_adler32_combine
+ middle, _ = @data.length.divmod(2)
+ piece1 = @data[0...middle]
+ piece2 = @data[middle..-1]
+
+ checksum1 = self.adler32(piece1)
+ checksum2 = self.adler32(piece2)
+ checksum = FFI::Zlib.adler32_combine(checksum1, checksum2, piece2.length)
+
+ assert_equal checksum1, EXPECTED_ADLER32_1
+ assert_equal checksum2, EXPECTED_ADLER32_2
+ assert_equal checksum, EXPECTED_ADLER32_FULL
+ end
+
+
+end
+
+class TestCRC32 < Test::Unit::TestCase
+ include Setup
+
+ EXPECTED_CRC32_1 = 4007132158
+ EXPECTED_CRC32_2 = 1117097248
+ EXPECTED_CRC32_FULL = 703194008
+
+ def crc32(data)
+ @buffer.put_string(0, data)
+ checksum = FFI::Zlib.crc32(0, nil, 0)
+ checksum = FFI::Zlib.crc32(checksum, @buffer, data.length)
+ end
+
+ def test_crc32
+ checksum = self.crc32(@data)
+ assert_equal checksum, EXPECTED_CRC32_FULL
+ end
+
+ def test_running_crc32
+ checksum = FFI::Zlib.crc32(0, nil, 0)
+ @data.each_line do |line|
+ @buffer.put_string(0, line)
+ checksum = FFI::Zlib.crc32(checksum, @buffer, line.length)
+ end
+
+ assert_equal checksum, EXPECTED_CRC32_FULL
+ end
+
+ def test_crc32_combine
+ middle, _ = @data.length.divmod(2)
+ piece1 = @data[0...middle]
+ piece2 = @data[middle..-1]
+
+ checksum1 = self.crc32(piece1)
+ checksum2 = self.crc32(piece2)
+ checksum = FFI::Zlib.crc32_combine(checksum1, checksum2, piece2.length)
+
+ assert_equal checksum1, EXPECTED_CRC32_1
+ assert_equal checksum2, EXPECTED_CRC32_2
+ assert_equal checksum, EXPECTED_CRC32_FULL
+ end
+
+end
52 tests/test_compress.rb
@@ -0,0 +1,52 @@
+require "test/unit"
+require "ffi/zlib"
+require "tests/helper.rb"
+
+class TestCompress < Test::Unit::TestCase
+ include Setup
+
+ def test_compress
+ do_test
+
+ s1 = do_test(FFI::Zlib::Z_NO_COMPRESSION)
+ s2 = do_test(FFI::Zlib::Z_BEST_SPEED)
+ s3 = do_test(FFI::Zlib::Z_DEFAULT_COMPRESSION)
+ s4 = do_test(FFI::Zlib::Z_BEST_COMPRESSION)
+
+ assert s1 > s2
+ assert s2 > s3
+ assert s3 >= s4
+ end
+
+ def do_test(level=nil)
+ @buffer.put_string(0, @data)
+
+ buffer_size = FFI::Zlib.compressBound(@data.length)
+ assert_not_equal buffer_size, 0
+
+ compressed_buffer_size = FFI::Buffer.alloc_inout(:ulong).put_ulong(0, buffer_size)
+ compressed_buffer = FFI::MemoryPointer.new(buffer_size)
+
+ if level.nil?
+ result = FFI::Zlib.compress(compressed_buffer, compressed_buffer_size, @buffer, @data.length)
+ else
+ result = FFI::Zlib.compress2(compressed_buffer, compressed_buffer_size, @buffer, @data.length, level)
+ end
+
+ compressed_size = compressed_buffer_size.get_ulong(0)
+ assert_equal result, FFI::Zlib::Z_OK
+
+ uncompressed_buffer_size = FFI::Buffer.alloc_inout(:ulong).put_ulong(0, @data.length)
+ uncompressed_buffer = FFI::MemoryPointer.new(@data.length)
+ result = FFI::Zlib.uncompress(uncompressed_buffer, uncompressed_buffer_size, compressed_buffer, compressed_size)
+
+ uncompressed_size = uncompressed_buffer_size.get_ulong(0)
+ uncompressed = uncompressed_buffer.get_string(0)
+ assert_equal result, FFI::Zlib::Z_OK
+ assert_equal uncompressed_size, @data.length
+ assert_equal uncompressed, @data
+
+ return compressed_size
+ end
+
+end
Please sign in to comment.
Something went wrong with that request. Please try again.