snappy_ffi 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/snappy_ffi.rb +137 -0
  2. metadata +73 -0
data/lib/snappy_ffi.rb ADDED
@@ -0,0 +1,137 @@
1
+ require 'rubygems'
2
+ require 'ffi'
3
+
4
+ #:nodoc
5
+ module Snappy; end
6
+
7
+ module Snappy::FFI
8
+ Version = "0.1.2"
9
+
10
+ #:nodoc
11
+ module Snappy::FFI::Lib
12
+ extend FFI::Library
13
+
14
+ # Find the library in the normal places, or the file specified by SNAPPY_LIB if set
15
+ paths =
16
+ Array(
17
+ ENV['SNAPPY_LIB'] ||
18
+ Dir['/{opt,usr}/{,local/}lib{,64}/libsnappy.{dylib,so*}']
19
+ )
20
+ begin
21
+ ffi_lib(*paths)
22
+ rescue LoadError
23
+ raise LoadError,
24
+ "didn't find libsnappy on your system. " +
25
+ "Please install (http://code.google.com/p/snappy/)"
26
+ end
27
+
28
+ # What should we look for?
29
+ ExportSets = [
30
+ {
31
+ :description => "g++ 4",
32
+ :max_compressed_length => '_ZN6snappy19MaxCompressedLengthEm',
33
+ :get_uncompressed_length => '_ZN6snappy21GetUncompressedLengthEPKcmPm',
34
+ :raw_compress => '_ZN6snappy11RawCompressEPKcmPcPm',
35
+ :raw_uncompress => '_ZN6snappy13RawUncompressEPKcmPc'
36
+ }
37
+ ]
38
+
39
+ # Let you add extra entries to this list without hacking at this file
40
+ if Snappy::FFI.const_defined?(:LocalExportSet)
41
+ ExportSets << Snappy::FFI::LocalExportSet
42
+ end
43
+
44
+ # Walk FunctionSets until we find something that works
45
+ libsnappy = ffi_libraries.first
46
+ ChosenExportSet = ExportSets.find { |set|
47
+ libsnappy.find_function(set[:max_compressed_length])
48
+ }
49
+
50
+ if ChosenExportSet.nil?
51
+ raise LoadError, "snappy_ffi couldn't identify your libsnappy's function exports. " +
52
+ "You'll need to determine what these functions are called, then tell Snappy::FFI. " +
53
+ "Please see http://github.com/delta407/snappy-ruby/ for more information."
54
+ end
55
+
56
+ attach_function :max_compressed_length, ChosenExportSet[:max_compressed_length],
57
+ [:size_t], :size_t
58
+ attach_function :get_uncompressed_length, ChosenExportSet[:get_uncompressed_length],
59
+ [:buffer_in, :size_t, :pointer], :bool
60
+ attach_function :raw_compress, ChosenExportSet[:raw_compress],
61
+ [:buffer_in, :size_t, :buffer_out, :pointer], :void
62
+ attach_function :raw_uncompress, ChosenExportSet[:raw_uncompress],
63
+ [:buffer_in, :size_t, :buffer_out], :bool
64
+
65
+ # We deal in *size_t quite a lot
66
+ # Make it a struct, so it's easy to convert from pointers to values and back
67
+ class SizeT < FFI::Struct
68
+ layout :value, :size_t
69
+ end
70
+ end
71
+
72
+ # Compresses a string, returning the compressed value
73
+ def self.compress(input)
74
+ # Set up our input
75
+ input = input.to_s
76
+ input_size = input.bytesize rescue input.size
77
+
78
+ # Make a place to record our compressed size
79
+ output_size = Lib::SizeT.new
80
+
81
+ # Make a buffer big enough to hold the worst case
82
+ max = Lib.max_compressed_length(input_size)
83
+ FFI::MemoryPointer.new(max) { |output_buffer|
84
+ # Compress
85
+ Lib.raw_compress(input, input_size, output_buffer, output_size.pointer)
86
+
87
+ # Get our string
88
+ output = output_buffer.get_bytes(0, output_size[:value])
89
+
90
+ # Return, copying taint as needed
91
+ if input.tainted?
92
+ return output.taint
93
+ else
94
+ return output
95
+ end
96
+ }
97
+ end
98
+
99
+ # Decompresses a string, throwing ArgumentError if it's somehow corrupt
100
+ def self.uncompress(input)
101
+ # Set up our input
102
+ input = input.to_s
103
+ input_size = input.bytesize rescue input.size
104
+
105
+ # Make a place to record our uncompressed size
106
+ output_size = Lib::SizeT.new
107
+
108
+ # See how big our output will be
109
+ if !Lib.get_uncompressed_length(input, input_size, output_size.pointer)
110
+ # failure!
111
+ raise ArgumentError, "invalid compressed data"
112
+ end
113
+
114
+ # Make the buffer
115
+ FFI::MemoryPointer.new(output_size[:value]) { |output_buffer|
116
+ # Decompress
117
+ if !Lib.raw_uncompress(input, input_size, output_buffer)
118
+ raise ArgumentError, "invalid compressed data"
119
+ end
120
+
121
+ # Get our string
122
+ output = output_buffer.get_bytes(0, output_size[:value])
123
+
124
+ # Return, copying taint as needed
125
+ if input.tainted?
126
+ return output.taint
127
+ else
128
+ return output
129
+ end
130
+ }
131
+ end
132
+ end
133
+
134
+ module Snappy
135
+ def self.compress(string); Snappy::FFI.compress(string) end
136
+ def self.uncompress(string); Snappy::FFI.uncompress(string) end
137
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snappy_ffi
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 2
9
+ version: 0.1.2
10
+ platform: ruby
11
+ authors:
12
+ - Will Glynn
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-03-24 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: ffi
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ description: FFI extension to to bring the Snappy compression library to Ruby. libsnappy must be installed.
33
+ email: will@willglynn.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files: []
39
+
40
+ files:
41
+ - lib/snappy_ffi.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/delta407/snappy-ruby
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements:
66
+ - libsnappy
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.6
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: FFI extension for libsnappy.
72
+ test_files: []
73
+