msgpack-1.4.2/0000755000004100000410000000000014021120706013164 5ustar www-datawww-datamsgpack-1.4.2/doclib/0000755000004100000410000000000014021120706014420 5ustar www-datawww-datamsgpack-1.4.2/doclib/msgpack.rb0000644000004100000410000000405214021120706016373 0ustar www-datawww-data module MessagePack # # Serializes an object into an IO or String. # # @overload dump(obj, options={}) # @param obj [Object] object to be serialized # @param options [Hash] # @return [String] serialized data # # @overload dump(obj, io, options={}) # @param obj [Object] object to be serialized # @param io [IO] # @param options [Hash] # @return [nil] # # See Packer#initialize for supported options. # def self.dump(obj) end # # Serializes an object into an IO or String. Alias of dump. # # @overload pack(obj, options={}) # @param obj [Object] object to be serialized # @param options [Hash] # @return [String] serialized data # # @overload pack(obj, io, options={}) # @param obj [Object] object to be serialized # @param io [IO] # @param options [Hash] # @return [nil] # # See Packer#initialize for supported options. # def self.pack(obj) end # # Deserializes an object from an IO or String. # # @overload load(string, options={}) # @param string [String] data to deserialize # @param options [Hash] # # @overload load(io, options={}) # @param io [IO] # @param options [Hash] # # @return [Object] deserialized object # # See Unpacker#initialize for supported options. # def self.load(src, options={}) end # # Deserializes an object from an IO or String. Alias of load. # # @overload unpack(string, options={}) # @param string [String] data to deserialize # @param options [Hash] # # @overload unpack(io, options={}) # @param io [IO] # @param options [Hash] # # @return [Object] deserialized object # # See Unpacker#initialize for supported options. # def self.unpack(src, options={}) end # # An instance of Factory class. DefaultFactory is also used # by global pack/unpack methods such as MessagePack.dump/load, # Hash#to_msgpack, and other to_msgpack methods. # # Calling DefaultFactory.register_type lets you add an extension # type globally. # DefaultFactory = Factory.new end msgpack-1.4.2/doclib/msgpack/0000755000004100000410000000000014021120706016045 5ustar www-datawww-datamsgpack-1.4.2/doclib/msgpack/buffer.rb0000644000004100000410000001155614021120706017653 0ustar www-datawww-datamodule MessagePack class Buffer # # Creates a MessagePack::Buffer instance. # # @overload initialize(options={}) # @param options [Hash] # # @overload initialize(io, options={}) # @param io [IO] # @param options [Hash] # This buffer writes written data into the IO when it is filled. # This buffer reads data from the IO when it is empty. # # _io_ must respond to readpartial(length, [,string]) or read(string) method and # write(string) or append(string) method. # # Supported options: # # * *:io_buffer_size* buffer size to read data from the internal IO. (default: 32768) # * *:read_reference_threshold* the threshold size to enable zero-copy deserialize optimization. Read strings longer than this threshold will refer the original string instead of copying it. (default: 256) (supported in MRI only) # * *:write_reference_threshold* the threshold size to enable zero-copy serialize optimization. The buffer refers written strings longer than this threshold instead of copying it. (default: 524288) (supported in MRI only) # def initialize(*args) end # # Makes the buffer empty # # @return nil # def clear end # # Returns byte size of the buffer. # # @return nil # def size end # # Returns _true_ if the buffer is empty. # This method is slightly faster than _size_. # # @return [Boolean] # def empty? end # # Appends the given data to the buffer. # # @param data [String] # @return [Integer] byte size written # def write(data) end # # Appends the given data to the buffer. # # @param data [String] # @return [Buffer] self # def <<(data) end # # Consumes _n_ bytes from the head of the buffer and returns consumed data. # If the size of the buffer is less than _n_, it reads all of data in the buffer. # # If _n_ is 0, it does nothing and returns an empty string. # If the optional _buffer_ argument is given, the content of the string will be replaced with the consumed data. # # @overload read # # @overload read(n) # @param n [Integer] bytes to read # # @overload read(n, buffer) # @param n [Integer] bytes to read # @param buffer [String] buffer to read into # # @return [String] # def read(n) end # # Consumes _n_ bytes from the head of the buffer and returns consumed data. # If the size of the buffer is less than _n_, it does nothing and raises EOFError. # # If _n_ is 0, it does nothing and returns an empty string. # If the optional _buffer_ argument is given, the content of the string will be replaced with the consumed data. # # @overload read_all # # @overload read_all(n) # @param n [Integer] bytes to read # # @overload read_all(n, buffer) # @param n [Integer] bytes to read # @param buffer [String] buffer to read into # # @return [String] # def read_all(n, buffer=nil) end # # Consumes _n_ bytes from the head of the buffer. # If the size of the buffer is less than _n_, it skips all of data in the buffer and returns integer less than _n_. # # If _n_ is 0, it does nothing and returns _0_. # # @param n [Integer] byte size to skip # @return [Integer] byte size actually skipped # def skip(n) end # # Consumes _n_ bytes from the head of the buffer. # If the size of the buffer is less than _n_, it does nothing and raises EOFError. # If _n_ is 0, it does nothing. # # @param n [Integer] byte size to skip # @return [Buffer] self # def skip_all(n) end # # Returns all data in the buffer as a string. # Destructive update to the returned string does NOT effect the buffer. # # @return [String] # def to_str end # # Returns content of the buffer as an array of strings. # # This method is sometimes faster than to_s because the internal # structure of the buffer is a queue of buffer chunks. # # @return [Array] array of strings # def to_a end # # Internal io # # @return IO # attr_reader :io # # Flushes data in the internal buffer to the internal IO. # If internal IO is not set, it does nothing. # # @return [Buffer] self # def flush end # # Closes internal IO if its set. # If internal IO is not set, it does nothing # # @return nil # def close end # # Writes all of data in the internal buffer into the given IO. # This method consumes and removes data from the internal buffer. # _io_ must respond to write(data) method. # # @param io [IO] # @return [Integer] byte size of written data # def write_to(io) end end end msgpack-1.4.2/doclib/msgpack/core_ext.rb0000644000004100000410000000305014021120706020200 0ustar www-datawww-data class NilClass # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class TrueClass # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class FalseClass # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class Fixnum < Integer # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class Bignum < Integer # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class Float < Numeric # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class String # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class Array # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class Hash # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end class Symbol # # Same as MessagePack.to_msgpack(self[, packer]). # # @return [String] serialized data # def to_msgpack(packer=nil) end end msgpack-1.4.2/doclib/msgpack/error.rb0000644000004100000410000000045214021120706017524 0ustar www-datawww-datamodule MessagePack class UnpackError < StandardError end class MalformedFormatError < UnpackError end class StackError < UnpackError end class UnexpectedTypeError < UnpackError include TypeError end class UnknownExtTypeError < UnpackError include TypeError end end msgpack-1.4.2/doclib/msgpack/extension_value.rb0000644000004100000410000000046014021120706021602 0ustar www-datawww-datamodule MessagePack # # MessagePack::ExtensionValue is a struct to represent unknown ext type object. # Its contents are accessed by type and payload (messagepack bytes representation) methods. # And it is extended to add to_msgpack object. # ExtensionValue = Struct.new(:type, :payload) end msgpack-1.4.2/doclib/msgpack/timestamp.rb0000644000004100000410000000225314021120706020377 0ustar www-datawww-datamodule MessagePack # A utility class for MessagePack timestamp type class Timestamp # # The timestamp extension type defined in the MessagePack spec. # # See https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type for details. # TYPE = -1 # @return [Integer] Second part of the timestamp. attr_reader :sec # @return [Integer] Nanosecond part of the timestamp. attr_reader :nsec # @param [Integer] sec # @param [Integer] nsec def initialize(sec, nsec) end # @example An unpacker implementation for the Time class # lambda do |payload| # tv = MessagePack::Timestamp.from_msgpack_ext(payload) # Time.at(tv.sec, tv.nsec, :nanosecond) # end # # @param [String] data # @return [MessagePack::Timestamp] def self.from_msgpack_ext(data) end # @example A packer implementation for the Time class # unpacker = lambda do |time| # MessagePack::Timestamp.to_msgpack_ext(time.tv_sec, time.tv_nsec) # end # # @param [Integer] sec # @param [Integer] nsec # @return [String] def self.to_msgpack_ext(sec, nsec) end end end msgpack-1.4.2/doclib/msgpack/factory.rb0000644000004100000410000000570614021120706020051 0ustar www-datawww-datamodule MessagePack # # MessagePack::Factory is a class to generate Packer and Unpacker which has # same set of ext types. # class Factory # # Creates a MessagePack::Factory instance # def initialize end # # Creates a MessagePack::Packer instance, which has ext types already registered. # Options are passed to MessagePack::Packer#initialized. # # See also Packer#initialize for options. # def packer(*args) end # # Serialize the passed value # # If it could not serialize the object, it raises # NoMethodError: undefined method `to_msgpack' for #. # # @param obj [Object] object to serialize # @param options [Hash] # @return [String] serialized object # # See Packer#initialize for supported options. # def dump(obj, options={}) end alias pack dump # # Creates a MessagePack::Unpacker instance, which has ext types already registered. # Options are passed to MessagePack::Unpacker#initialized. # # See also Unpacker#initialize for options. # def unpacker(*args) end # # Deserializes an object from the string or io and returns it. # # If there're not enough data to deserialize one object, this method raises EOFError. # If data format is invalid, this method raises MessagePack::MalformedFormatError. # If the object nests too deeply, this method raises MessagePack::StackError. # # @param data [String] # @param options [Hash] # @return [Object] deserialized object # # See Unpacker#initialize for supported options. # def load(data, options={}) end alias unpack load # # Register a type and Class to be registered for packer and/or unpacker. # If options are not speicified, factory will use :to_msgpack_ext for packer, and # :from_msgpack_ext for unpacker. # # @param type [Fixnum] type id of registered Class (0-127) # @param klass [Class] Class to be associated with type id # @param options [Hash] specify method name or Proc which are used by packer/unpacker # @return nil # # Supported options: # # * *:packer* specify symbol or proc object for packer # * *:unpacker* specify symbol or proc object for unpacker # def register_type(type, klass, options={}) end # # Returns a list of registered types, ordered by type id. # # @param selector [Symbol] specify to list types registered for :packer, :unpacker or :both (default) # @return Array # def registered_types(selector=:both) end # # Returns true/false which indicate specified class or type id is registered or not. # # @param klass_or_type [Class or Fixnum] Class or type id (0-127) to be checked # @param selector [Symbol] specify to check for :packer, :unpacker or :both (default) # @return true or false # def type_registered?(klass_or_type, selector=:both) end end end msgpack-1.4.2/doclib/msgpack/time.rb0000644000004100000410000000116114021120706017327 0ustar www-datawww-datamodule MessagePack # MessagePack::Time provides packer and unpacker functions for a timestamp type. # @example Setup for DefaultFactory # MessagePack::DefaultFactory.register_type( # MessagePack::Timestamp::TYPE, # Time, # packer: MessagePack::Time::Packer, # unpacker: MessagePack::Time::Unpacker # ) class Time # A packer function that packs a Time instance to a MessagePack timestamp. Packer = lambda { |payload| # ... } # An unpacker function that unpacks a MessagePack timestamp to a Time instance. Unpacker = lambda { |time| # ... } end end msgpack-1.4.2/doclib/msgpack/packer.rb0000644000004100000410000001264314021120706017645 0ustar www-datawww-datamodule MessagePack # # MessagePack::Packer is a class to serialize objects. # class Packer # # Creates a MessagePack::Packer instance. # See Buffer#initialize for supported options. # # @overload initialize(options={}) # @param options [Hash] # # @overload initialize(io, options={}) # @param io [IO] # @param options [Hash] # This packer writes serialzied objects into the IO when the internal buffer is filled. # _io_ must respond to write(string) or append(string) method. # # Supported options: # # * *:compatibility_mode* serialize in older versions way, without str8 and bin types # # See also Buffer#initialize for other options. # def initialize(*args) end # # Register a new ext type to serialize it. This method should be called with one of # method name or block, which returns bytes(ASCII-8BIT String) representation of # object to be serialized. # # @overload register_type(type, klass, &block) # @param type [Fixnum] type id (0-127) user defined type id for specified Class # @param klass [Class] Class to be serialized with speicifed type id # @yieldparam object [Object] object to be serialized # # @overload register_type(type, klass, method_name) # @param type [Fixnum] type id (0-127) user defined type id for specified Class # @param klass [Class] Class to be serialized with speicifed type id # @param method_name [Symbol] method which returns bytes of serialized representation # # @return nil # def register_type(type, klass, method_name, &block) end # # Returns a list of registered types, ordered by type id. # Each element is a Hash object includes keys :type, :class and :packer. # # @return Array # def registered_types end # # Returns true/false which indicate specified class or type id is registered or not. # # @param klass_or_type [Class or Fixnum] Class or type id (0-127) to be checked # @return true or false # def type_registered?(klass_or_type) end # # Internal buffer # # @return MessagePack::Buffer # attr_reader :buffer # # Serializes an object into internal buffer, and flushes to io if necessary. # # If it could not serialize the object, it raises # NoMethodError: undefined method `to_msgpack' for #. # # @param obj [Object] object to serialize # @return [Packer] self # def write(obj) end alias pack write # # Serializes a nil object. Same as write(nil). # def write_nil end # # Serializes a string object as binary data. Same as write("string".encode(Encoding::BINARY)). # def write_bin(obj) end # # Write a header of an array whose size is _n_. # For example, write_array_header(1).write(true) is same as write([ true ]). # # @return [Packer] self # def write_array_header(n) end # # Write a header of an map whose size is _n_. # For example, write_map_header(1).write('key').write(true) is same as write('key'=>true). # # @return [Packer] self # def write_map_header(n) end # # Write a header of a binary string whose size is _n_. Useful if you want to append large binary data without loading it into memory at once. # For example, # MessagePack::Packer.new(io).write_bin_header(12).flush # io.write('chunk1') # io.write('chunk2') # is the same as # write('chunk1chunk2'.encode(Encoding::BINARY)). # # @return [Packer] self # def write_bin_header(n) end # # Serializes _value_ as 32-bit single precision float into internal buffer. # _value_ will be approximated with the nearest possible single precision float, thus # being potentially lossy. However, the serialized string will only take up 5 bytes # instead of 9 bytes compared to directly serializing a 64-bit double precision Ruby Float. # # @param value [Numeric] # @return [Packer] self # def write_float32(value) end # # Flushes data in the internal buffer to the internal IO. Same as _buffer.flush. # If internal IO is not set, it does nothing. # # @return [Packer] self # def flush end # # Makes the internal buffer empty. Same as _buffer.clear_. # # @return nil # def clear end # # Returns size of the internal buffer. Same as buffer.size. # # @return [Integer] # def size end # # Returns _true_ if the internal buffer is empty. Same as buffer.empty?. # This method is slightly faster than _size_. # # @return [Boolean] # def empty? end # # Returns all data in the buffer as a string. Same as buffer.to_str. # # @return [String] # def to_str end alias to_s to_str # # Returns content of the internal buffer as an array of strings. Same as buffer.to_a. # This method is faster than _to_str_. # # @return [Array] array of strings # def to_a end # # Writes all of data in the internal buffer into the given IO. Same as buffer.write_to(io). # This method consumes and removes data from the internal buffer. # _io_ must respond to write(data) method. # # @param io [IO] # @return [Integer] byte size of written data # def write_to(io) end end end msgpack-1.4.2/doclib/msgpack/unpacker.rb0000644000004100000410000001255514021120706020212 0ustar www-datawww-datamodule MessagePack # # MessagePack::Unpacker is a class to deserialize objects. # class Unpacker # # Creates a MessagePack::Unpacker instance. # # @overload initialize(options={}) # @param options [Hash] # # @overload initialize(io, options={}) # @param io [IO] # @param options [Hash] # This unpacker reads data from the _io_ to fill the internal buffer. # _io_ must respond to readpartial(length [,string]) or read(length [,string]) method. # # Supported options: # # * *:symbolize_keys* deserialize keys of Hash objects as Symbol instead of String # * *:allow_unknown_ext* allow to deserialize ext type object with unknown type id as ExtensionValue instance. Otherwise (by default), unpacker throws UnknownExtTypeError. # # See also Buffer#initialize for other options. # def initialize(*args) end # # Register a new ext type to deserialize it. This method should be called with # Class and its class method name, or block, which returns a instance object. # # @overload register_type(type, &block) # @param type [Fixnum] type id (0-127) user defined type id for specified deserializer block # @yieldparam data [String] bytes(ASCII-8BIT String) represents serialized object, to be deserialized # # @overload register_type(type, klass, class_method_name) # @param type [Fixnum] type id (0-127) user defined type id for specified Class # @param klass [Class] Class to be serialized with speicifed type id # @param class_method_name [Symbol] class method which returns an instance object # # @return nil # def register_type(type, klass, method_name, &block) end # # Returns a list of registered types, ordered by type id. # Each element is a Hash object includes keys :type, :class and :unpacker. # # @return Array # def registered_types end # # Returns true/false which indicate specified class or type id is registered or not. # # @param klass_or_type [Class or Fixnum] Class or type id (0-127) to be checked # @return true or false # def type_registered?(klass_or_type) end # # Internal buffer # # @return [MessagePack::Buffer] # attr_reader :buffer # # Deserializes an object from the io or internal buffer and returns it. # # This method reads data from io into the internal buffer and deserializes an object # from the buffer. It repeats reading data from the io until enough data is available # to deserialize at least one object. After deserializing one object, unused data is # left in the internal buffer. # # If there're not enough data to deserialize one object, this method raises EOFError. # If data format is invalid, this method raises MessagePack::MalformedFormatError. # If the object nests too deeply, this method raises MessagePack::StackError. # # @return [Object] deserialized object # def read end alias unpack read # # Deserializes an object and ignores it. This method is faster than _read_. # # This method could raise the same errors with _read_. # # @return nil # def skip end # # Deserializes a nil value if it exists and returns _true_. # Otherwise, if a byte exists but the byte doesn't represent nil value, # returns _false_. # # If there're not enough data, this method raises EOFError. # # @return [Boolean] # def skip_nil end # # Read a header of an array and returns its size. # It converts a serialized array into a stream of elements. # # If the serialized object is not an array, it raises MessagePack::UnexpectedTypeError. # If there're not enough data, this method raises EOFError. # # @return [Integer] size of the array # def read_array_header end # # Reads a header of an map and returns its size. # It converts a serialized map into a stream of key-value pairs. # # If the serialized object is not a map, it raises MessagePack::UnexpectedTypeError. # If there're not enough data, this method raises EOFError. # # @return [Integer] size of the map # def read_map_header end # # Appends data into the internal buffer. # This method is equivalent to unpacker.buffer.append(data). # # @param data [String] # @return [Unpacker] self # def feed(data) end # # Repeats to deserialize objects. # # It repeats until the io or internal buffer does not include any complete objects. # # If the an IO is set, it repeats to read data from the IO when the buffer # becomes empty until the IO raises EOFError. # # This method could raise same errors with _read_ excepting EOFError. # # @yieldparam object [Object] deserialized object # @return nil # def each(&block) end # # Appends data into the internal buffer and repeats to deserialize objects. # This method is equivalent to unpacker.feed(data) && unpacker.each { ... }. # # @param data [String] # @yieldparam object [Object] deserialized object # @return nil # def feed_each(data, &block) end # # Clears the internal buffer and resets deserialization state of the unpacker. # # @return nil # def reset end end end msgpack-1.4.2/msgpack.gemspec0000644000004100000410000000237614021120706016166 0ustar www-datawww-data$LOAD_PATH.push File.expand_path("../lib", __FILE__) require 'msgpack/version' Gem::Specification.new do |s| s.name = "msgpack" s.version = MessagePack::VERSION s.summary = "MessagePack, a binary-based efficient data interchange format." s.description = %q{MessagePack is a binary-based efficient object serialization library. It enables to exchange structured objects between many languages like JSON. But unlike JSON, it is very fast and small.} s.authors = ["Sadayuki Furuhashi", "Theo Hultberg", "Satoshi Tagomori"] s.email = ["frsyuki@gmail.com", "theo@iconara.net", "tagomoris@gmail.com"] s.license = "Apache 2.0" s.homepage = "http://msgpack.org/" s.require_paths = ["lib"] if /java/ =~ RUBY_PLATFORM s.files = Dir['lib/**/*.rb', 'lib/**/*.jar'] s.platform = Gem::Platform.new('java') else s.files = `git ls-files`.split("\n") s.extensions = ["ext/msgpack/extconf.rb"] end s.test_files = `git ls-files -- {test,spec}/*`.split("\n") s.required_ruby_version = ">= 2.4" s.add_development_dependency 'bundler' s.add_development_dependency 'rake' s.add_development_dependency 'rake-compiler' s.add_development_dependency 'rspec', ['~> 3.3'] s.add_development_dependency 'yard' s.add_development_dependency 'json' end msgpack-1.4.2/.travis.yml0000644000004100000410000000141114021120706015272 0ustar www-datawww-datalanguage: ruby branches: only: - master gemfile: - Gemfile before_install: # This is only for Ruby 2.5.0, Bundler 1.16.1 and rubygems 2.7.3 # See https://github.com/travis-ci/travis-ci/issues/8969 - "[ \"x2.7.3\" = \"x\"$(gem --version) ] && gem update --system --no-document || echo \"no need to update rubygem\"" # http://rubies.travis-ci.org/ matrix: include: - rvm: 2.4.5 os: linux - rvm: 2.5.8 os: linux - rvm: 2.6.6 os: linux - rvm: 2.6.6 os: osx - rvm: 2.7.1 os: linux - rvm: ruby-head os: linux - rvm: jruby-head os: linux - rvm: jruby-19mode os: linux allow_failures: - rvm: 2.6.1 os: osx - rvm: ruby-head - rvm: jruby-head - rvm: jruby-19mode msgpack-1.4.2/README.md0000644000004100000410000001600414021120706014444 0ustar www-datawww-data# MessagePack [MessagePack](http://msgpack.org) is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON but it's faster and smaller. For example, small integers (like flags or error code) are encoded into a single byte, and typical short strings only require an extra byte in addition to the strings themselves. If you ever wished to use JSON for convenience (storing an image with metadata) but could not for technical reasons (binary data, size, speed...), MessagePack is a perfect replacement. require 'msgpack' msg = [1,2,3].to_msgpack #=> "\x93\x01\x02\x03" MessagePack.unpack(msg) #=> [1,2,3] Use RubyGems to install: gem install msgpack or build msgpack-ruby and install: bundle rake gem install --local pkg/msgpack ## Use cases * Create REST API returing MessagePack using Rails + [RABL](https://github.com/nesquena/rabl) * Store objects efficiently serialized by msgpack on memcached or Redis * In fact Redis supports msgpack in [EVAL-scripts](http://redis.io/commands/eval) * Upload data in efficient format from mobile devices such as smartphones * MessagePack works on iPhone/iPad and Android. See also [Objective-C](https://github.com/msgpack/msgpack-objectivec) and [Java](https://github.com/msgpack/msgpack-java) implementations * Design a portable protocol to communicate with embedded devices * Check also [Fluentd](http://fluentd.org/) which is a log collector which uses msgpack for the log format (they say it uses JSON but actually it's msgpack, which is compatible with JSON) * Exchange objects between software components written in different languages * You'll need a flexible but efficient format so that components exchange objects while keeping compatibility ## Portability MessagePack for Ruby should run on x86, ARM, PowerPC, SPARC and other CPU architectures. And it works with MRI (CRuby) and Rubinius. Patches to improve portability is highly welcomed. ## Serializing objects Use `MessagePack.pack` or `to_msgpack`: ```ruby require 'msgpack' msg = MessagePack.pack(obj) # or msg = obj.to_msgpack ``` ### Streaming serialization Packer provides advanced API to serialize objects in streaming style: ```ruby # serialize a 2-element array [e1, e2] pk = MessagePack::Packer.new(io) pk.write_array_header(2).write(e1).write(e2).flush ``` See [API reference](http://ruby.msgpack.org/MessagePack/Packer.html) for details. ## Deserializing objects Use `MessagePack.unpack`: ```ruby require 'msgpack' obj = MessagePack.unpack(msg) ``` ### Streaming deserialization Unpacker provides advanced API to deserialize objects in streaming style: ```ruby # deserialize objects from an IO u = MessagePack::Unpacker.new(io) u.each do |obj| # ... end ``` or event-driven style which works well with EventMachine: ```ruby # event-driven deserialization def on_read(data) @u ||= MessagePack::Unpacker.new @u.feed_each(data) {|obj| # ... } end ``` See [API reference](http://ruby.msgpack.org/MessagePack/Unpacker.html) for details. ## Serializing and deserializing symbols By default, symbols are serialized as strings: ```ruby packed = :symbol.to_msgpack # => "\xA6symbol" MessagePack.unpack(packed) # => "symbol" ``` This can be customized by registering an extension type for them: ```ruby MessagePack::DefaultFactory.register_type(0x00, Symbol) # symbols now survive round trips packed = :symbol.to_msgpack # => "\xc7\x06\x00symbol" MessagePack.unpack(packed) # => :symbol ``` The extension type for symbols is configurable like any other extension type. For example, to customize how symbols are packed you can just redefine Symbol#to_msgpack_ext. Doing this gives you an option to prevent symbols from being serialized altogether by throwing an exception: ```ruby class Symbol def to_msgpack_ext raise "Serialization of symbols prohibited" end end MessagePack::DefaultFactory.register_type(0x00, Symbol) [1, :symbol, 'string'].to_msgpack # => RuntimeError: Serialization of symbols prohibited ``` ## Serializing and deserializing Time instances There are the timestamp extension type in MessagePack, but it is not registered by default. To map Ruby's Time to MessagePack's timestamp for the default factory: ```ruby MessagePack::DefaultFactory.register_type( MessagePack::Timestamp::TYPE, # or just -1 Time, packer: MessagePack::Time::Packer, unpacker: MessagePack::Time::Unpacker ) ``` See [API reference](http://ruby.msgpack.org/) for details. ## Extension Types Packer and Unpacker support [Extension types of MessagePack](https://github.com/msgpack/msgpack/blob/master/spec.md#types-extension-type). ```ruby # register how to serialize custom class at first pk = MessagePack::Packer.new(io) pk.register_type(0x01, MyClass1, :to_msgpack_ext) # equal to pk.register_type(0x01, MyClass) pk.register_type(0x02, MyClass2){|obj| obj.how_to_serialize() } # blocks also available # almost same API for unpacker uk = MessagePack::Unpacker.new() uk.register_type(0x01, MyClass1, :from_msgpack_ext) uk.register_type(0x02){|data| MyClass2.create_from_serialized_data(data) } ``` `MessagePack::Factory` is to create packer and unpacker which have same extension types. ```ruby factory = MessagePack::Factory.new factory.register_type(0x01, MyClass1) # same with next line factory.register_type(0x01, MyClass1, packer: :to_msgpack_ext, unpacker: :from_msgpack_ext) pk = factory.packer(options_for_packer) uk = factory.unpacker(options_for_unpacker) ``` For `MessagePack.pack` and `MessagePack.unpack`, default packer/unpacker refer `MessagePack::DefaultFactory`. Call `MessagePack::DefaultFactory.register_type` to enable types process globally. ```ruby MessagePack::DefaultFactory.register_type(0x03, MyClass3) MessagePack.unpack(data_with_ext_typeid_03) #=> MyClass3 instance ``` ## Buffer API MessagePack for Ruby provides a buffer API so that you can read or write data by hand, not via Packer or Unpacker API. This [MessagePack::Buffer](http://ruby.msgpack.org/MessagePack/Buffer.html) is backed with a fixed-length shared memory pool which is very fast for small data (<= 4KB), and has zero-copy capability which significantly affects performance to handle large binary data. ## How to build and run tests Before building msgpack, you need to install bundler and dependencies. gem install bundler bundle install Then, you can run the tasks as follows: ### Build bundle exec rake build ### Run tests bundle exec rake spec ### Generating docs bundle exec rake doc ## How to build -java rubygems To build -java gems for JRuby, run: rake build:java If this directory has Gemfile.lock (generated with MRI), remove it beforehand. ## Updating documents Online documents (http://ruby.msgpack.org) is generated from gh-pages branch. Following commands update documents in gh-pages branch: bundle exec rake doc git checkout gh-pages cp doc/* ./ -a ## Copyright * Author * Sadayuki Furuhashi * Copyright * Copyright (c) 2008-2015 Sadayuki Furuhashi * License * Apache License, Version 2.0 msgpack-1.4.2/spec/0000755000004100000410000000000014021120706014116 5ustar www-datawww-datamsgpack-1.4.2/spec/cruby/0000755000004100000410000000000014021120706015242 5ustar www-datawww-datamsgpack-1.4.2/spec/cruby/buffer_packer.rb0000644000004100000410000000100114021120706020355 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' require 'stringio' if defined?(Encoding) Encoding.default_external = 'ASCII-8BIT' end describe Packer do let :packer do Packer.new end it 'initialize' do Packer.new Packer.new(nil) Packer.new(StringIO.new) Packer.new({}) Packer.new(StringIO.new, {}) end it 'buffer' do o1 = packer.buffer.object_id packer.buffer << 'frsyuki' packer.buffer.to_s.should == 'frsyuki' packer.buffer.object_id.should == o1 end end msgpack-1.4.2/spec/cruby/buffer_spec.rb0000644000004100000410000002630514021120706020060 0ustar www-datawww-datarequire 'spec_helper' require 'random_compat' require 'stringio' if defined?(Encoding) Encoding.default_external = 'ASCII-8BIT' end describe Buffer do STATIC_EXAMPLES = {} STATIC_EXAMPLES[:empty01] = '' STATIC_EXAMPLES[:empty02] = '' STATIC_EXAMPLES[:copy01] = 'short' STATIC_EXAMPLES[:copy02] = 'short'*2 STATIC_EXAMPLES[:ref01] = 'short'*128 STATIC_EXAMPLES[:ref02] = 'short'*128*2 STATIC_EXAMPLES[:ref03] = 'a'*((1024*1024+2)*2) STATIC_EXAMPLES[:refcopy01] = 'short'*128 STATIC_EXAMPLES[:expand01] = 'short'*1024 STATIC_EXAMPLES[:expand02] = 'short'*(127+1024) STATIC_EXAMPLES[:offset01] = 'ort'+'short' STATIC_EXAMPLES[:offset02] = 'ort'+'short'*127 STATIC_EXAMPLES[:offset03] = 'ort'+'short'*(126+1024) if ''.respond_to?(:force_encoding) STATIC_EXAMPLES.each_value {|v| v.force_encoding('ASCII-8BIT') } end STATIC_EXAMPLES.each_value {|v| v.freeze } r = Random.new random_seed = r.seed puts "buffer random seed: 0x#{random_seed.to_s(16)}" let :random_cases_examples do r = Random.new(random_seed) cases = {} examples = {} 10.times do |i| b = Buffer.new s = r.bytes(0) r.rand(3).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b << x end r.rand(2).times do n = r.rand(1024*1400) b.read(n) s.slice!(0, n) end key = :"random#{"%02d" % i}" cases[key] = b examples[key] = s end [cases, examples] end let :static_cases do map = {} map[:empty01] = empty01 map[:empty02] = empty02 map[:copy01] = copy01 map[:copy02] = copy02 map[:ref01] = ref01 map[:ref02] = ref02 map[:ref03] = ref03 map[:refcopy01] = refcopy01 map[:expand01] = expand01 map[:expand02] = expand02 map[:offset01] = offset01 map[:offset02] = offset02 map[:offset03] = offset03 map end let :static_examples do STATIC_EXAMPLES end let :random_cases do random_cases_examples[0] end let :random_examples do random_cases_examples[1] end let :cases do static_cases.merge(random_cases) end let :examples do static_examples.merge(random_examples) end let :case_keys do examples.keys end let :empty01 do Buffer.new end let :empty02 do b = Buffer.new b << 'a' b.read_all(1) b end let :copy01 do # one copy chunk b = Buffer.new b << 'short' b end let :copy02 do # one copy chunk b = Buffer.new b << 'short' b << 'short' b end let :expand02 do # one copy chunk / expanded b = Buffer.new 1024.times do b << 'short' end b end let :ref01 do # one reference chunk b = Buffer.new b << 'short'*128 b.to_s b end let :ref02 do # two reference chunks b = Buffer.new b << 'short'*128 b.to_s b << 'short'*128 b.to_a b end let :ref03 do # two reference chunks b = Buffer.new b << 'a'*(1024*1024+2) b << 'a'*(1024*1024+2) b end let :refcopy01 do # one reference chunk + one copy chunk b = Buffer.new b << 'short'*127 b.to_s b << 'short' b end let :expand01 do # one copy chunk / expanded b = Buffer.new 1024.times do b << 'short' end b end let :expand02 do # one reference chunk + one copy chunk / expanded b = Buffer.new b << 'short'*127 b.to_s 1024.times do b << 'short' end b end let :offset01 do # one copy chunk / offset b = Buffer.new b << 'short' b << 'short' b.skip(2) b end let :offset02 do # one reference chunk / offset b = Buffer.new b << 'short'*127 b.to_s b.skip(2) b << 'short' b end let :offset03 do # one reference chunk / offset + one copy chunk / expanded b = Buffer.new b << 'short'*127 b.to_s 1024.times do b << 'short' end b.skip(2) b end it 'empty?' do empty01.empty?.should == true empty02.empty?.should == true end it 'size' do case_keys.each {|k| cases[k].size.should == examples[k].size } end it 'short write increments size' do case_keys.each {|k| sz = examples[k].size 10.times do |i| cases[k].write 'short' sz += 'short'.size cases[k].size.should == sz end } end it 'read with limit decrements size' do case_keys.each {|k| sz = examples[k].size next if sz < 2 cases[k].read(1).should == examples[k][0,1] sz -= 1 cases[k].size.should == sz cases[k].read(1).should == examples[k][1,1] sz -= 1 cases[k].size.should == sz } end it 'read_all with limit decrements size' do case_keys.each {|k| sz = examples[k].size next if sz < 2 cases[k].read_all(1).should == examples[k][0,1] sz -= 1 cases[k].size.should == sz cases[k].read_all(1).should == examples[k][1,1] sz -= 1 cases[k].size.should == sz } end it 'skip decrements size' do case_keys.each {|k| sz = examples[k].size next if sz < 2 cases[k].skip(1).should == 1 sz -= 1 cases[k].size.should == sz cases[k].skip(1).should == 1 sz -= 1 cases[k].size.should == sz } end it 'skip_all decrements size' do case_keys.each {|k| sz = examples[k].size next if sz < 2 cases[k].skip_all(1) sz -= 1 cases[k].size.should == sz cases[k].skip_all(1) sz -= 1 cases[k].size.should == sz } end it 'read_all against insufficient buffer raises EOFError and consumes nothing' do case_keys.each {|k| sz = examples[k].size lambda { cases[k].read_all(sz+1) }.should raise_error(EOFError) cases[k].size.should == sz } end it 'skip_all against insufficient buffer raises EOFError and consumes nothing' do case_keys.each {|k| sz = examples[k].size lambda { cases[k].skip_all(sz+1) }.should raise_error(EOFError) cases[k].size.should == sz } end it 'read against insufficient buffer consumes all buffer or return nil' do case_keys.each {|k| sz = examples[k].size if sz == 0 cases[k].read(sz+1).should == nil else cases[k].read(sz+1).should == examples[k] end cases[k].size.should == 0 } end it 'skip against insufficient buffer consumes all buffer' do case_keys.each {|k| sz = examples[k].size cases[k].skip(sz+1).should == examples[k].size cases[k].size.should == 0 } end it 'read with no arguments consumes all buffer and returns string and do not return nil' do case_keys.each {|k| cases[k].read_all.should == examples[k] cases[k].size.should == 0 } end it 'read_all with no arguments consumes all buffer and returns string' do case_keys.each {|k| cases[k].read_all.should == examples[k] cases[k].size.should == 0 } end it 'to_s returns a string and consume nothing' do case_keys.each {|k| cases[k].to_s.should == examples[k] cases[k].size.should == examples[k].size } end it 'to_s and modify' do case_keys.each {|k| s = cases[k].to_s s << 'x' cases[k].to_s.should == examples[k] } end it 'big write and modify reference' do big2 = "a" * (1024*1024 + 2) case_keys.each {|k| big1 = "a" * (1024*1024 + 2) cases[k].write(big1) big1 << 'x' cases[k].read.should == examples[k] + big2 } end it 'big write -> short write' do big1 = "a" * (1024*1024 + 2) case_keys.each {|k| sz = examples[k].size cases[k].write big1 cases[k].size.should == sz + big1.size cases[k].write("c") cases[k].size.should == sz + big1.size + 1 cases[k].read_all.should == examples[k] + big1 + "c" cases[k].size.should == 0 cases[k].empty?.should == true } end it 'big write 2'do big1 = "a" * (1024*1024 + 2) big2 = "b" * (1024*1024 + 2) case_keys.each {|k| sz = examples[k].size cases[k].write big1 cases[k].write big2 cases[k].size.should == sz + big1.size + big2.size cases[k].read_all(sz + big1.size).should == examples[k] + big1 cases[k].size.should == big2.size cases[k].read.should == big2 cases[k].size.should == 0 cases[k].empty?.should == true } end it 'read 0' do case_keys.each {|k| cases[k].read(0).should == '' cases[k].read.should == examples[k] } end it 'skip 0' do case_keys.each {|k| cases[k].skip(0).should == 0 cases[k].read.should == examples[k] } end it 'read_all 0' do case_keys.each {|k| cases[k].read_all(0).should == '' cases[k].read_all.should == examples[k] } end it 'skip_all 0' do case_keys.each {|k| cases[k].skip_all(0) cases[k].read_all.should == examples[k] } end it 'write_to' do case_keys.each {|k| sio = StringIO.new cases[k].write_to(sio).should == examples[k].size cases[k].size.should == 0 sio.string.should == examples[k] } end it 'random read/write' do r = Random.new(random_seed) s = r.bytes(0) b = Buffer.new 10.times { # write r.rand(4).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b.write(x) end # read r.rand(3).times do n = r.rand(1024*1400) ex = s.slice!(0, n) ex = nil if ex.empty? x = b.read(n) x.size == ex.size if x != nil x.should == ex b.size.should == s.size end } end it 'random read_all/write' do r = Random.new(random_seed) s = r.bytes(0) b = Buffer.new 10.times { # write r.rand(4).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b.write(x) end # read_all r.rand(3).times do n = r.rand(1024*1400) begin x = b.read_all(n) ex = s.slice!(0, n) x.size == n x.should == ex b.size.should == s.size rescue EOFError b.size.should == s.size b.read.should == s s.clear break end end } end it 'random skip write' do r = Random.new(random_seed) s = r.bytes(0) b = Buffer.new 10.times { # write r.rand(4).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b.write(x) end # skip r.rand(3).times do n = r.rand(1024*1400) ex = s.slice!(0, n) b.skip(n).should == ex.size b.size.should == s.size end } end it 'random skip_all write' do r = Random.new(random_seed) s = r.bytes(0) b = Buffer.new 10.times { # write r.rand(4).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b.write(x) end # skip_all r.rand(3).times do n = r.rand(1024*1400) begin b.skip_all(n) s.slice!(0, n) b.size.should == s.size ensure EOFError b.size.should == s.size b.read.should == s s.clear break end end } end end msgpack-1.4.2/spec/cruby/unpacker_spec.rb0000644000004100000410000000245514021120706020417 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' describe Unpacker do let :unpacker do Unpacker.new end let :packer do Packer.new end it 'skip_nil succeeds' do unpacker.feed("\xc0") unpacker.skip_nil.should == true end it 'skip_nil fails' do unpacker.feed("\x90") unpacker.skip_nil.should == false end it 'skip skips objects' do packer.write(1) packer.write(2) packer.write(3) packer.write(4) packer.write(5) unpacker = Unpacker.new unpacker.feed(packer.to_s) unpacker.read.should == 1 unpacker.skip unpacker.read.should == 3 unpacker.skip unpacker.read.should == 5 end it 'skip raises EOFError' do lambda { unpacker.skip }.should raise_error(EOFError) end it 'skip_nil raises EOFError' do lambda { unpacker.skip_nil }.should raise_error(EOFError) end it 'skip raises level stack too deep error' do 512.times { packer.write_array_header(1) } packer.write(nil) unpacker = Unpacker.new unpacker.feed(packer.to_s) lambda { unpacker.skip }.should raise_error(MessagePack::StackError) end it 'skip raises invalid byte error' do unpacker.feed("\xc1") lambda { unpacker.skip }.should raise_error(MessagePack::MalformedFormatError) end end msgpack-1.4.2/spec/cruby/buffer_unpacker.rb0000644000004100000410000000051414021120706020730 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' describe Unpacker do let :unpacker do Unpacker.new end let :packer do Packer.new end it 'buffer' do o1 = unpacker.buffer.object_id unpacker.buffer << 'frsyuki' unpacker.buffer.to_s.should == 'frsyuki' unpacker.buffer.object_id.should == o1 end end msgpack-1.4.2/spec/cruby/buffer_io_spec.rb0000644000004100000410000001112614021120706020542 0ustar www-datawww-datarequire 'spec_helper' require 'random_compat' require 'stringio' if defined?(Encoding) Encoding.default_external = 'ASCII-8BIT' end describe Buffer do r = Random.new random_seed = r.seed puts "buffer_io random seed: 0x#{random_seed.to_s(16)}" let :source do '' end def set_source(s) source.replace(s) end let :io do StringIO.new(source.dup) end let :buffer do Buffer.new(io) end it 'io returns internal io' do buffer.io.should == io end it 'close closes internal io' do expect(io).to receive(:close) buffer.close end it 'short feed and read all' do set_source 'aa' buffer.read.should == 'aa' end it 'short feed and read short' do set_source 'aa' buffer.read(1).should == 'a' buffer.read(1).should == 'a' buffer.read(1).should == nil end it 'long feed and read all' do set_source ' '*(1024*1024) s = buffer.read s.size.should == source.size s.should == source end it 'long feed and read mixed' do set_source ' '*(1024*1024) buffer.read(10).should == source.slice!(0, 10) buffer.read(10).should == source.slice!(0, 10) buffer.read(10).should == source.slice!(0, 10) s = buffer.read s.size.should == source.size s.should == source end it 'eof' do set_source '' buffer.read.should == '' end it 'eof 2' do set_source 'a' buffer.read.should == 'a' buffer.read.should == '' end it 'write short once and flush' do buffer.write('aa') buffer.flush io.string.should == 'aa' end it 'write short twice and flush' do buffer.write('a') buffer.write('a') buffer.flush io.string.should == 'aa' end it 'write long once and flush' do s = ' '*(1024*1024) buffer.write s buffer.flush io.string.size.should == s.size io.string.should == s end it 'write short multi and flush' do s = ' '*(1024*1024) 1024.times { buffer.write ' '*1024 } buffer.flush io.string.size.should == s.size io.string.should == s end it 'random read' do r = Random.new(random_seed) 50.times { fragments = [] r.rand(4).times do n = r.rand(1024*1400) s = r.bytes(n) fragments << s end io = StringIO.new(fragments.join) b = Buffer.new(io) fragments.each {|s| x = b.read(s.size) x.size.should == s.size x.should == s } b.empty?.should == true b.read.should == '' } end it 'random read_all' do r = Random.new(random_seed) 50.times { fragments = [] r.bytes(0) r.rand(4).times do n = r.rand(1024*1400) s = r.bytes(n) fragments << s end io = StringIO.new(fragments.join) b = Buffer.new(io) fragments.each {|s| x = b.read_all(s.size) x.size.should == s.size x.should == s } b.empty?.should == true lambda { b.read_all(1) }.should raise_error(EOFError) } end it 'random skip' do r = Random.new(random_seed) 50.times { fragments = [] r.rand(4).times do n = r.rand(1024*1400) s = r.bytes(n) fragments << s end io = StringIO.new(fragments.join) b = Buffer.new(io) fragments.each {|s| b.skip(s.size).should == s.size } b.empty?.should == true b.skip(1).should == 0 } end it 'random skip_all' do r = Random.new(random_seed) 50.times { fragments = [] r.rand(4).times do n = r.rand(1024*1400) s = r.bytes(n) fragments << s end io = StringIO.new(fragments.join) b = Buffer.new(io) fragments.each {|s| lambda { b.skip_all(s.size) }.should_not raise_error } b.empty?.should == true lambda { b.skip_all(1) }.should raise_error(EOFError) } end it 'random write and flush' do r = Random.new(random_seed) 50.times { s = r.bytes(0) io = StringIO.new b = Buffer.new(io) r.rand(4).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b.write(x) end (io.string.size + b.size).should == s.size b.flush io.string.size.should == s.size io.string.should == s } end it 'random write and clear' do r = Random.new(random_seed) b = Buffer.new 50.times { s = r.bytes(0) r.rand(4).times do n = r.rand(1024*1400) x = r.bytes(n) s << x b.write(x) end b.size.should == s.size b.clear } end end msgpack-1.4.2/spec/packer_spec.rb0000644000004100000410000003744014021120706016732 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' require 'stringio' require 'tempfile' require 'zlib' if defined?(Encoding) Encoding.default_external = 'ASCII-8BIT' end describe MessagePack::Packer do let :packer do MessagePack::Packer.new end it 'initialize' do MessagePack::Packer.new MessagePack::Packer.new(nil) MessagePack::Packer.new(StringIO.new) MessagePack::Packer.new({}) MessagePack::Packer.new(StringIO.new, {}) end it 'gets IO or object which has #write to write/append data to it' do sample_data = {"message" => "morning!", "num" => 1} sample_packed = MessagePack.pack(sample_data) Tempfile.open("for_io") do |file| file.sync = true p1 = MessagePack::Packer.new(file) p1.write sample_data p1.flush file.rewind expect(file.read).to eql(sample_packed) file.unlink end dio = StringIO.new p2 = MessagePack::Packer.new(dio) p2.write sample_data p2.flush dio.rewind expect(dio.string).to eql(sample_packed) dio = StringIO.new writer = Zlib::GzipWriter.new(dio) writer.sync = true p3 = MessagePack::Packer.new(writer) p3.write sample_data p3.flush writer.flush(Zlib::FINISH) writer.close dio.rewind compressed = dio.string str = Zlib::GzipReader.wrap(StringIO.new(compressed)){|gz| gz.read } expect(str).to eql(sample_packed) class DummyIO def initialize @buf = "".force_encoding('ASCII-8BIT') @pos = 0 end def write(val) @buf << val.to_s end def read(length=nil,outbuf="") if @pos == @buf.size nil elsif length.nil? val = @buf[@pos..(@buf.size)] @pos = @buf.size outbuf << val outbuf else val = @buf[@pos..(@pos + length)] @pos += val.size @pos = @buf.size if @pos > @buf.size outbuf << val outbuf end end def flush # nop end def close # nop end end dio = DummyIO.new p4 = MessagePack::Packer.new(dio) p4.write sample_data p4.flush expect(dio.read).to eql(sample_packed) end it 'gets options to specify how to pack values' do u1 = MessagePack::Packer.new u1.compatibility_mode?.should == false u2 = MessagePack::Packer.new(compatibility_mode: true) u2.compatibility_mode?.should == true end it 'write' do packer.write([]) packer.to_s.should == "\x90" end it 'write_nil' do packer.write_nil packer.to_s.should == "\xc0" end it 'write_array_header 0' do packer.write_array_header(0) packer.to_s.should == "\x90" end it 'write_array_header 1' do packer.write_array_header(1) packer.to_s.should == "\x91" end it 'write_map_header 0' do packer.write_map_header(0) packer.to_s.should == "\x80" end it 'write_map_header 1' do packer.write_map_header(1) packer.to_s.should == "\x81" end it 'write_bin_header 0' do packer.write_bin_header(0) packer.to_s.should == "\xC4\x00" end it 'write_bin_header 255' do packer.write_bin_header(255) packer.to_s.should == "\xC4\xFF" end it 'write_bin_header 256' do packer.write_bin_header(256) packer.to_s.should == "\xC5\x01\x00" end it 'write_bin_header 65535' do packer.write_bin_header(65535) packer.to_s.should == "\xC5\xFF\xFF" end it 'write_bin_header 65536' do packer.write_bin_header(65536) packer.to_s.should == "\xC6\x00\x01\x00\x00" end it 'write_bin_header 999999' do packer.write_bin_header(999999) packer.to_s.should == "\xC6\x00\x0F\x42\x3F" end it 'write_bin' do packer.write_bin("hello") packer.to_s.should == "\xC4\x05hello" end describe '#write_float32' do tests = [ ['small floats', 3.14, "\xCA\x40\x48\xF5\xC3"], ['big floats', Math::PI * 1_000_000_000_000_000_000, "\xCA\x5E\x2E\x64\xB7"], ['negative floats', -2.1, "\xCA\xC0\x06\x66\x66"], ['integer', 123, "\xCA\x42\xF6\x00\x00"], ] tests.each do |ctx, numeric, packed| context("with #{ctx}") do it("encodes #{numeric} as float32") do packer.write_float32(numeric) packer.to_s.should == packed end end end context 'with non numeric' do it 'raises argument error' do expect { packer.write_float32('abc') }.to raise_error(ArgumentError) end end end it 'flush' do io = StringIO.new pk = MessagePack::Packer.new(io) pk.write_nil pk.flush pk.to_s.should == '' io.string.should == "\xc0" end it 'to_msgpack returns String' do nil.to_msgpack.class.should == String true.to_msgpack.class.should == String false.to_msgpack.class.should == String 1.to_msgpack.class.should == String 1.0.to_msgpack.class.should == String "".to_msgpack.class.should == String Hash.new.to_msgpack.class.should == String Array.new.to_msgpack.class.should == String end it 'to_msgpack with packer equals to_msgpack' do nil.to_msgpack(MessagePack::Packer.new).to_str.should == nil.to_msgpack true.to_msgpack(MessagePack::Packer.new).to_str.should == true.to_msgpack false.to_msgpack(MessagePack::Packer.new).to_str.should == false.to_msgpack 1.to_msgpack(MessagePack::Packer.new).to_str.should == 1.to_msgpack 1.0.to_msgpack(MessagePack::Packer.new).to_str.should == 1.0.to_msgpack "".to_msgpack(MessagePack::Packer.new).to_str.should == "".to_msgpack Hash.new.to_msgpack(MessagePack::Packer.new).to_str.should == Hash.new.to_msgpack Array.new.to_msgpack(MessagePack::Packer.new).to_str.should == Array.new.to_msgpack end it 'raises type error on wrong type' do packer = MessagePack::Packer.new expect { packer.write_float "hello" }.to raise_error(TypeError) expect { packer.write_string 1 }.to raise_error(TypeError) expect { packer.write_bin 1 }.to raise_error(TypeError) expect { packer.write_array "hello" }.to raise_error(TypeError) expect { packer.write_hash "hello" }.to raise_error(TypeError) expect { packer.write_symbol "hello" }.to raise_error(TypeError) expect { packer.write_int "hello" }.to raise_error(TypeError) expect { packer.write_extension "hello" }.to raise_error(TypeError) end class CustomPack01 def to_msgpack(pk=nil) return MessagePack.pack(self, pk) unless pk.class == MessagePack::Packer pk.write_array_header(2) pk.write(1) pk.write(2) return pk end end class CustomPack02 def to_msgpack(pk=nil) [1,2].to_msgpack(pk) end end it 'calls custom to_msgpack method' do MessagePack.pack(CustomPack01.new).should == [1,2].to_msgpack MessagePack.pack(CustomPack02.new).should == [1,2].to_msgpack CustomPack01.new.to_msgpack.should == [1,2].to_msgpack CustomPack02.new.to_msgpack.should == [1,2].to_msgpack end it 'calls custom to_msgpack method with io' do s01 = StringIO.new MessagePack.pack(CustomPack01.new, s01) s01.string.should == [1,2].to_msgpack s02 = StringIO.new MessagePack.pack(CustomPack02.new, s02) s02.string.should == [1,2].to_msgpack s03 = StringIO.new CustomPack01.new.to_msgpack(s03) s03.string.should == [1,2].to_msgpack s04 = StringIO.new CustomPack02.new.to_msgpack(s04) s04.string.should == [1,2].to_msgpack end context 'in compatibility mode' do it 'does not use the bin types' do packed = MessagePack.pack('hello'.force_encoding(Encoding::BINARY), compatibility_mode: true) packed.should eq("\xA5hello") packed = MessagePack.pack(('hello' * 100).force_encoding(Encoding::BINARY), compatibility_mode: true) packed.should start_with("\xDA\x01\xF4") packer = MessagePack::Packer.new(compatibility_mode: 1) packed = packer.pack(('hello' * 100).force_encoding(Encoding::BINARY)) packed.to_str.should start_with("\xDA\x01\xF4") end it 'does not use the str8 type' do packed = MessagePack.pack('x' * 32, compatibility_mode: true) packed.should start_with("\xDA\x00\x20") end end class ValueOne def initialize(num) @num = num end def num @num end def to_msgpack_ext @num.to_msgpack end def self.from_msgpack_ext(data) self.new(MessagePack.unpack(data)) end end class ValueTwo def initialize(num) @num_s = num.to_s end def num @num_s.to_i end def to_msgpack_ext @num_s.to_msgpack end def self.from_msgpack_ext(data) self.new(MessagePack.unpack(data)) end end describe '#type_registered?' do it 'receive Class or Integer, and return bool' do expect(subject.type_registered?(0x00)).to be_falsy expect(subject.type_registered?(0x01)).to be_falsy expect(subject.type_registered?(::ValueOne)).to be_falsy end it 'returns true if specified type or class is already registered' do subject.register_type(0x30, ::ValueOne, :to_msgpack_ext) subject.register_type(0x31, ::ValueTwo, :to_msgpack_ext) expect(subject.type_registered?(0x00)).to be_falsy expect(subject.type_registered?(0x01)).to be_falsy expect(subject.type_registered?(0x30)).to be_truthy expect(subject.type_registered?(0x31)).to be_truthy expect(subject.type_registered?(::ValueOne)).to be_truthy expect(subject.type_registered?(::ValueTwo)).to be_truthy end end describe '#register_type' do it 'get type and class mapping for packing' do packer = MessagePack::Packer.new packer.register_type(0x01, ValueOne){|obj| obj.to_msgpack_ext } packer.register_type(0x02, ValueTwo){|obj| obj.to_msgpack_ext } packer = MessagePack::Packer.new packer.register_type(0x01, ValueOne, :to_msgpack_ext) packer.register_type(0x02, ValueTwo, :to_msgpack_ext) packer = MessagePack::Packer.new packer.register_type(0x01, ValueOne, &:to_msgpack_ext) packer.register_type(0x02, ValueTwo, &:to_msgpack_ext) end it 'returns a Hash which contains map of Class and type' do packer = MessagePack::Packer.new packer.register_type(0x01, ValueOne, :to_msgpack_ext) packer.register_type(0x02, ValueTwo, :to_msgpack_ext) expect(packer.registered_types).to be_a(Array) expect(packer.registered_types.size).to eq(2) one = packer.registered_types[0] expect(one.keys.sort).to eq([:type, :class, :packer].sort) expect(one[:type]).to eq(0x01) expect(one[:class]).to eq(ValueOne) expect(one[:packer]).to eq(:to_msgpack_ext) two = packer.registered_types[1] expect(two.keys.sort).to eq([:type, :class, :packer].sort) expect(two[:type]).to eq(0x02) expect(two[:class]).to eq(ValueTwo) expect(two[:packer]).to eq(:to_msgpack_ext) end context 'when it has no ext type but a super class has' do before { stub_const('Value', Class.new) } before do Value.class_eval do def to_msgpack_ext 'value_msgpacked' end end end before { packer.register_type(0x01, Value, :to_msgpack_ext) } context "when it is a child class" do before { stub_const('InheritedValue', Class.new(Value)) } subject { packer.pack(InheritedValue.new).to_s } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } context "when it is a grandchild class" do before { stub_const('InheritedTwiceValue', Class.new(InheritedValue)) } subject { packer.pack(InheritedTwiceValue.new).to_s } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } end end end context 'when it and its super class has an ext type' do before { stub_const('Value', Class.new) } before do Value.class_eval do def to_msgpack_ext 'value_msgpacked' end end end before { packer.register_type(0x01, Value, :to_msgpack_ext) } context "when it is a child class" do before { stub_const('InheritedValue', Class.new(Value)) } before do InheritedValue.class_eval do def to_msgpack_ext 'inherited_value_msgpacked' end end end before { packer.register_type(0x02, InheritedValue, :to_msgpack_ext) } subject { packer.pack(InheritedValue.new).to_s } it { is_expected.to eq "\xC7\x19\x02inherited_value_msgpacked" } end context "even when it is a child class" do before { stub_const('InheritedValue', Class.new(Value)) } before do InheritedValue.class_eval do def to_msgpack_ext 'inherited_value_msgpacked' end end end before { packer.register_type(0x02, InheritedValue, :to_msgpack_ext) } subject { packer.pack(Value.new).to_s } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } end end context 'when it has no ext type but an included module has' do subject { packer.pack(Value.new).to_s } before do mod = Module.new do def to_msgpack_ext 'value_msgpacked' end end stub_const('Mod', mod) end before { packer.register_type(0x01, Mod, :to_msgpack_ext) } before { stub_const('Value', Class.new{ include Mod }) } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } end context 'when it has no ext type but it was extended by a module which has one' do subject { packer.pack(object).to_s } let(:object) { Object.new.extend Mod } before do mod = Module.new do def to_msgpack_ext 'value_msgpacked' end end stub_const('Mod', mod) end before { packer.register_type(0x01, Mod, :to_msgpack_ext) } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } end context 'when registering a type for symbols' do before { packer.register_type(0x00, ::Symbol, :to_msgpack_ext) } it 'packs symbols in an ext type' do expect(packer.pack(:symbol).to_s).to eq "\xc7\x06\x00symbol" end end end describe "fixnum and bignum" do it "fixnum.to_msgpack" do 23.to_msgpack.should == "\x17" end it "fixnum.to_msgpack(packer)" do 23.to_msgpack(packer) packer.to_s.should == "\x17" end it "bignum.to_msgpack" do -4294967296.to_msgpack.should == "\xD3\xFF\xFF\xFF\xFF\x00\x00\x00\x00" end it "bignum.to_msgpack(packer)" do -4294967296.to_msgpack(packer) packer.to_s.should == "\xD3\xFF\xFF\xFF\xFF\x00\x00\x00\x00" end it "unpack(fixnum)" do MessagePack.unpack("\x17").should == 23 end it "unpack(bignum)" do MessagePack.unpack("\xD3\xFF\xFF\xFF\xFF\x00\x00\x00\x00").should == -4294967296 end end describe "ext formats" do [1, 2, 4, 8, 16].zip([0xd4, 0xd5, 0xd6, 0xd7, 0xd8]).each do |n,b| it "msgpack fixext #{n} format" do MessagePack::ExtensionValue.new(1, "a"*n).to_msgpack.should == [b, 1].pack('CC') + "a"*n end end it "msgpack ext 8 format" do MessagePack::ExtensionValue.new(1, "").to_msgpack.should == [0xc7, 0, 1].pack('CCC') + "" MessagePack::ExtensionValue.new(-1, "a"*255).to_msgpack.should == [0xc7, 255, -1].pack('CCC') + "a"*255 end it "msgpack ext 16 format" do MessagePack::ExtensionValue.new(1, "a"*256).to_msgpack.should == [0xc8, 256, 1].pack('CnC') + "a"*256 MessagePack::ExtensionValue.new(-1, "a"*65535).to_msgpack.should == [0xc8, 65535, -1].pack('CnC') + "a"*65535 end it "msgpack ext 32 format" do MessagePack::ExtensionValue.new(1, "a"*65536).to_msgpack.should == [0xc9, 65536, 1].pack('CNC') + "a"*65536 MessagePack::ExtensionValue.new(-1, "a"*65538).to_msgpack.should == [0xc9, 65538, -1].pack('CNC') + "a"*65538 end end end msgpack-1.4.2/spec/jruby/0000755000004100000410000000000014021120706015251 5ustar www-datawww-datamsgpack-1.4.2/spec/jruby/unpacker_spec.rb0000644000004100000410000001177714021120706020435 0ustar www-datawww-data# encoding: ascii-8bit require 'stringio' require 'tempfile' require 'spec_helper' describe MessagePack::Unpacker do let :unpacker do MessagePack::Unpacker.new end let :packer do MessagePack::Packer.new end let :buffer1 do MessagePack.pack(:foo => 'bar') end let :buffer2 do MessagePack.pack(:hello => {:world => [1, 2, 3]}) end let :buffer3 do MessagePack.pack(:x => 'y') end describe '#execute/#execute_limit/#finished?' do let :buffer do buffer1 + buffer2 + buffer3 end it 'extracts an object from the buffer' do subject.execute(buffer, 0) subject.data.should == {'foo' => 'bar'} end it 'extracts an object from the buffer, starting at an offset' do subject.execute(buffer, buffer1.length) subject.data.should == {'hello' => {'world' => [1, 2, 3]}} end it 'extracts an object from the buffer, starting at an offset reading bytes up to a limit' do subject.execute_limit(buffer, buffer1.length, buffer2.length) subject.data.should == {'hello' => {'world' => [1, 2, 3]}} end it 'extracts nothing if the limit cuts an object in half' do subject.execute_limit(buffer, buffer1.length, 3) subject.data.should be_nil end it 'returns the offset where the object ended' do subject.execute(buffer, 0).should == buffer1.length subject.execute(buffer, buffer1.length).should == buffer1.length + buffer2.length end it 'is finished if #data returns an object' do subject.execute_limit(buffer, buffer1.length, buffer2.length) subject.should be_finished subject.execute_limit(buffer, buffer1.length, 3) subject.should_not be_finished end end describe '#each' do context 'with a StringIO stream' do it 'yields each object in the stream' do objects = [] subject.stream = StringIO.new(buffer1 + buffer2 + buffer3) subject.each do |obj| objects << obj end objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end end context 'with a File stream' do it 'yields each object in the stream' do objects = [] file = Tempfile.new('msgpack') file.write(buffer1) file.write(buffer2) file.write(buffer3) file.open subject.stream = file subject.each do |obj| objects << obj end objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end end end describe '#fill' do it 'is a no-op' do subject.stream = StringIO.new(buffer1 + buffer2 + buffer3) subject.fill subject.each { |obj| } end end def flatten(struct, results = []) case struct when Array struct.each { |v| flatten(v, results) } when Hash struct.each { |k, v| flatten(v, flatten(k, results)) } else results << struct end results end context 'encoding', :encodings do before :all do @default_internal = Encoding.default_internal @default_external = Encoding.default_external end after :all do Encoding.default_internal = @default_internal Encoding.default_external = @default_external end let :buffer do MessagePack.pack({'hello' => 'world', 'nested' => ['object', {"sk\xC3\xA5l".force_encoding('utf-8') => true}]}) end let :unpacker do described_class.new end before do Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::ISO_8859_1 end it 'produces results with encoding as binary or string(utf8)' do unpacker.execute(buffer, 0) strings = flatten(unpacker.data).grep(String) strings.map(&:encoding).uniq.sort{|a,b| a.to_s <=> b.to_s}.should == [Encoding::ASCII_8BIT, Encoding::UTF_8] end it 'recodes to internal encoding' do unpacker.execute(buffer, 0) unpacker.data['nested'][1].keys.should == ["sk\xC3\xA5l".force_encoding(Encoding::UTF_8)] end end context 'extensions' do context 'symbolized keys' do let :buffer do MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]}) end let :unpacker do described_class.new(:symbolize_keys => true) end it 'can symbolize keys when using #execute' do unpacker.execute(buffer, 0) unpacker.data.should == {:hello => 'world', :nested => ['object', {:structure => true}]} end end context 'encoding', :encodings do let :buffer do MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]}) end let :unpacker do described_class.new() end it 'decode binary as ascii-8bit string when using #execute' do unpacker.execute(buffer, 0) strings = flatten(unpacker.data).grep(String) strings.should == %w[hello world nested object structure] strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT] end end end end msgpack-1.4.2/spec/jruby/benchmarks/0000755000004100000410000000000014021120706017366 5ustar www-datawww-datamsgpack-1.4.2/spec/jruby/benchmarks/symbolize_keys_bm.rb0000644000004100000410000000072414021120706023444 0ustar www-datawww-data# encoding: utf-8 $: << File.expand_path('../../../lib', __FILE__) require 'viiite' require 'msgpack' iterations = 10_000 data = MessagePack.pack(:hello => 'world', :nested => ['structure', {:value => 42}]) Viiite.bm do |b| b.report(:strings) do iterations.times do MessagePack.unpack(data) end end b.report(:symbols) do options = {:symbolize_keys => true} iterations.times do MessagePack.unpack(data, options) end end endmsgpack-1.4.2/spec/jruby/benchmarks/shootout_bm.rb0000644000004100000410000000467514021120706022271 0ustar www-datawww-data# encoding: utf-8 if RUBY_PLATFORM.include?('java') # JRuby should use this library, MRI should use the standard gem $: << File.expand_path('../../../lib', __FILE__) end require 'viiite' require 'msgpack' require 'json' require 'bson' if RUBY_PLATFORM.include?('java') BSON_IMPL = BSON::BSON_JAVA else BSON_IMPL = BSON::BSON_C end OBJECT_STRUCTURE = {'x' => ['y', 34, 2**30 + 3, 2.1223423423356, {'hello' => 'world', '5' => [63, 'asjdl']}]} ENCODED_MSGPACK = "\x81\xA1x\x95\xA1y\"\xCE@\x00\x00\x03\xCB@\x00\xFA\x8E\x9F9\xFA\xC1\x82\xA5hello\xA5world\xA15\x92?\xA5asjdl" ENCODED_BSON = "d\x00\x00\x00\x04x\x00\\\x00\x00\x00\x020\x00\x02\x00\x00\x00y\x00\x101\x00\"\x00\x00\x00\x102\x00\x03\x00\x00@\x013\x00\xC1\xFA9\x9F\x8E\xFA\x00@\x034\x002\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x045\x00\x19\x00\x00\x00\x100\x00?\x00\x00\x00\x021\x00\x06\x00\x00\x00asjdl\x00\x00\x00\x00\x00" ENCODED_JSON = '{"x":["y",34,1073741827,2.1223423423356,{"hello":"world","5":[63,"asjdl"]}]}' ITERATIONS = 1_00_000 IMPLEMENTATIONS = ENV.fetch('IMPLEMENTATIONS', 'json,bson,msgpack').split(',').map(&:to_sym) Viiite.bm do |b| b.variation_point :ruby, Viiite.which_ruby IMPLEMENTATIONS.each do |lib| b.variation_point :lib, lib b.report(:pack) do ITERATIONS.times do case lib when :msgpack then MessagePack.pack(OBJECT_STRUCTURE) when :bson then BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s when :json then OBJECT_STRUCTURE.to_json end end end b.report(:unpack) do ITERATIONS.times do case lib when :msgpack then MessagePack.unpack(ENCODED_MSGPACK) when :bson then BSON_IMPL.deserialize(ENCODED_BSON) when :json then JSON.parse(ENCODED_JSON) end end end b.report(:pack_unpack) do ITERATIONS.times do case lib when :msgpack then MessagePack.unpack(MessagePack.pack(OBJECT_STRUCTURE)) when :bson then BSON_IMPL.deserialize(BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s) when :json then JSON.parse(OBJECT_STRUCTURE.to_json) end end end b.report(:unpack_pack) do ITERATIONS.times do case lib when :msgpack then MessagePack.pack(MessagePack.unpack(ENCODED_MSGPACK)) when :bson then BSON_IMPL.serialize(BSON_IMPL.deserialize(ENCODED_BSON)).to_s when :json then OBJECT_STRUCTURE.to_json(JSON.parse(ENCODED_JSON)) end end end end endmsgpack-1.4.2/spec/unpack_spec.rb0000644000004100000410000000434114021120706016740 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' require 'stringio' if defined?(Encoding) Encoding.default_external = 'ASCII-8BIT' end describe MessagePack do it 'MessagePack.unpack symbolize_keys' do symbolized_hash = {:a => 'b', :c => 'd'} MessagePack.load(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash MessagePack.unpack(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash end it 'Unpacker#read symbolize_keys' do unpacker = MessagePack::Unpacker.new(:symbolize_keys => true) symbolized_hash = {:a => 'b', :c => 'd'} unpacker.feed(MessagePack.pack(symbolized_hash)).read.should == symbolized_hash end it "msgpack str 8 type" do MessagePack.unpack([0xd9, 0x00].pack('C*')).should == "" MessagePack.unpack([0xd9, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xd9, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack str 16 type" do MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xda, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xda, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack str 32 type" do MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack bin 8 type" do MessagePack.unpack([0xc4, 0x00].pack('C*')).should == "" MessagePack.unpack([0xc4, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xc4, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack bin 16 type" do MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xc5, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xc5, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack bin 32 type" do MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end end msgpack-1.4.2/spec/ext_value_spec.rb0000644000004100000410000000535614021120706017462 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' describe MessagePack::ExtensionValue do subject do described_class.new(1, "data") end describe '#type/#type=' do it 'returns value set by #initialize' do subject.type.should == 1 end it 'assigns a value' do subject.type = 2 subject.type.should == 2 end end describe '#payload/#payload=' do it 'returns value set by #initialize' do subject.payload.should == "data" end it 'assigns a value' do subject.payload = "a" subject.payload.should == "a" end end describe '#==/#eql?/#hash' do it 'returns equivalent if the content is same' do ext1 = MessagePack::ExtensionValue.new(1, "data") ext2 = MessagePack::ExtensionValue.new(1, "data") (ext1 == ext2).should be true ext1.eql?(ext2).should be true (ext1.hash == ext2.hash).should be true end it 'returns not equivalent if type is not same' do ext1 = MessagePack::ExtensionValue.new(1, "data") ext2 = MessagePack::ExtensionValue.new(2, "data") (ext1 == ext2).should be false ext1.eql?(ext2).should be false (ext1.hash == ext2.hash).should be false end it 'returns not equivalent if payload is not same' do ext1 = MessagePack::ExtensionValue.new(1, "data") ext2 = MessagePack::ExtensionValue.new(1, "value") (ext1 == ext2).should be false ext1.eql?(ext2).should be false (ext1.hash == ext2.hash).should be false end end describe '#to_msgpack' do it 'serializes very short payload' do ext = MessagePack::ExtensionValue.new(1, "a"*2).to_msgpack ext.should == "\xd5\x01" + "a"*2 end it 'serializes short payload' do ext = MessagePack::ExtensionValue.new(1, "a"*18).to_msgpack ext.should == "\xc7\x12\x01" + "a"*18 end it 'serializes long payload' do ext = MessagePack::ExtensionValue.new(1, "a"*65540).to_msgpack ext.should == "\xc9\x00\x01\x00\x04\x01" + "a"*65540 end it 'with a packer serializes to a packer' do ext = MessagePack::ExtensionValue.new(1, "aa") packer = MessagePack::Packer.new ext.to_msgpack(packer) packer.buffer.to_s.should == "\xd5\x01aa" end [-129, -65540, -(2**40), 128, 65540, 2**40].each do |type| context "with invalid type (#{type})" do it 'raises RangeError' do lambda { MessagePack::ExtensionValue.new(type, "a").to_msgpack }.should raise_error(RangeError) end end end end describe '#dup' do it 'duplicates' do ext1 = MessagePack::ExtensionValue.new(1, "data") ext2 = ext1.dup ext2.type = 2 ext2.payload = "data2" ext1.type.should == 1 ext1.payload.should == "data" end end end msgpack-1.4.2/spec/factory_spec.rb0000644000004100000410000002602714021120706017133 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' describe MessagePack::Factory do subject do described_class.new end describe '#packer' do it 'creates a Packer instance' do subject.packer.should be_kind_of(MessagePack::Packer) end it 'creates new instance' do subject.packer.object_id.should_not == subject.packer.object_id end end describe '#unpacker' do it 'creates a Unpacker instance' do subject.unpacker.should be_kind_of(MessagePack::Unpacker) end it 'creates new instance' do subject.unpacker.object_id.should_not == subject.unpacker.object_id end it 'creates unpacker with symbolize_keys option' do unpacker = subject.unpacker(symbolize_keys: true) unpacker.feed(MessagePack.pack({'k'=>'v'})) unpacker.read.should == {:k => 'v'} end it 'creates unpacker with allow_unknown_ext option' do unpacker = subject.unpacker(allow_unknown_ext: true) unpacker.feed(MessagePack::ExtensionValue.new(1, 'a').to_msgpack) unpacker.read.should == MessagePack::ExtensionValue.new(1, 'a') end it 'creates unpacker without allow_unknown_ext option' do unpacker = subject.unpacker unpacker.feed(MessagePack::ExtensionValue.new(1, 'a').to_msgpack) expect{ unpacker.read }.to raise_error(MessagePack::UnknownExtTypeError) end end describe '#dump and #load' do it 'can be used like a standard coder' do subject.register_type(0x00, Symbol) expect(subject.load(subject.dump(:symbol))).to be == :symbol end it 'is alias as pack and unpack' do subject.register_type(0x00, Symbol) expect(subject.unpack(subject.pack(:symbol))).to be == :symbol end it 'accept options' do hash = subject.unpack(MessagePack.pack('k' => 'v'), symbolize_keys: true) expect(hash).to be == { k: 'v' } end end describe '#freeze' do it 'can freeze factory instance to deny new registrations anymore' do subject.register_type(0x00, Symbol) subject.freeze expect(subject.frozen?).to be_truthy expect{ subject.register_type(0x01, Array) }.to raise_error(RuntimeError, "can't modify frozen Factory") end end class MyType def initialize(a, b) @a = a @b = b end attr_reader :a, :b def to_msgpack_ext [a, b].pack('CC') end def self.from_msgpack_ext(data) new(*data.unpack('CC')) end def to_msgpack_ext_only_a [a, 0].pack('CC') end def self.from_msgpack_ext_only_b(data) a, b = *data.unpack('CC') new(0, b) end end class MyType2 < MyType end describe '#registered_types' do it 'returns Array' do expect(subject.registered_types).to be_instance_of(Array) end it 'returns Array of Hash contains :type, :class, :packer, :unpacker' do subject.register_type(0x20, ::MyType) subject.register_type(0x21, ::MyType2) list = subject.registered_types expect(list.size).to eq(2) expect(list[0]).to be_instance_of(Hash) expect(list[1]).to be_instance_of(Hash) expect(list[0].keys.sort).to eq([:type, :class, :packer, :unpacker].sort) expect(list[1].keys.sort).to eq([:type, :class, :packer, :unpacker].sort) expect(list[0][:type]).to eq(0x20) expect(list[0][:class]).to eq(::MyType) expect(list[0][:packer]).to eq(:to_msgpack_ext) expect(list[0][:unpacker]).to eq(:from_msgpack_ext) expect(list[1][:type]).to eq(0x21) expect(list[1][:class]).to eq(::MyType2) expect(list[1][:packer]).to eq(:to_msgpack_ext) expect(list[1][:unpacker]).to eq(:from_msgpack_ext) end it 'returns Array of Hash which has nil for unregistered feature' do subject.register_type(0x21, ::MyType2, unpacker: :from_msgpack_ext) subject.register_type(0x20, ::MyType, packer: :to_msgpack_ext) list = subject.registered_types expect(list.size).to eq(2) expect(list[0]).to be_instance_of(Hash) expect(list[1]).to be_instance_of(Hash) expect(list[0].keys.sort).to eq([:type, :class, :packer, :unpacker].sort) expect(list[1].keys.sort).to eq([:type, :class, :packer, :unpacker].sort) expect(list[0][:type]).to eq(0x20) expect(list[0][:class]).to eq(::MyType) expect(list[0][:packer]).to eq(:to_msgpack_ext) expect(list[0][:unpacker]).to be_nil expect(list[1][:type]).to eq(0x21) expect(list[1][:class]).to eq(::MyType2) expect(list[1][:packer]).to be_nil expect(list[1][:unpacker]).to eq(:from_msgpack_ext) end end describe '#type_registered?' do it 'receive Class or Integer, and return bool' do expect(subject.type_registered?(0x00)).to be_falsy expect(subject.type_registered?(0x01)).to be_falsy expect(subject.type_registered?(::MyType)).to be_falsy end it 'has option to specify what types are registered for' do expect(subject.type_registered?(0x00, :both)).to be_falsy expect(subject.type_registered?(0x00, :packer)).to be_falsy expect(subject.type_registered?(0x00, :unpacker)).to be_falsy expect{ subject.type_registered?(0x00, :something) }.to raise_error(ArgumentError) end it 'returns true if specified type or class is already registered' do subject.register_type(0x20, ::MyType) subject.register_type(0x21, ::MyType2) expect(subject.type_registered?(0x00)).to be_falsy expect(subject.type_registered?(0x01)).to be_falsy expect(subject.type_registered?(0x20)).to be_truthy expect(subject.type_registered?(0x21)).to be_truthy expect(subject.type_registered?(::MyType)).to be_truthy expect(subject.type_registered?(::MyType2)).to be_truthy end end describe '#register_type' do let :src do ::MyType.new(1, 2) end it 'registers #to_msgpack_ext and .from_msgpack_ext by default' do subject.register_type(0x7f, ::MyType) data = subject.packer.write(src).to_s my = subject.unpacker.feed(data).read my.a.should == 1 my.b.should == 2 end it 'registers custom packer method name' do subject.register_type(0x7f, ::MyType, packer: :to_msgpack_ext_only_a, unpacker: :from_msgpack_ext) data = subject.packer.write(src).to_s my = subject.unpacker.feed(data).read my.a.should == 1 my.b.should == 0 end it 'registers custom unpacker method name' do subject.register_type(0x7f, ::MyType, packer: :to_msgpack_ext, unpacker: 'from_msgpack_ext_only_b') data = subject.packer.write(src).to_s my = subject.unpacker.feed(data).read my.a.should == 0 my.b.should == 2 end it 'registers custom proc objects' do pk = lambda {|obj| [obj.a + obj.b].pack('C') } uk = lambda {|data| ::MyType.new(data.unpack('C').first, -1) } subject.register_type(0x7f, ::MyType, packer: pk, unpacker: uk) data = subject.packer.write(src).to_s my = subject.unpacker.feed(data).read my.a.should == 3 my.b.should == -1 end it 'does not affect existent packer and unpackers' do subject.register_type(0x7f, ::MyType) packer = subject.packer unpacker = subject.unpacker subject.register_type(0x7f, ::MyType, packer: :to_msgpack_ext_only_a, unpacker: :from_msgpack_ext_only_b) data = packer.write(src).to_s my = unpacker.feed(data).read my.a.should == 1 my.b.should == 2 end describe "registering an ext type for a module" do before do mod = Module.new do def self.from_msgpack_ext(data) "unpacked #{data}" end def to_msgpack_ext 'value_msgpacked' end end stub_const('Mod', mod) end let(:factory) { described_class.new } before { factory.register_type(0x01, Mod) } describe "packing an object whose class included the module" do subject { factory.packer.pack(value).to_s } before { stub_const('Value', Class.new{ include Mod }) } let(:value) { Value.new } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } end describe "packing an object which has been extended by the module" do subject { factory.packer.pack(object).to_s } let(:object) { Object.new.extend Mod } it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" } end describe "unpacking with the module" do subject { factory.unpacker.feed("\xC7\x06\x01module").unpack } it { is_expected.to eq "unpacked module" } end end end describe 'the special treatment of symbols with ext type' do let(:packer) { subject.packer } let(:unpacker) { subject.unpacker } def symbol_after_roundtrip packed_symbol = packer.pack(:symbol).to_s unpacker.feed(packed_symbol).unpack end context 'if no ext type is registered for symbols' do it 'converts symbols to string' do expect(symbol_after_roundtrip).to eq 'symbol' end end context 'if an ext type is registered for symbols' do context 'if using the default serializer' do before { subject.register_type(0x00, ::Symbol) } it 'lets symbols survive a roundtrip' do expect(symbol_after_roundtrip).to be :symbol end end context 'if using a custom serializer' do before do class Symbol alias_method :to_msgpack_ext_orig, :to_msgpack_ext def to_msgpack_ext self.to_s.codepoints.to_a.pack('n*') end end class << Symbol alias_method :from_msgpack_ext_orig, :from_msgpack_ext def from_msgpack_ext(data) data.unpack('n*').map(&:chr).join.to_sym end end end before { subject.register_type(0x00, ::Symbol) } it 'lets symbols survive a roundtrip' do expect(symbol_after_roundtrip).to be :symbol end after do class Symbol alias_method :to_msgpack_ext, :to_msgpack_ext_orig end class << Symbol alias_method :from_msgpack_ext, :from_msgpack_ext_orig end end end end end describe 'under stressful GC' do it 'works well' do begin GC.stress = true f = MessagePack::Factory.new f.register_type(0x0a, Symbol) ensure GC.stress = false end end end describe 'DefaultFactory' do it 'is a factory' do MessagePack::DefaultFactory.should be_kind_of(MessagePack::Factory) end require_relative 'exttypes' it 'should be referred by MessagePack.pack and MessagePack.unpack' do MessagePack::DefaultFactory.register_type(DummyTimeStamp1::TYPE, DummyTimeStamp1) MessagePack::DefaultFactory.register_type(DummyTimeStamp2::TYPE, DummyTimeStamp2, packer: :serialize, unpacker: :deserialize) t = Time.now dm1 = DummyTimeStamp1.new(t.to_i, t.usec) expect(MessagePack.unpack(MessagePack.pack(dm1))).to eq(dm1) dm2 = DummyTimeStamp1.new(t.to_i, t.usec) expect(MessagePack.unpack(MessagePack.pack(dm2))).to eq(dm2) end end end msgpack-1.4.2/spec/timestamp_spec.rb0000644000004100000410000000706614021120706017471 0ustar www-datawww-data# frozen_string_literal: true require 'spec_helper' describe MessagePack::Timestamp do describe 'malformed format' do it do expect do MessagePack::Timestamp.from_msgpack_ext([0xd4, 0x00].pack("C*")) end.to raise_error(MessagePack::MalformedFormatError) end end describe 'register_type with Time' do let(:factory) do factory = MessagePack::Factory.new factory.register_type( MessagePack::Timestamp::TYPE, Time, packer: MessagePack::Time::Packer, unpacker: MessagePack::Time::Unpacker ) factory end let(:time) { Time.local(2019, 6, 17, 1, 2, 3, 123_456_789 / 1000.0) } it 'serializes and deserializes Time' do prefix_fixext8_with_type_id = [0xd7, -1].pack("c*") packed = factory.pack(time) expect(packed).to start_with(prefix_fixext8_with_type_id) expect(packed.size).to eq(10) unpacked = factory.unpack(packed) expect(unpacked.to_i).to eq(time.to_i) expect(unpacked.to_f).to eq(time.to_f) # expect(unpacked).to eq(time) # we can't do it because of nsec (rational vs float?) end let(:time_without_nsec) { Time.local(2019, 6, 17, 1, 2, 3, 0) } it 'serializes time without nanosec as fixext4' do prefix_fixext4_with_type_id = [0xd6, -1].pack("c*") packed = factory.pack(time_without_nsec) expect(packed).to start_with(prefix_fixext4_with_type_id) expect(packed.size).to eq(6) unpacked = factory.unpack(packed) expect(unpacked).to eq(time_without_nsec) end let(:time_after_2514) { Time.at(1 << 34) } # the max num of 34bit int means 2514-05-30 01:53:04 UTC it 'serializes time after 2038 as ext8' do prefix_ext8_with_12bytes_payload_and_type_id = [0xc7, 12, -1].pack("c*") expect(time_after_2514.to_i).to be > 0xffffffff packed = factory.pack(time_after_2514) expect(packed).to start_with(prefix_ext8_with_12bytes_payload_and_type_id) expect(packed.size).to eq(15) end it 'runs correctly (regression)' do expect(factory.unpack(factory.pack(Time.utc(2200)))).to eq(Time.utc(2200)) end end describe 'register_type with MessagePack::Timestamp' do let(:factory) do factory = MessagePack::Factory.new factory.register_type(MessagePack::Timestamp::TYPE, MessagePack::Timestamp) factory end let(:timestamp) { MessagePack::Timestamp.new(Time.now.tv_sec, 123_456_789) } it 'serializes and deserializes MessagePack::Timestamp' do packed = factory.pack(timestamp) unpacked = factory.unpack(packed) expect(unpacked).to eq(timestamp) end end describe 'timestamp32' do it 'handles [1, 0]' do t = MessagePack::Timestamp.new(1, 0) payload = t.to_msgpack_ext unpacked = MessagePack::Timestamp.from_msgpack_ext(payload) expect(unpacked).to eq(t) end end describe 'timestamp64' do it 'handles [1, 1]' do t = MessagePack::Timestamp.new(1, 1) payload = t.to_msgpack_ext unpacked = MessagePack::Timestamp.from_msgpack_ext(payload) expect(unpacked).to eq(t) end end describe 'timestamp96' do it 'handles [-1, 0]' do t = MessagePack::Timestamp.new(-1, 0) payload = t.to_msgpack_ext unpacked = MessagePack::Timestamp.from_msgpack_ext(payload) expect(unpacked).to eq(t) end it 'handles [-1, 999_999_999]' do t = MessagePack::Timestamp.new(-1, 999_999_999) payload = t.to_msgpack_ext unpacked = MessagePack::Timestamp.from_msgpack_ext(payload) expect(unpacked).to eq(t) end end end msgpack-1.4.2/spec/unpacker_spec.rb0000644000004100000410000006017714021120706017300 0ustar www-datawww-data# encoding: ascii-8bit require 'stringio' require 'tempfile' require 'zlib' require 'spec_helper' describe MessagePack::Unpacker do let :unpacker do MessagePack::Unpacker.new end let :packer do MessagePack::Packer.new end it 'gets options to specify how to unpack values' do u1 = MessagePack::Unpacker.new u1.symbolize_keys?.should == false u1.freeze?.should == false u1.allow_unknown_ext?.should == false u2 = MessagePack::Unpacker.new(symbolize_keys: true, freeze: true, allow_unknown_ext: true) u2.symbolize_keys?.should == true u2.freeze?.should == true u2.allow_unknown_ext?.should == true end if automatic_string_keys_deduplication? it 'ensure string hash keys are deduplicated' do sample_data = [{"foo" => 1}, {"foo" => 2}] sample_packed = MessagePack.pack(sample_data).force_encoding('ASCII-8BIT') unpacker.feed(sample_packed) hashes = nil unpacker.each { |obj| hashes = obj } expect(hashes[0].keys.first).to equal(hashes[1].keys.first) end end it 'gets IO or object which has #read to read data from it' do sample_data = {"message" => "morning!", "num" => 1} sample_packed = MessagePack.pack(sample_data).force_encoding('ASCII-8BIT') Tempfile.open("for_io") do |file| file.sync = true file.write sample_packed file.rewind u1 = MessagePack::Unpacker.new(file) u1.each do |obj| expect(obj).to eql(sample_data) end file.unlink end sio = StringIO.new(sample_packed) u2 = MessagePack::Unpacker.new(sio) u2.each do |obj| expect(obj).to eql(sample_data) end dio = StringIO.new Zlib::GzipWriter.wrap(dio){|gz| gz.write sample_packed } reader = Zlib::GzipReader.new(StringIO.new(dio.string)) u3 = MessagePack::Unpacker.new(reader) u3.each do |obj| expect(obj).to eql(sample_data) end class DummyIO def initialize @buf = "".force_encoding('ASCII-8BIT') @pos = 0 end def write(val) @buf << val.to_s end def read(length=nil,outbuf="") if @pos == @buf.size nil elsif length.nil? val = @buf[@pos..(@buf.size)] @pos = @buf.size outbuf << val outbuf else val = @buf[@pos..(@pos + length)] @pos += val.size @pos = @buf.size if @pos > @buf.size outbuf << val outbuf end end def flush # nop end end dio = DummyIO.new dio.write sample_packed u4 = MessagePack::Unpacker.new(dio) u4.each do |obj| expect(obj).to eql(sample_data) end end it 'read_array_header succeeds' do unpacker.feed("\x91") unpacker.read_array_header.should == 1 end it 'read_array_header fails' do unpacker.feed("\x81") lambda { unpacker.read_array_header }.should raise_error(MessagePack::TypeError) # TypeError is included in UnexpectedTypeError lambda { unpacker.read_array_header }.should raise_error(MessagePack::UnexpectedTypeError) end it 'read_map_header converts an map to key-value sequence' do packer.write_array_header(2) packer.write("e") packer.write(1) unpacker = MessagePack::Unpacker.new unpacker.feed(packer.to_s) unpacker.read_array_header.should == 2 unpacker.read.should == "e" unpacker.read.should == 1 end it 'read_map_header succeeds' do unpacker.feed("\x81") unpacker.read_map_header.should == 1 end it 'read_map_header converts an map to key-value sequence' do packer.write_map_header(1) packer.write("k") packer.write("v") unpacker = MessagePack::Unpacker.new unpacker.feed(packer.to_s) unpacker.read_map_header.should == 1 unpacker.read.should == "k" unpacker.read.should == "v" end it 'read_map_header fails' do unpacker.feed("\x91") lambda { unpacker.read_map_header }.should raise_error(MessagePack::TypeError) # TypeError is included in UnexpectedTypeError lambda { unpacker.read_map_header }.should raise_error(MessagePack::UnexpectedTypeError) end it 'read raises EOFError before feeding' do lambda { unpacker.read }.should raise_error(EOFError) end let :sample_object do [1024, {["a","b"]=>["c","d"]}, ["e","f"], "d", 70000, 4.12, 1.5, 1.5, 1.5] end it 'feed and each continue internal state' do raw = sample_object.to_msgpack.to_s * 4 objects = [] raw.split(//).each do |b| unpacker.feed(b) unpacker.each {|c| objects << c } end objects.should == [sample_object] * 4 end it 'feed_each continues internal state' do raw = sample_object.to_msgpack.to_s * 4 objects = [] raw.split(//).each do |b| unpacker.feed_each(b) {|c| objects << c } end objects.should == [sample_object] * 4 end it 'feed_each enumerator' do raw = sample_object.to_msgpack.to_s * 4 enum = unpacker.feed_each(raw) enum.should be_instance_of(Enumerator) enum.to_a.should == [sample_object] * 4 end it 'reset clears internal buffer' do # 1-element array unpacker.feed("\x91") unpacker.reset unpacker.feed("\x01") unpacker.each.map {|x| x }.should == [1] end it 'reset clears internal state' do # 1-element array unpacker.feed("\x91") unpacker.each.map {|x| x }.should == [] unpacker.reset unpacker.feed("\x01") unpacker.each.map {|x| x }.should == [1] end it 'frozen short strings' do raw = sample_object.to_msgpack.to_s.force_encoding('UTF-8') lambda { unpacker.feed_each(raw.freeze) { } }.should_not raise_error end it 'frozen long strings' do raw = (sample_object.to_msgpack.to_s * 10240).force_encoding('UTF-8') lambda { unpacker.feed_each(raw.freeze) { } }.should_not raise_error end it 'read raises invalid byte error' do unpacker.feed("\xc1") lambda { unpacker.read }.should raise_error(MessagePack::MalformedFormatError) end it "gc mark" do raw = sample_object.to_msgpack.to_s * 4 n = 0 raw.split(//).each do |b| GC.start unpacker.feed_each(b) {|o| GC.start o.should == sample_object n += 1 } GC.start end n.should == 4 end it "buffer" do orig = "a"*32*1024*4 raw = orig.to_msgpack.to_s n = 655 times = raw.size / n times += 1 unless raw.size % n == 0 off = 0 parsed = false times.times do parsed.should == false seg = raw[off, n] off += seg.length unpacker.feed_each(seg) {|obj| parsed.should == false obj.should == orig parsed = true } end parsed.should == true end it 'MessagePack.unpack symbolize_keys' do symbolized_hash = {:a => 'b', :c => 'd'} MessagePack.load(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash MessagePack.unpack(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash end it 'Unpacker#unpack symbolize_keys' do unpacker = MessagePack::Unpacker.new(:symbolize_keys => true) symbolized_hash = {:a => 'b', :c => 'd'} unpacker.feed(MessagePack.pack(symbolized_hash)).read.should == symbolized_hash end it "msgpack str 8 type" do MessagePack.unpack([0xd9, 0x00].pack('C*')).should == "" MessagePack.unpack([0xd9, 0x00].pack('C*')).encoding.should == Encoding::UTF_8 MessagePack.unpack([0xd9, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xd9, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack str 16 type" do MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).encoding.should == Encoding::UTF_8 MessagePack.unpack([0xda, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xda, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack str 32 type" do MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).encoding.should == Encoding::UTF_8 MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack bin 8 type" do MessagePack.unpack([0xc4, 0x00].pack('C*')).should == "" MessagePack.unpack([0xc4, 0x00].pack('C*')).encoding.should == Encoding::ASCII_8BIT MessagePack.unpack([0xc4, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xc4, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack bin 16 type" do MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).encoding.should == Encoding::ASCII_8BIT MessagePack.unpack([0xc5, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xc5, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end it "msgpack bin 32 type" do MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == "" MessagePack.unpack([0xc6, 0x0, 0x00, 0x00, 0x000].pack('C*')).encoding.should == Encoding::ASCII_8BIT MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a" MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa" end describe "ext formats" do let(:unpacker) { MessagePack::Unpacker.new(allow_unknown_ext: true) } [1, 2, 4, 8, 16].zip([0xd4, 0xd5, 0xd6, 0xd7, 0xd8]).each do |n,b| it "msgpack fixext #{n} format" do unpacker.feed([b, 1].pack('CC') + "a"*n).unpack.should == MessagePack::ExtensionValue.new(1, "a"*n) unpacker.feed([b, -1].pack('CC') + "a"*n).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*n) end end it "msgpack ext 8 format" do unpacker.feed([0xc7, 0, 1].pack('CCC')).unpack.should == MessagePack::ExtensionValue.new(1, "") unpacker.feed([0xc7, 255, -1].pack('CCC') + "a"*255).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*255) end it "msgpack ext 16 format" do unpacker.feed([0xc8, 0, 1].pack('CnC')).unpack.should == MessagePack::ExtensionValue.new(1, "") unpacker.feed([0xc8, 256, -1].pack('CnC') + "a"*256).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*256) end it "msgpack ext 32 format" do unpacker.feed([0xc9, 0, 1].pack('CNC')).unpack.should == MessagePack::ExtensionValue.new(1, "") unpacker.feed([0xc9, 256, -1].pack('CNC') + "a"*256).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*256) unpacker.feed([0xc9, 65536, -1].pack('CNC') + "a"*65536).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*65536) end end class ValueOne attr_reader :num def initialize(num) @num = num end def ==(obj) self.num == obj.num end def num @num end def to_msgpack_ext @num.to_msgpack end def self.from_msgpack_ext(data) self.new(MessagePack.unpack(data)) end end class ValueTwo attr_reader :num_s def initialize(num) @num_s = num.to_s end def ==(obj) self.num_s == obj.num_s end def num @num_s.to_i end def to_msgpack_ext @num_s.to_msgpack end def self.from_msgpack_ext(data) self.new(MessagePack.unpack(data)) end end describe '#type_registered?' do it 'receive Class or Integer, and return bool' do expect(subject.type_registered?(0x00)).to be_falsy expect(subject.type_registered?(0x01)).to be_falsy expect(subject.type_registered?(::ValueOne)).to be_falsy end it 'returns true if specified type or class is already registered' do subject.register_type(0x30, ::ValueOne, :from_msgpack_ext) subject.register_type(0x31, ::ValueTwo, :from_msgpack_ext) expect(subject.type_registered?(0x00)).to be_falsy expect(subject.type_registered?(0x01)).to be_falsy expect(subject.type_registered?(0x30)).to be_truthy expect(subject.type_registered?(0x31)).to be_truthy expect(subject.type_registered?(::ValueOne)).to be_truthy expect(subject.type_registered?(::ValueTwo)).to be_truthy end it 'cannot detect unpack rule with block, not method' do subject.register_type(0x40){|data| ValueOne.from_msgpack_ext(data) } expect(subject.type_registered?(0x40)).to be_truthy expect(subject.type_registered?(ValueOne)).to be_falsy end end context 'with ext definitions' do it 'get type and class mapping for packing' do unpacker = MessagePack::Unpacker.new unpacker.register_type(0x01){|data| ValueOne.from_msgpack_ext } unpacker.register_type(0x02){|data| ValueTwo.from_msgpack_ext(data) } unpacker = MessagePack::Unpacker.new unpacker.register_type(0x01, ValueOne, :from_msgpack_ext) unpacker.register_type(0x02, ValueTwo, :from_msgpack_ext) end it 'returns a Array of Hash which contains :type, :class and :unpacker' do unpacker = MessagePack::Unpacker.new unpacker.register_type(0x02, ValueTwo, :from_msgpack_ext) unpacker.register_type(0x01, ValueOne, :from_msgpack_ext) list = unpacker.registered_types expect(list).to be_a(Array) expect(list.size).to eq(2) one = list[0] expect(one.keys.sort).to eq([:type, :class, :unpacker].sort) expect(one[:type]).to eq(0x01) expect(one[:class]).to eq(ValueOne) expect(one[:unpacker]).to eq(:from_msgpack_ext) two = list[1] expect(two.keys.sort).to eq([:type, :class, :unpacker].sort) expect(two[:type]).to eq(0x02) expect(two[:class]).to eq(ValueTwo) expect(two[:unpacker]).to eq(:from_msgpack_ext) end it 'returns a Array of Hash, which contains nil for class if block unpacker specified' do unpacker = MessagePack::Unpacker.new unpacker.register_type(0x01){|data| ValueOne.from_msgpack_ext } unpacker.register_type(0x02, &ValueTwo.method(:from_msgpack_ext)) list = unpacker.registered_types expect(list).to be_a(Array) expect(list.size).to eq(2) one = list[0] expect(one.keys.sort).to eq([:type, :class, :unpacker].sort) expect(one[:type]).to eq(0x01) expect(one[:class]).to be_nil expect(one[:unpacker]).to be_instance_of(Proc) two = list[1] expect(two.keys.sort).to eq([:type, :class, :unpacker].sort) expect(two[:type]).to eq(0x02) expect(two[:class]).to be_nil expect(two[:unpacker]).to be_instance_of(Proc) end describe "registering an ext type for a module" do subject { unpacker.feed("\xc7\x06\x00module").unpack } let(:unpacker) { MessagePack::Unpacker.new } before do mod = Module.new do def self.from_msgpack_ext(data) "unpacked #{data}" end end stub_const('Mod', mod) end before { unpacker.register_type(0x00, Mod, :from_msgpack_ext) } it { is_expected.to eq "unpacked module" } end end def flatten(struct, results = []) case struct when Array struct.each { |v| flatten(v, results) } when Hash struct.each { |k, v| flatten(v, flatten(k, results)) } else results << struct end results end subject do described_class.new end let :buffer1 do MessagePack.pack(:foo => 'bar') end let :buffer2 do MessagePack.pack(:hello => {:world => [1, 2, 3]}) end let :buffer3 do MessagePack.pack(:x => 'y') end describe '#read' do context 'with a buffer' do it 'reads objects' do objects = [] subject.feed(buffer1) subject.feed(buffer2) subject.feed(buffer3) objects << subject.read objects << subject.read objects << subject.read objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end it 'reads map header' do subject.feed({}.to_msgpack) subject.read_map_header.should == 0 end it 'reads array header' do subject.feed([].to_msgpack) subject.read_array_header.should == 0 end end end describe '#each' do context 'with a buffer' do it 'yields each object in the buffer' do objects = [] subject.feed(buffer1) subject.feed(buffer2) subject.feed(buffer3) subject.each do |obj| objects << obj end objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end it 'returns an enumerator when no block is given' do subject.feed(buffer1) subject.feed(buffer2) subject.feed(buffer3) enum = subject.each enum.map { |obj| obj.keys.first }.should == %w[foo hello x] end end context 'with a stream passed to the constructor' do it 'yields each object in the stream' do objects = [] unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3)) unpacker.each do |obj| objects << obj end objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end end context 'with a stream and symbolize_keys passed to the constructor' do it 'yields each object in the stream, with symbolized keys' do objects = [] unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3), symbolize_keys: true) unpacker.each do |obj| objects << obj end objects.should == [{:foo => 'bar'}, {:hello => {:world => [1, 2, 3]}}, {:x => 'y'}] end end end describe '#feed_each' do it 'feeds the buffer then runs #each' do objects = [] subject.feed_each(buffer1 + buffer2 + buffer3) do |obj| objects << obj end objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end it 'handles chunked data' do objects = [] buffer = buffer1 + buffer2 + buffer3 buffer.chars.each do |ch| subject.feed_each(ch) do |obj| objects << obj end end objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}] end end context 'regressions' do it 'handles massive arrays (issue #2)' do array = ['foo'] * 10_000 MessagePack.unpack(MessagePack.pack(array)).size.should == 10_000 end it 'preserve string encoding (issue #200)' do string = 'a'.force_encoding(Encoding::UTF_8) MessagePack.unpack(MessagePack.pack(string)).encoding.should == string.encoding string *= 256 MessagePack.unpack(MessagePack.pack(string)).encoding.should == string.encoding end end context 'extensions' do context 'symbolized keys' do let :buffer do MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]}) end let :unpacker do described_class.new(:symbolize_keys => true) end it 'can symbolize keys when using #each' do objs = [] unpacker.feed(buffer) unpacker.each do |obj| objs << obj end objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}] end it 'can symbolize keys when using #feed_each' do objs = [] unpacker.feed_each(buffer) do |obj| objs << obj end objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}] end end context 'freeze' do let :struct do {'hello' => 'world', 'nested' => ['object', {'structure' => true}]} end let :buffer do MessagePack.pack(struct) end let :unpacker do described_class.new(:freeze => true) end it 'can freeze objects when using .unpack' do parsed_struct = MessagePack.unpack(buffer, freeze: true) parsed_struct.should == struct parsed_struct.should be_frozen parsed_struct['hello'].should be_frozen parsed_struct['nested'].should be_frozen parsed_struct['nested'][0].should be_frozen parsed_struct['nested'][1].should be_frozen if string_deduplication? parsed_struct.keys[0].should be_equal('hello'.freeze) parsed_struct.keys[1].should be_equal('nested'.freeze) parsed_struct.values[0].should be_equal('world'.freeze) parsed_struct.values[1][0].should be_equal('object'.freeze) parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze) end end it 'can freeze objects when using #each' do objs = [] unpacker.feed(buffer) unpacker.each do |obj| objs << obj end parsed_struct = objs.first parsed_struct.should == struct parsed_struct.should be_frozen parsed_struct['hello'].should be_frozen parsed_struct['nested'].should be_frozen parsed_struct['nested'][0].should be_frozen parsed_struct['nested'][1].should be_frozen if string_deduplication? parsed_struct.keys[0].should be_equal('hello'.freeze) parsed_struct.keys[1].should be_equal('nested'.freeze) parsed_struct.values[0].should be_equal('world'.freeze) parsed_struct.values[1][0].should be_equal('object'.freeze) parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze) end end it 'can freeze objects when using #feed_each' do objs = [] unpacker.feed_each(buffer) do |obj| objs << obj end parsed_struct = objs.first parsed_struct.should == struct parsed_struct.should be_frozen parsed_struct['hello'].should be_frozen parsed_struct['nested'].should be_frozen parsed_struct['nested'][0].should be_frozen parsed_struct['nested'][1].should be_frozen if string_deduplication? parsed_struct.keys[0].should be_equal('hello'.freeze) parsed_struct.keys[1].should be_equal('nested'.freeze) parsed_struct.values[0].should be_equal('world'.freeze) parsed_struct.values[1][0].should be_equal('object'.freeze) parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze) end end end context 'binary encoding', :encodings do let :buffer do MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]}) end let :unpacker do described_class.new() end it 'decodes binary as ascii-8bit when using #feed' do objs = [] unpacker.feed(buffer) unpacker.each do |obj| objs << obj end strings = flatten(objs).grep(String) strings.should == %w[hello world nested object structure] strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT] end it 'decodes binary as ascii-8bit when using #feed_each' do objs = [] unpacker.feed_each(buffer) do |obj| objs << obj end strings = flatten(objs).grep(String) strings.should == %w[hello world nested object structure] strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT] end end context 'string encoding', :encodings do let :buffer do MessagePack.pack({'hello'.force_encoding(Encoding::UTF_8) => 'world'.force_encoding(Encoding::UTF_8), 'nested'.force_encoding(Encoding::UTF_8) => ['object'.force_encoding(Encoding::UTF_8), {'structure'.force_encoding(Encoding::UTF_8) => true}]}) end let :unpacker do described_class.new() end it 'decodes string as utf-8 when using #feed' do objs = [] unpacker.feed(buffer) unpacker.each do |obj| objs << obj end strings = flatten(objs).grep(String) strings.should == %w[hello world nested object structure] strings.map(&:encoding).uniq.should == [Encoding::UTF_8] end it 'decodes binary as ascii-8bit when using #feed_each' do objs = [] unpacker.feed_each(buffer) do |obj| objs << obj end strings = flatten(objs).grep(String) strings.should == %w[hello world nested object structure] strings.map(&:encoding).uniq.should == [Encoding::UTF_8] end end end end msgpack-1.4.2/spec/pack_spec.rb0000644000004100000410000000315614021120706016400 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' require 'stringio' if defined?(Encoding) Encoding.default_external = 'ASCII-8BIT' end describe MessagePack do it 'to_msgpack returns String' do nil.to_msgpack.class.should == String true.to_msgpack.class.should == String false.to_msgpack.class.should == String 1.to_msgpack.class.should == String 1.0.to_msgpack.class.should == String "".to_msgpack.class.should == String Hash.new.to_msgpack.class.should == String Array.new.to_msgpack.class.should == String end class CustomPack01 def to_msgpack(pk=nil) return MessagePack.pack(self, pk) unless pk.class == MessagePack::Packer pk.write_array_header(2) pk.write(1) pk.write(2) return pk end end class CustomPack02 def to_msgpack(pk=nil) [1,2].to_msgpack(pk) end end it 'calls custom to_msgpack method' do MessagePack.pack(CustomPack01.new).should == [1,2].to_msgpack MessagePack.pack(CustomPack02.new).should == [1,2].to_msgpack CustomPack01.new.to_msgpack.should == [1,2].to_msgpack CustomPack02.new.to_msgpack.should == [1,2].to_msgpack end it 'calls custom to_msgpack method with io' do s01 = StringIO.new MessagePack.pack(CustomPack01.new, s01) s01.string.should == [1,2].to_msgpack s02 = StringIO.new MessagePack.pack(CustomPack02.new, s02) s02.string.should == [1,2].to_msgpack s03 = StringIO.new CustomPack01.new.to_msgpack(s03) s03.string.should == [1,2].to_msgpack s04 = StringIO.new CustomPack02.new.to_msgpack(s04) s04.string.should == [1,2].to_msgpack end end msgpack-1.4.2/spec/format_spec.rb0000644000004100000410000001312114021120706016743 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' describe MessagePack do it "nil" do check 1, nil end it "true" do check 1, true end it "false" do check 1, false end it "zero" do check 1, 0 end it "positive fixnum" do check 1, 1 check 1, (1 << 6) check 1, (1 << 7)-1 end it "positive int 8" do check 1, -1 check 2, (1 << 7) check 2, (1 << 8) - 1 end it "positive int 16" do check 3, (1 << 8) check 3, (1 << 16) - 1 end it "positive int 32" do check 5, (1 << 16) check 5, (1 << 32) - 1 end it "positive int 64" do check 9, (1 << 32) #check 9, (1<<64)-1 end it "negative fixnum" do check 1, -1 check 1, -((1 << 5)-1) check 1, -(1 << 5) end it "negative int 8" do check 2, -((1 << 5)+1) check 2, -(1 << 7) end it "negative int 16" do check 3, -((1 << 7)+1) check 3, -(1 << 15) end it "negative int 32" do check 5, -((1 << 15)+1) check 5, -(1 << 31) end it "negative int 64" do check 9, -((1 << 31)+1) check 9, -(1 << 63) end it "double" do check 9, 1.0 check 9, 0.1 check 9, -0.1 check 9, -1.0 end it "fixraw" do check_raw 1, 0 check_raw 1, (1 << 5)-1 end it "raw 8" do check_raw 2, (1 << 5) check_raw 2, (1 << 8)-1 end it "raw 16" do check_raw 3, (1 << 8) check_raw 3, (1 << 16)-1 end it "raw 32" do check_raw 5, (1 << 16) #check_raw 5, (1 << 32)-1 # memory error end it "str encoding is UTF_8" do v = pack_unpack('string'.force_encoding(Encoding::UTF_8)) v.encoding.should == Encoding::UTF_8 end it "str transcode US-ASCII" do v = pack_unpack('string'.force_encoding(Encoding::US_ASCII)) v.encoding.should == Encoding::UTF_8 end it "str transcode UTF-16" do v = pack_unpack('string'.encode(Encoding::UTF_16)) v.encoding.should == Encoding::UTF_8 v.should == 'string' end it "str transcode EUC-JP 7bit safe" do v = pack_unpack('string'.force_encoding(Encoding::EUC_JP)) v.encoding.should == Encoding::UTF_8 v.should == 'string' end it "str transcode EUC-JP 7bit unsafe" do v = pack_unpack([0xa4, 0xa2].pack('C*').force_encoding(Encoding::EUC_JP)) v.encoding.should == Encoding::UTF_8 v.should == "\xE3\x81\x82".force_encoding('UTF-8') end it "symbol to str" do v = pack_unpack(:a) v.should == "a".force_encoding('UTF-8') end it "symbol to str with encoding" do a = "\xE3\x81\x82".force_encoding('UTF-8') v = pack_unpack(a.encode('Shift_JIS').to_sym) v.encoding.should == Encoding::UTF_8 v.should == a end it "symbol to bin" do a = "\xE3\x81\x82".force_encoding('ASCII-8BIT') v = pack_unpack(a.to_sym) v.encoding.should == Encoding::ASCII_8BIT v.should == a end it "bin 8" do check_bin 2, (1<<8)-1 end it "bin 16" do check_bin 3, (1<<16)-1 end it "bin 32" do check_bin 5, (1<<16) end it "bin encoding is ASCII_8BIT" do pack_unpack('string'.force_encoding(Encoding::ASCII_8BIT)).encoding.should == Encoding::ASCII_8BIT end it "fixarray" do check_array 1, 0 check_array 1, (1 << 4)-1 end it "array 16" do check_array 3, (1 << 4) #check_array 3, (1 << 16)-1 end it "array 32" do #check_array 5, (1 << 16) #check_array 5, (1 << 32)-1 # memory error end it "nil" do match nil, "\xc0" end it "false" do match false, "\xc2" end it "true" do match true, "\xc3" end it "0" do match 0, "\x00" end it "127" do match 127, "\x7f" end it "128" do match 128, "\xcc\x80" end it "256" do match 256, "\xcd\x01\x00" end it "-1" do match -1, "\xff" end it "-33" do match -33, "\xd0\xdf" end it "-129" do match -129, "\xd1\xff\x7f" end it "{1=>1}" do obj = {1=>1} match obj, "\x81\x01\x01" end it "1.0" do match 1.0, "\xcb\x3f\xf0\x00\x00\x00\x00\x00\x00" end it "[]" do match [], "\x90" end it "[0, 1, ..., 14]" do obj = (0..14).to_a match obj, "\x9f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" end it "[0, 1, ..., 15]" do obj = (0..15).to_a match obj, "\xdc\x00\x10\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" end it "{}" do obj = {} match obj, "\x80" end ## FIXME # it "{0=>0, 1=>1, ..., 14=>14}" do # a = (0..14).to_a; # match Hash[*a.zip(a).flatten], "\x8f\x05\x05\x0b\x0b\x00\x00\x06\x06\x0c\x0c\x01\x01\x07\x07\x0d\x0d\x02\x02\x08\x08\x0e\x0e\x03\x03\x09\x09\x04\x04\x0a\x0a" # end # # it "{0=>0, 1=>1, ..., 15=>15}" do # a = (0..15).to_a; # match Hash[*a.zip(a).flatten], "\xde\x00\x10\x05\x05\x0b\x0b\x00\x00\x06\x06\x0c\x0c\x01\x01\x07\x07\x0d\x0d\x02\x02\x08\x08\x0e\x0e\x03\x03\x09\x09\x0f\x0f\x04\x04\x0a\x0a" # end ## FIXME # it "fixmap" do # check_map 1, 0 # check_map 1, (1<<4)-1 # end # # it "map 16" do # check_map 3, (1<<4) # check_map 3, (1<<16)-1 # end # # it "map 32" do # check_map 5, (1<<16) # #check_map 5, (1<<32)-1 # memory error # end def check(len, obj) raw = obj.to_msgpack.to_s raw.length.should == len MessagePack.unpack(raw).should == obj end def check_raw(overhead, num) check num+overhead, (" "*num).force_encoding(Encoding::UTF_8) end def check_bin(overhead, num) check num+overhead, (" "*num).force_encoding(Encoding::ASCII_8BIT) end def check_array(overhead, num) check num+overhead, Array.new(num) end def match(obj, buf) raw = obj.to_msgpack.to_s raw.should == buf end def pack_unpack(obj) MessagePack.unpack(obj.to_msgpack) end end msgpack-1.4.2/spec/random_compat.rb0000644000004100000410000000051614021120706017270 0ustar www-datawww-data unless defined? Random class Random def initialize(seed=Time.now.to_i) Kernel.srand(seed) @seed = seed end attr_reader :seed def rand(arg) Kernel.rand(arg) end def bytes(n) array = [] n.times do array << rand(256) end array.pack('C*') end end end msgpack-1.4.2/spec/cases_compact.msg0000644000004100000410000000016414021120706017433 0ustar www-datawww-dataÂÃÀÿÿÿÿÿÌÿÍÿÿÎÿÿÿÿààЀрҀËË€Ë?ðË¿ð¡a¡a¡a   ‘‘‘€€€¡aa¡aa¡aa‘‘‘¡amsgpack-1.4.2/spec/cases.msg0000644000004100000410000000032514021120706015724 0ustar www-datawww-dataÂÃÀÌÍÎÏÐÑÒÓÿÐÿÑÿÿÒÿÿÿÿÓÿÿÿÿÿÿÿÿÌÍÿÎÿÿÏÿÿÿÿàÐàÑÿ€Òÿÿ€Óÿÿÿÿ€ËË€Ë?ðË¿ð¡aÚaÛa ÚÛ‘ÜÝÜÝ€Þß¡aaÞ¡aaß¡aa‘‘‘¡amsgpack-1.4.2/spec/exttypes.rb0000644000004100000410000000146714021120706016340 0ustar www-datawww-dataclass DummyTimeStamp1 TYPE = 15 attr_reader :utime, :usec, :time def initialize(utime, usec) @utime = utime @usec = usec @time = Time.at(utime, usec) end def ==(other) self.utime == other.utime && self.usec == other.usec end def self.type_id 15 end def self.from_msgpack_ext(data) new(*data.unpack('I*')) end def to_msgpack_ext [@utime,@usec].pack('I*') end end class DummyTimeStamp2 TYPE = 16 attr_reader :utime, :usec, :time def initialize(utime, usec) @utime = utime @usec = usec @time = Time.at(utime, usec) end def ==(other) self.utime == other.utime && self.usec == other.usec end def self.deserialize(data) new(* data.split(',', 2).map(&:to_i)) end def serialize [@utime,@usec].map(&:to_s).join(',') end end msgpack-1.4.2/spec/spec_helper.rb0000644000004100000410000000203514021120706016734 0ustar www-datawww-data if ENV['SIMPLE_COV'] require 'simplecov' SimpleCov.start do add_filter 'spec/' add_filter 'pkg/' add_filter 'vendor/' end end if ENV['GC_STRESS'] puts "enable GC.stress" GC.stress = true end require 'msgpack' def java? /java/ =~ RUBY_PLATFORM end # checking if Hash#[]= (rb_hash_aset) dedupes string keys def automatic_string_keys_deduplication? h = {} x = {} r = rand.to_s h[%W(#{r}).join('')] = :foo x[%W(#{r}).join('')] = :foo x.keys[0].equal?(h.keys[0]) end def string_deduplication? r1 = rand.to_s r2 = r1.dup (-r1).equal?(-r2) end if java? RSpec.configure do |c| c.treat_symbols_as_metadata_keys_with_true_values = true c.filter_run_excluding :encodings => !(defined? Encoding) end else RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] end end Packer = MessagePack::Packer Unpacker = MessagePack::Unpacker Buffer = MessagePack::Buffer Factory = MessagePack::Factory ExtensionValue = MessagePack::ExtensionValue end msgpack-1.4.2/spec/cases.json0000644000004100000410000000033414021120706016107 0ustar www-datawww-data[false,true,null,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,127,127,255,65535,4294967295,-32,-32,-128,-32768,-2147483648,0.0,-0.0,1.0,-1.0,"a","a","a","","","",[0],[0],[0],[],[],[],{},{},{},{"a":97},{"a":97},{"a":97},[[]],[["a"]]]msgpack-1.4.2/spec/msgpack_spec.rb0000644000004100000410000001704314021120706017107 0ustar www-datawww-data# encoding: ascii-8bit require 'spec_helper' def utf8enc(str) str.encode('UTF-8') end def asciienc(str) str.encode('ASCII-8BIT') end describe MessagePack do tests = { 'constant values' => [ ['true', true, "\xC3"], ['false', false, "\xC2"], ['nil', nil, "\xC0"] ], 'numbers' => [ ['zero', 0, "\x00"], ['127', 127, "\x7F"], ['128', 128, "\xCC\x80"], ['256', 256, "\xCD\x01\x00"], ['-1', -1, "\xFF"], ['-33', -33, "\xD0\xDF"], ['-129', -129, "\xD1\xFF\x7F"], ['small integers', 42, "*"], ['medium integers', 333, "\xCD\x01M"], ['large integers', 2**31 - 1, "\xCE\x7F\xFF\xFF\xFF"], ['huge integers', 2**64 - 1, "\xCF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], ['negative integers', -1, "\xFF"], ['1.0', 1.0, "\xcb\x3f\xf0\x00\x00\x00\x00\x00\x00"], ['small floats', 3.14, "\xCB@\t\x1E\xB8Q\xEB\x85\x1F"], ['big floats', Math::PI * 1_000_000_000_000_000_000, "\xCBC\xC5\xCC\x96\xEF\xD1\x19%"], ['negative floats', -2.1, "\xCB\xC0\x00\xCC\xCC\xCC\xCC\xCC\xCD"] ], 'strings' => [ ['tiny strings', utf8enc('hello world'), "\xABhello world"], ['short strings', utf8enc('hello' * 5), "\xB9hellohellohellohellohello"], ['empty strings', utf8enc(''), "\xA0"] ], 'binary strings' => [ ['tiny strings', asciienc('hello world'), "\xC4\vhello world"], ['short strings', asciienc('hello' * 5), "\xC4\x19hellohellohellohellohello"], ['empty strings', asciienc(''), "\xC4\x00"] ], 'arrays' => [ ['empty arrays', [], "\x90"], ['arrays with strings', [utf8enc("hello"), utf8enc("world")], "\x92\xA5hello\xA5world"], ['arrays with mixed values', [utf8enc("hello"), utf8enc("world"), 42], "\x93\xA5hello\xA5world*"], ['arrays of arrays', [[[[1, 2], 3], 4]], "\x91\x92\x92\x92\x01\x02\x03\x04"], ['empty arrays', [], "\x90"] ], 'hashes' => [ ['empty hashes', {}, "\x80"], ['hashes', {utf8enc('foo') => utf8enc('bar')}, "\x81\xA3foo\xA3bar"], ['hashes with mixed keys and values', {utf8enc('foo') => utf8enc('bar'), 3 => utf8enc('three'), utf8enc('four') => 4, utf8enc('x') => [utf8enc('y')], utf8enc('a') => utf8enc('b')}, "\x85\xA3foo\xA3bar\x03\xA5three\xA4four\x04\xA1x\x91\xA1y\xA1a\xA1b"], ['hashes of hashes', {{utf8enc('x') => {utf8enc('y') => utf8enc('z')}} => utf8enc('s')}, "\x81\x81\xA1x\x81\xA1y\xA1z\xA1s"], ['hashes with nils', {utf8enc('foo') => nil}, "\x81\xA3foo\xC0"] ] } tests.each do |ctx, its| context("with #{ctx}") do its.each do |desc, unpacked, packed| it("encodes #{desc}") do MessagePack.pack(unpacked).should == packed end it "decodes #{desc}" do MessagePack.unpack(packed).should == unpacked end end end end context 'using other names for .pack and .unpack' do it 'can unpack with .load' do MessagePack.load("\xABhello world").should == 'hello world' end it 'can pack with .dump' do MessagePack.dump(utf8enc('hello world')).should == "\xABhello world" end end context 'with symbols' do it 'encodes symbols as strings' do MessagePack.pack(:symbol).should == "\xA6symbol" end end context 'with different external encoding', :encodings do before do @default_external = Encoding.default_external @default_internal = Encoding.default_internal Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::ISO_8859_1 end after do Encoding.default_external = @default_external Encoding.default_internal = @default_internal end it 'transcodes strings when encoding' do input = "sk\xE5l".force_encoding(Encoding::ISO_8859_1) MessagePack.pack(input).should == "\xA5sk\xC3\xA5l" end end context 'with other things' do it 'raises an error on #pack with an unsupported type' do expect { MessagePack.pack(self) }.to raise_error(NoMethodError, /^undefined method `to_msgpack'/) end it 'rasies an error on #unpack with garbage' do skip "but nothing was raised. why?" expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError) end end context 'extensions' do it 'can unpack hashes with symbolized keys' do packed = MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]}) unpacked = MessagePack.unpack(packed, :symbolize_keys => true) unpacked.should == {:hello => 'world', :nested => ['object', {:structure => true}]} end it 'does not symbolize keys even if other options are present' do packed = MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]}) unpacked = MessagePack.unpack(packed, :other_option => false) unpacked.should == {'hello' => 'world', 'nested' => ['object', {'structure' => true}]} end it 'can unpack strings with a specified encoding', :encodings do packed = MessagePack.pack({utf8enc('hello') => utf8enc('world')}) unpacked = MessagePack.unpack(packed) unpacked['hello'].encoding.should == Encoding::UTF_8 end it 'can pack strings with a specified encoding', :encodings do packed = MessagePack.pack({'hello' => "w\xE5rld".force_encoding(Encoding::ISO_8859_1)}) packed.index("w\xC3\xA5rld").should_not be_nil end end context 'in compatibility mode' do it 'does not use the bin types' do packed = MessagePack.pack('hello'.force_encoding(Encoding::BINARY), compatibility_mode: true) packed.should eq("\xA5hello") packed = MessagePack.pack(('hello' * 100).force_encoding(Encoding::BINARY), compatibility_mode: true) packed.should start_with("\xDA\x01\xF4") end it 'does not use the str8 type' do packed = MessagePack.pack('x' * 32, compatibility_mode: true) packed.should start_with("\xDA\x00\x20") end end context 'when a Bignum has a small value' do tests['numbers'].take(10).each do |desc, unpacked, packed| it("encodes #{desc} to the smallest representation") do bignum = (1 << 64).coerce(unpacked)[0] MessagePack.pack(bignum).should eq(packed) end end end context 'when the source is na IO-like object' do require 'tempfile' require 'stringio' it 'work with IO destination object as 2nd argument of MessagePack.pack' do Tempfile.create("pack-test") do |io| return_value = MessagePack.pack(utf8enc('hello world'), io) return_value.should be_nil io.rewind io.read.force_encoding(Encoding::ASCII_8BIT).should eq("\xABhello world".force_encoding(Encoding::ASCII_8BIT)) end end it 'work with IO-like StringIO destination object as 2nd argument of MessagePack.pack' do io = StringIO.new return_value = MessagePack.pack(utf8enc('hello world'), io) return_value.should be_nil io.rewind io.read.force_encoding(Encoding::ASCII_8BIT).should eq("\xABhello world".force_encoding(Encoding::ASCII_8BIT)) end it 'work with IO source object as source of MessagePack.unpack' do Tempfile.create("unpack-test") do |io| MessagePack.pack(utf8enc('hello world'), io) io.rewind return_value = MessagePack.unpack(io) return_value.should eq(utf8enc('hello world')) end end it 'work with IO-like StringIO object of MessagePack.unpack' do io = StringIO.new MessagePack.pack(utf8enc('hello world'), io) io.rewind return_value = MessagePack.unpack(io) return_value.should eq(utf8enc('hello world')) end end end msgpack-1.4.2/spec/cases_spec.rb0000644000004100000410000000131614021120706016554 0ustar www-datawww-datarequire 'spec_helper' require 'json' describe MessagePack do here = File.dirname(__FILE__) CASES = File.read("#{here}/cases.msg") CASES_JSON = File.read("#{here}/cases.json") CASES_COMPACT = File.read("#{here}/cases_compact.msg") it 'compare with json' do ms = [] MessagePack::Unpacker.new.feed_each(CASES) {|m| ms << m } js = JSON.load(CASES_JSON) ms.zip(js) {|m,j| m.should == j } end it 'compare with compat' do ms = [] MessagePack::Unpacker.new.feed_each(CASES) {|m| ms << m } cs = [] MessagePack::Unpacker.new.feed_each(CASES_COMPACT) {|c| cs << c } ms.zip(cs) {|m,c| m.should == c } end end msgpack-1.4.2/.rubocop.yml0000644000004100000410000000157214021120706015443 0ustar www-datawww-data# This configuration was generated by `rubocop --auto-gen-config` # on 2015-03-09 17:42:55 +0100 using RuboCop version 0.29.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. AllCops: TargetRubyVersion: 2.4 # Offense count: 3 Lint/AmbiguousOperator: Enabled: false # Offense count: 1 # Configuration parameters: AllowSafeAssignment. Lint/AssignmentInCondition: Enabled: false # Offense count: 1 Security/Eval: Enabled: false # Offense count: 3 # Cop supports --auto-correct. Lint/UnusedBlockArgument: Enabled: false # Offense count: 35 # Cop supports --auto-correct. Lint/UnusedMethodArgument: Enabled: false # Offense count: 128 Lint/Void: Enabled: false msgpack-1.4.2/msgpack.org.md0000644000004100000410000000176714021120706015734 0ustar www-datawww-data# MessagePack for Ruby ``` require 'msgpack' msg = [1,2,3].to_msgpack #=> "\x93\x01\x02\x03" MessagePack.unpack(msg) #=> [1,2,3] ``` ## Install ``` gem install msgpack ``` ## Use cases * Create REST API returing MessagePack using Rails + [RABL](https://github.com/nesquena/rabl) * Store objects efficiently in memcached or Redis * Upload data in efficient format from mobile devices. See also MessagePack for [Objective-C](https://github.com/msgpack/msgpack-objectivec) and [Java](https://github.com/msgpack/msgpack-java) ## Links * [Github](https://github.com/msgpack/msgpack-ruby) * [API document](http://ruby.msgpack.org/) ## Streaming API ``` # serialize a 2-element array [e1, e2] pk = MessagePack::Packer.new(io) pk.write_array_header(2).write(e1).write(e2).flush ``` ``` # deserialize objects from an IO u = MessagePack::Unpacker.new(io) u.each { |obj| ... } ``` ``` # event-driven deserialization def on_read(data) @u ||= MessagePack::Unpacker.new @u.feed_each(data) { |obj| ... } end ``` msgpack-1.4.2/.gitignore0000644000004100000410000000027214021120706015155 0ustar www-datawww-data*.o *.so *.bundle *.gem *.class *.jar doc .yardoc .bundle Gemfile* pkg test/debug.log *~ *.swp /rdoc tmp .classpath .project .settings /nbproject/private/ coverage/ .idea/ .ruby-version msgpack-1.4.2/LICENSE0000644000004100000410000002367614021120706014207 0ustar www-datawww-data Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS msgpack-1.4.2/bench/0000755000004100000410000000000014021120706014243 5ustar www-datawww-datamsgpack-1.4.2/bench/pack_log.rb0000644000004100000410000000161114021120706016346 0ustar www-datawww-datarequire 'viiite' require 'msgpack' data_plain = { 'message' => '127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"' } data_structure = { 'remote_host' => '127.0.0.1', 'remote_user' => '-', 'date' => '10/Oct/2000:13:55:36 -0700', 'request' => 'GET /apache_pb.gif HTTP/1.0', 'method' => 'GET', 'path' => '/apache_pb.gif', 'protocol' => 'HTTP/1.0', 'status' => 200, 'bytes' => 2326, 'referer' => 'http://www.example.com/start.html', 'agent' => 'Mozilla/4.08 [en] (Win98; I ;Nav)', } Viiite.bench do |b| b.range_over([10_000, 100_000, 1000_000], :runs) do |runs| b.report(:plain) do runs.times do MessagePack.pack(data_plain) end end b.report(:structure) do runs.times do MessagePack.pack(data_structure) end end end end msgpack-1.4.2/bench/run_symbols.sh0000644000004100000410000000113314021120706017151 0ustar www-datawww-data#!/bin/sh # so master and this branch have the benchmark file in any case cp bench/pack_symbols.rb bench/pack_symbols_tmp.rb benchmark="" current_branch=`git rev-parse --abbrev-ref HEAD` for branch in master $current_branch; do echo "Testing branch $branch" git checkout $branch echo "Installing gem..." rake install echo "Running benchmark..." if [ "$benchmark" ]; then benchmark+=$'\n' fi benchmark+=$(viiite run bench/pack_symbols_tmp.rb) echo done rm bench/pack_symbols_tmp.rb echo "$benchmark" | viiite report --regroup bench,reg_type,count,branchmsgpack-1.4.2/bench/pack_log_long.rb0000644000004100000410000000344614021120706017375 0ustar www-datawww-data# viiite report --regroup bench,threads bench/pack_log_long.rb require 'viiite' require 'msgpack' data_plain = { 'message' => '127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"' } data_structure = { 'remote_host' => '127.0.0.1', 'remote_user' => '-', 'date' => '10/Oct/2000:13:55:36 -0700', 'request' => 'GET /apache_pb.gif HTTP/1.0', 'method' => 'GET', 'path' => '/apache_pb.gif', 'protocol' => 'HTTP/1.0', 'status' => 200, 'bytes' => 2326, 'referer' => 'http://www.example.com/start.html', 'agent' => 'Mozilla/4.08 [en] (Win98; I ;Nav)', } seconds = 3600 # 1 hour Viiite.bench do |b| b.range_over([1, 2, 4, 8, 16], :threads) do |threads| b.report(:plain) do ths = [] end_at = Time.now + seconds threads.times do t = Thread.new do packs = 0 while Time.now < end_at 10000.times do MessagePack.pack(data_plain) end packs += 10000 end packs end ths.push t end sum = ths.reduce(0){|r,t| r + t.value } puts "MessagePack.pack, plain, #{threads} threads: #{sum} times, #{sum / seconds} times/second." end b.report(:structure) do ths = [] end_at = Time.now + seconds threads.times do t = Thread.new do packs = 0 while Time.now < end_at 10000.times do MessagePack.pack(data_structure) end packs += 10000 end packs end ths.push t end sum = ths.reduce(0){|r,t| r + t.value } puts "MessagePack.pack, structured, #{threads} threads: #{sum} times, #{sum / seconds} times/second." end end end msgpack-1.4.2/bench/pack.rb0000644000004100000410000000104114021120706015502 0ustar www-datawww-datarequire 'viiite' require 'msgpack' data = { 'hello' => 'world', 'nested' => ['structure', {value: 42}] } data_sym = { hello: 'world', nested: ['structure', {value: 42}] } data = MessagePack.pack(:hello => 'world', :nested => ['structure', {:value => 42}]) Viiite.bench do |b| b.range_over([10_000, 100_000, 1000_000], :runs) do |runs| b.report(:strings) do runs.times do MessagePack.pack(data) end end b.report(:symbols) do runs.times do MessagePack.pack(data_sym) end end end end msgpack-1.4.2/bench/unpack_log.rb0000644000004100000410000000166214021120706016717 0ustar www-datawww-datarequire 'viiite' require 'msgpack' data_plain = MessagePack.pack({ 'message' => '127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"' }) data_structure = MessagePack.pack({ 'remote_host' => '127.0.0.1', 'remote_user' => '-', 'date' => '10/Oct/2000:13:55:36 -0700', 'request' => 'GET /apache_pb.gif HTTP/1.0', 'method' => 'GET', 'path' => '/apache_pb.gif', 'protocol' => 'HTTP/1.0', 'status' => 200, 'bytes' => 2326, 'referer' => 'http://www.example.com/start.html', 'agent' => 'Mozilla/4.08 [en] (Win98; I ;Nav)', }) Viiite.bench do |b| b.range_over([10_000, 100_000, 1000_000], :runs) do |runs| b.report(:plain) do runs.times do MessagePack.unpack(data_plain) end end b.report(:structure) do runs.times do MessagePack.unpack(data_structure) end end end end msgpack-1.4.2/bench/unpack.rb0000644000004100000410000000071314021120706016052 0ustar www-datawww-datarequire 'viiite' require 'msgpack' data = MessagePack.pack(:hello => 'world', :nested => ['structure', {:value => 42}]) Viiite.bench do |b| b.range_over([10_000, 100_000, 1000_000], :runs) do |runs| b.report(:strings) do runs.times do MessagePack.unpack(data) end end b.report(:symbols) do options = {:symbolize_keys => true} runs.times do MessagePack.unpack(data, options) end end end end msgpack-1.4.2/bench/unpack_log_long.rb0000644000004100000410000000352614021120706017737 0ustar www-datawww-data# viiite report --regroup bench,threads bench/pack_log_long.rb require 'viiite' require 'msgpack' data_plain = MessagePack.pack({ 'message' => '127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"' }) data_structure = MessagePack.pack({ 'remote_host' => '127.0.0.1', 'remote_user' => '-', 'date' => '10/Oct/2000:13:55:36 -0700', 'request' => 'GET /apache_pb.gif HTTP/1.0', 'method' => 'GET', 'path' => '/apache_pb.gif', 'protocol' => 'HTTP/1.0', 'status' => 200, 'bytes' => 2326, 'referer' => 'http://www.example.com/start.html', 'agent' => 'Mozilla/4.08 [en] (Win98; I ;Nav)', }) seconds = 3600 # 1 hour Viiite.bench do |b| b.range_over([1, 2, 4, 8, 16], :threads) do |threads| b.report(:plain) do ths = [] end_at = Time.now + seconds threads.times do t = Thread.new do packs = 0 while Time.now < end_at 10000.times do MessagePack.unpack(data_plain) end packs += 10000 end packs end ths.push t end sum = ths.reduce(0){|r,t| r + t.value } puts "MessagePack.unpack, plain, #{threads} threads: #{sum} times, #{sum / seconds} times/second." end b.report(:structure) do ths = [] end_at = Time.now + seconds threads.times do t = Thread.new do packs = 0 while Time.now < end_at 10000.times do MessagePack.unpack(data_structure) end packs += 10000 end packs end ths.push t end sum = ths.reduce(0){|r,t| r + t.value } puts "MessagePack.unpack, structured, #{threads} threads: #{sum} times, #{sum / seconds} times/second." end end end msgpack-1.4.2/bench/run_long.sh0000644000004100000410000000142314021120706016422 0ustar www-datawww-data#!/bin/sh # prerequisites # $ sudo apt-get install sysstat # $ rbenv shell 2.2.1 (or jruby-x.x.x or ...) # $ rake install # 60 * 600 : 60*60 * 5[threads] * 2[bench] ruby -v echo "pack log long" viiite report --regroup bench,threads bench/pack_log_long.rb & sar -o pack_log_long.sar -r 60 600 > /dev/null 2>&1 & declare -i i=0 while [ $i -lt 600 ]; do ps auxww | grep ruby | grep -v grep | awk '{print $5,$6;}' >> pack_log_long.mem.txt i=i+1 sleep 60 done sleep 120 # cool down echo "unpack log long" viiite report --regroup bench,threads bench/unpack_log_long.rb & sar -o unpack_log_long.sar -r 60 600 > /dev/null 2>&1 & i=0 while [ $i -lt 600 ]; do ps auxww | grep ruby | grep -v grep | awk '{print $5,$6;}' >> pack_log_long.mem.txt i=i+1 sleep 60 done msgpack-1.4.2/bench/run.sh0000644000004100000410000000055314021120706015406 0ustar www-datawww-data#!/bin/sh # prerequisites # $ rbenv shell 2.2.1 (or jruby-x.x.x or ...) # $ rake install echo "pack" viiite report --regroup bench,runs bench/pack.rb echo "unpack" viiite report --regroup bench,runs bench/unpack.rb echo "pack log" viiite report --regroup bench,runs bench/pack_log.rb echo "unpack log" viiite report --regroup bench,runs bench/unpack_log.rb msgpack-1.4.2/bench/pack_symbols.rb0000644000004100000410000000122014021120706017251 0ustar www-datawww-datarequire 'viiite' require 'msgpack' data = :symbol Viiite.bench do |b| b.variation_point :branch, `git rev-parse --abbrev-ref HEAD` b.range_over([:symbol, :none], :reg_type) do |reg_type| packer = MessagePack::Packer.new packer.register_type(0x00, Symbol, :to_msgpack_ext) if reg_type == :symbol b.range_over([100_000, 1_000_000, 10_000_000], :count) do |count| packer.clear b.report(:multi_run) do count.times do packer.pack(data) end end packer.clear items_data = [].fill(data, 0, count) b.report(:large_run) do packer.pack(items_data) end end end end msgpack-1.4.2/Rakefile0000644000004100000410000000355514021120706014641 0ustar www-datawww-data require 'bundler' Bundler::GemHelper.install_tasks require 'fileutils' require 'rspec/core' require 'rspec/core/rake_task' require 'yard' task :spec => :compile desc 'Run RSpec code examples and measure coverage' task :coverage do |t| ENV['SIMPLE_COV'] = '1' Rake::Task["spec"].invoke end desc 'Generate YARD document' YARD::Rake::YardocTask.new(:doc) do |t| t.files = ['lib/msgpack/version.rb','doclib/**/*.rb'] t.options = [] t.options << '--debug' << '--verbose' if $trace end spec = eval File.read("msgpack.gemspec") if RUBY_PLATFORM =~ /java/ require 'rake/javaextensiontask' Rake::JavaExtensionTask.new('msgpack', spec) do |ext| ext.ext_dir = 'ext/java' jruby_home = RbConfig::CONFIG['prefix'] jars = ["#{jruby_home}/lib/jruby.jar"] ext.classpath = jars.map { |x| File.expand_path(x) }.join(':') ext.lib_dir = File.join(*['lib', 'msgpack', ENV['FAT_DIR']].compact) ext.source_version = '1.6' ext.target_version = '1.6' end else require 'rake/extensiontask' Rake::ExtensionTask.new('msgpack', spec) do |ext| ext.ext_dir = 'ext/msgpack' ext.cross_compile = true ext.lib_dir = File.join(*['lib', 'msgpack', ENV['FAT_DIR']].compact) # cross_platform names are of MRI's platform name ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] end end test_pattern = case when RUBY_PLATFORM =~ /java/ then 'spec/{,jruby/}*_spec.rb' when RUBY_ENGINE =~ /rbx/ then 'spec/*_spec.rb' else 'spec/{,cruby/}*_spec.rb' # MRI end RSpec::Core::RakeTask.new(:spec) do |t| t.rspec_opts = ["-c", "-f progress"] t.rspec_opts << "-Ilib" t.pattern = test_pattern t.verbose = true end namespace :build do desc 'Build gem for JRuby after cleaning' task :java => [:clean, :spec, :build] end CLEAN.include('lib/msgpack/msgpack.*') task :default => [:spec, :build, :doc] msgpack-1.4.2/lib/0000755000004100000410000000000014021120706013732 5ustar www-datawww-datamsgpack-1.4.2/lib/msgpack.rb0000644000004100000410000000214014021120706015701 0ustar www-datawww-datarequire "msgpack/version" if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" # This is same with `/java/ =~ RUBY_VERSION` require "java" require "msgpack/msgpack.jar" org.msgpack.jruby.MessagePackLibrary.new.load(JRuby.runtime, false) else require "msgpack/msgpack" end require "msgpack/packer" require "msgpack/unpacker" require "msgpack/factory" require "msgpack/symbol" require "msgpack/core_ext" require "msgpack/timestamp" require "msgpack/time" module MessagePack DefaultFactory = MessagePack::Factory.new DEFAULT_EMPTY_PARAMS = {}.freeze def load(src, param = nil) unpacker = nil if src.is_a? String unpacker = DefaultFactory.unpacker param || DEFAULT_EMPTY_PARAMS unpacker.feed_reference src else unpacker = DefaultFactory.unpacker src, param || DEFAULT_EMPTY_PARAMS end unpacker.full_unpack end alias :unpack :load module_function :load module_function :unpack def pack(v, *rest) packer = DefaultFactory.packer(*rest) packer.write v packer.full_pack end alias :dump :pack module_function :pack module_function :dump end msgpack-1.4.2/lib/msgpack/0000755000004100000410000000000014021120706015357 5ustar www-datawww-datamsgpack-1.4.2/lib/msgpack/version.rb0000644000004100000410000000031614021120706017371 0ustar www-datawww-datamodule MessagePack VERSION = "1.4.2" # Note for maintainers: # Don't miss building/releasing the JRuby version (rake buld:java) # See "How to build -java rubygems" in README for more details. end msgpack-1.4.2/lib/msgpack/symbol.rb0000644000004100000410000000021514021120706017207 0ustar www-datawww-dataclass Symbol def to_msgpack_ext [to_s].pack('A*') end def self.from_msgpack_ext(data) data.unpack('A*').first.to_sym end endmsgpack-1.4.2/lib/msgpack/core_ext.rb0000644000004100000410000000414214021120706017515 0ustar www-datawww-datamodule MessagePack module CoreExt def to_msgpack(packer_or_io = nil) if packer_or_io if packer_or_io.is_a?(MessagePack::Packer) to_msgpack_with_packer packer_or_io else MessagePack.pack(self, packer_or_io) end else MessagePack.pack(self) end end end end class NilClass include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_nil packer end end class TrueClass include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_true packer end end class FalseClass include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_false packer end end class Float include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_float self packer end end class String include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_string self packer end end class Array include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_array self packer end end class Hash include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_hash self packer end end class Symbol include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_symbol self packer end end if 1.class.name == "Integer" class Integer include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_int self packer end end else class Fixnum include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_int self packer end end class Bignum include MessagePack::CoreExt private def to_msgpack_with_packer(packer) packer.write_int self packer end end end module MessagePack class ExtensionValue include CoreExt private def to_msgpack_with_packer(packer) packer.write_extension self packer end end end msgpack-1.4.2/lib/msgpack/timestamp.rb0000644000004100000410000000416414021120706017714 0ustar www-datawww-data# frozen_string_literal: true module MessagePack class Timestamp # a.k.a. "TimeSpec" # Because the byte-order of MessagePack is big-endian in, # pack() and unpack() specifies ">". # See https://docs.ruby-lang.org/en/trunk/Array.html#method-i-pack for details. # The timestamp extension type defined in the MessagePack spec. # See https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type for details. TYPE = -1 TIMESTAMP32_MAX_SEC = (1 << 32) - 1 TIMESTAMP64_MAX_SEC = (1 << 34) - 1 # @return [Integer] attr_reader :sec # @return [Integer] attr_reader :nsec # @param [Integer] sec # @param [Integer] nsec def initialize(sec, nsec) @sec = sec @nsec = nsec end def self.from_msgpack_ext(data) case data.length when 4 # timestamp32 (sec: uint32be) sec, = data.unpack('L>') new(sec, 0) when 8 # timestamp64 (nsec: uint30be, sec: uint34be) n, s = data.unpack('L>2') sec = ((n & 0b11) << 32) | s nsec = n >> 2 new(sec, nsec) when 12 # timestam96 (nsec: uint32be, sec: int64be) nsec, sec = data.unpack('L>q>') new(sec, nsec) else raise MalformedFormatError, "Invalid timestamp data size: #{data.length}" end end def self.to_msgpack_ext(sec, nsec) if sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC if nsec === 0 && sec <= TIMESTAMP32_MAX_SEC # timestamp32 = (sec: uint32be) [sec].pack('L>') else # timestamp64 (nsec: uint30be, sec: uint34be) nsec30 = nsec << 2 sec_high2 = sec >> 32 # high 2 bits (`x & 0b11` is redandunt) sec_low32 = sec & 0xffffffff # low 32 bits [nsec30 | sec_high2, sec_low32].pack('L>2') end else # timestamp96 (nsec: uint32be, sec: int64be) [nsec, sec].pack('L>q>') end end def to_msgpack_ext self.class.to_msgpack_ext(sec, nsec) end def ==(other) other.class == self.class && sec == other.sec && nsec == other.nsec end end end msgpack-1.4.2/lib/msgpack/factory.rb0000644000004100000410000000410314021120706017351 0ustar www-datawww-datamodule MessagePack class Factory # see ext for other methods # [ {type: id, class: Class(or nil), packer: arg, unpacker: arg}, ... ] def registered_types(selector=:both) packer, unpacker = registered_types_internal # packer: Class -> [tid, proc, arg] # unpacker: tid -> [klass, proc, arg] list = [] case selector when :both packer.each_pair do |klass, ary| type = ary[0] packer_arg = ary[2] unpacker_arg = nil if unpacker.has_key?(type) && unpacker[type][0] == klass unpacker_arg = unpacker.delete(type)[2] end list << {type: type, class: klass, packer: packer_arg, unpacker: unpacker_arg} end # unpacker definition only unpacker.each_pair do |type, ary| list << {type: type, class: ary[0], packer: nil, unpacker: ary[2]} end when :packer packer.each_pair do |klass, ary| list << {type: ary[0], class: klass, packer: ary[2]} end when :unpacker unpacker.each_pair do |type, ary| list << {type: type, class: ary[0], unpacker: ary[2]} end else raise ArgumentError, "invalid selector #{selector}" end list.sort{|a, b| a[:type] <=> b[:type] } end def type_registered?(klass_or_type, selector=:both) case klass_or_type when Class klass = klass_or_type registered_types(selector).any?{|entry| klass <= entry[:class] } when Integer type = klass_or_type registered_types(selector).any?{|entry| type == entry[:type] } else raise ArgumentError, "class or type id" end end def load(src, param = nil) unpacker = nil if src.is_a? String unpacker = unpacker(param) unpacker.feed(src) else unpacker = unpacker(src, param) end unpacker.full_unpack end alias :unpack :load def dump(v, *rest) packer = packer(*rest) packer.write(v) packer.full_pack end alias :pack :dump end end msgpack-1.4.2/lib/msgpack/time.rb0000644000004100000410000000166614021120706016653 0ustar www-datawww-data# frozen_string_literal: true # MessagePack extention packer and unpacker for built-in Time class module MessagePack module Time # 3-arg Time.at is available Ruby >= 2.5 TIME_AT_3_AVAILABLE = begin !!::Time.at(0, 0, :nanosecond) rescue ArgumentError false end Unpacker = if TIME_AT_3_AVAILABLE lambda do |payload| tv = MessagePack::Timestamp.from_msgpack_ext(payload) ::Time.at(tv.sec, tv.nsec, :nanosecond) end else lambda do |payload| tv = MessagePack::Timestamp.from_msgpack_ext(payload) ::Time.at(tv.sec, tv.nsec / 1000.0) end end Packer = lambda { |time| MessagePack::Timestamp.to_msgpack_ext(time.tv_sec, time.tv_nsec) } end end msgpack-1.4.2/lib/msgpack/packer.rb0000644000004100000410000000123214021120706017147 0ustar www-datawww-datamodule MessagePack class Packer # see ext for other methods def registered_types list = [] registered_types_internal.each_pair do |klass, ary| list << {type: ary[0], class: klass, packer: ary[2]} end list.sort{|a, b| a[:type] <=> b[:type] } end def type_registered?(klass_or_type) case klass_or_type when Class klass = klass_or_type registered_types.any?{|entry| klass <= entry[:class] } when Integer type = klass_or_type registered_types.any?{|entry| type == entry[:type] } else raise ArgumentError, "class or type id" end end end end msgpack-1.4.2/lib/msgpack/unpacker.rb0000644000004100000410000000123414021120706017514 0ustar www-datawww-datamodule MessagePack class Unpacker # see ext for other methods def registered_types list = [] registered_types_internal.each_pair do |type, ary| list << {type: type, class: ary[0], unpacker: ary[2]} end list.sort{|a, b| a[:type] <=> b[:type] } end def type_registered?(klass_or_type) case klass_or_type when Class klass = klass_or_type registered_types.any?{|entry| klass == entry[:class] } when Integer type = klass_or_type registered_types.any?{|entry| type == entry[:type] } else raise ArgumentError, "class or type id" end end end end msgpack-1.4.2/ChangeLog0000644000004100000410000001760314021120706014745 0ustar www-datawww-data2021-02-01 version 1.4.2: * Add the required Ruby version (>= 2.4) to avoid compilation errors on older Ruby runtimes * Drop the support of old Ruby versions explicitly (1.8, 1.9, 2.0, 2.1, 2.2, 2.3) 2021-01-27 version 1.4.1: * Bugfix about the wrong string encoding longer than 256 bytes (#200) 2021-01-27 version 1.4.0: * Introduce the optimization to use frozen/deduped keys for map objects * Stop releasing fat gem (pre-built binaries) for mswin32 arch environments 2020-02-05 version 1.3.3: * Hotfix release for Windows environments: 1.3.2 missed including binaries 2020-02-04 version 1.3.2: * Add Ruby 2.7.0 binary in gem releases for Windows 2019-08-05 version 1.3.1: * Fix timestamp ext type bug about timestamps with seconds larger than 32bit int (after 2106-02-07 06:28:16 UTC) 2019-06-20 verison 1.3.0: * Add timestamp ext type (id:-1) support 2019-04-19 version 1.2.10: * Optimze MessagePack.unpack not to copy source string 2019-03-13 version 1.2.9: * Hotfix release only for JRuby: 1.2.8-java was built incorrectly 2019-03-11 version 1.2.8: * Fix a regression that MessagePack#unpack raises error if IO is assigned as the (only) argument * Improve compatibility that MessagePack#pack returns nil if IO is assigned as 2nd argument 2019-03-01 version 1.2.7: * Add Packer#write_bin and Packer#write_bin_header methods 2019-01-08 verison 1.2.6: * Update Ruby version 2.6 dependency (especially for Windows environment) * (version 1.2.4 and 1.2.5 were also releases for updated Ruby versions) 2018-03-02 version 1.2.3: * Add Ruby 2.5.0 binary in gem releases for Windows 2018-01-11 version 1.2.2: * Fix bug to occur SEGV occasionally (depends on GC timing) when exttype is used * Fix bug to encode an ext type with wrong type id if superclass is also registered as ext type 2017-12-08 version 1.2.1: * Hotfix release only for JRuby: 1.2.0-java was built in incorrect way 2017-12-07 version 1.2.0: * Add MessagePack::Factory#dump and MessagePack::Factory#load as convenient methods like MessagePack.dump and MessagePack.load * Fix bug to accept MessagePack::Factory#register_type after #freeze 2017-02-28 version 1.1.0: * Fix the extension type handling to accept modules in addition to classes 2017-01-24 version 1.0.3: * Support Ruby 2.4 2016-10-17 version 1.0.2: * Bump version up to release newer version to fix broken gem release for JRuby 2016-10-17 version 1.0.1: * Fix a bug to crash at packer when ext type is registered for superclass of packed object * Fix JRuby implementation about inconsistent API of Unpacker constructor 2016-07-08 version 1.0.0: * Fix to be able to pack Symbol with ext types * Fix for MRI 2.4 (Integer unification) 2016-05-10 version 0.7.6: * Fix bug to raise IndexOutOfBoundsException for Bignum value with small int in JRuby 2016-04-06 version 0.7.5: * Improved support for i386/armel/armhf environments * Fix bug for negative ext type id and some architectures (arm*) 2016-01-08 version 0.7.4: * Improved compatibility of Packer between CRuby and JRuby about argument IO-ish object values. 2016-01-07 version 0.7.3: * Add Packer#write_float32 method to pack floating point numbers into FLOAT of messagepack. 2016-01-06 version 0.7.2: * Improved compatibility of Unpacker between CRuby and JRuby to accept stream-like object by checking respond_to(:read) in addition to class check 2015-11-20 version 0.7.1: * Fixed bug to pack/unpack ext type objects larger than 256bytes incorrectly. 2015-10-24 version 0.7.0: * Add extension types support. * Fix to share almost all test cases between CRuby and JRuby implementations. * Fixed JRuby implementation to raise UnknownExtTypeError for unregistered ext type ids instead to generate MessagePack::ExtensionValue instances. (Specify `allow_unknown_ext: true` as unpacker option for v0.6.x behavior.) 2015-07-22 version 0.6.2: * Fix release workflow: Ruby 2.1 and 2.2 are supported for Windows (2.0 is omitted) * Fix to encode symbols along its encoding * Fix segmentation fault in minor case 2015-07-01 version 0.6.1: * Added :compatibility_mode option to Packer#initialize. Default is false. If it is set to true, str8 format and bin format family will not be used. 2015-05-26 version 0.6.0: * Added support for Binary types * Fixed to encode/decode between Binary types and ASCII-8BIT Ruby String objects 2015-05-21 version 0.5.12: * Added support for JRuby 9K. * Added a benchmarking suite. * Fixed a bug in the handling of options given to MessagePack.unpack in JRuby. 2015-02-04 version 0.5.11: * Fixed Encoding::CompatibilityError error when serializing a long string longer than write_reference_threshold (5KB by default) and whose encoding is not ASCII-8BIT. * Fix read_(map|array)_header (@funny-falcon++). * Internally, rename msgpack_unpacker_{init,reset,destroy} functions so that we can load msgpack-c in the same process (@miihael++) 2015-01-09 version 0.5.10: * Merged msgpack-jruby by @iconara. JRuby can run `require 'msgpack'` to use msgpack-jruby. 2014-10-05 version 0.5.9: * Fixed Unpacker#read_map_header and #read_array_header * Added support for Symbol GC added since MRI 2.2.0 2013-12-14 version 0.5.8: * Fixed compatibility with Ruby 2.1.0 * Added :symbolize_keys option to MessagePack.load and Unpacker#initialize 2013-10-12 version 0.5.7: * Added deserialization support for the new MessagePack spec 2013-09-23 version 0.5.6: * Fixed "can't modify frozen String" exception in Unpacker with ruby 2.1.0-dev * Getting work with Ruby v2.0 on Windows (Thank you @thegreendroid) * Fixed EOFError handling in Unpacker 2013-05-12 version 0.5.5: * Fixed SEGV problem in to_msgpack * Fixed a possible race condition in MessagePack.load when it loads data from IO * mingw32 package includes binary for ruby-2.0.0 2013-03-15 version 0.5.4: * Added missing MessagePack::Unpacker#reset method 2013-02-14 version 0.5.3: * Fixed segfault problem on Buffer#clear (reuse rmem internal fragment optimization) * Fixed segfault problem on Buffer (rmem free code) 2013-02-07 version 0.5.2: * Fixed invalid pack/unpack on 32bit architecture such as Win32 * Disable rmem on Rubinius because rmem is not thread safe 2012-12-23 version 0.5.1: * Fixed compile error with Rubinius 2.0.0-dev * Optimized msgpack_packer_write_hash for Rubinius 2012-12-20 version 0.5.0: * Rewrote all code and improved performance significantly * Added MessagePack::Buffer class * Added MessagePack::Packer class * Added Packer#buffer and Unpacker#buffer accessors which return MessagePack::Buffer * Added Packer#write_{array,map}_header and Unpacker#read_{array,map}_header methods * Added Packer#write_nil and Unpacker#skip_nil methods * Added Packer#write -> #pack alias and Unpacker#read method * Added exception classes - UnpackError, MalformedFormatError, StackError and TypeError * Added MessagePack.dup -> .pack and MessagePack.load -> .unpack aliases * Added Packer#empty?, #size and #clear methods * Added Packer#write_to(io) method to flush serialized data to IO efficiently * Added Unpacker#skip method to skip an object efficiently * Removed obsoleted Unpacker#fill, #execute, #execute_limit, #finished? and #data methods * Removed obsoleted Unapcker#stream and #stream= methods. Use unpacker.buffer.io instead 2012-05-05 version 0.4.7: * Fixed serialization of double values on ARM OABI architectures * Fixed byteorder problem on big-endian platforms * Don't use MRI internals in the Ruby extension for Rubinius * Detect whether st.h is present and don't use RUBY_VM as the condition for Rubinius 2011-08-08 version 0.4.6: * Fixed compile error problem on Mac OS X Lion 2011-05-09 version 0.4.5: * Improves compatibility with JRuby 2010-11-28 version 0.4.4: * Adds Unpacker#feed_each method * Improves compatibility with Rubinius * Improves compatibility with ruby-1.8.5 * Encodings of String instances to UTF-8 on Ruby 1.9 2010-06-29 version 0.4.3: * Adds MessagePack::VERSION constant * Fixes SEGV problem caused by GC bug at MessagePack_Unpacker_mark msgpack-1.4.2/Gemfile0000644000004100000410000000021214021120706014452 0ustar www-datawww-datasource 'https://rubygems.org/' gemspec ## enable this line to run benchmarks # gem "viiite" gem "rubocop", "~> 0.82.0" gem "simplecov" msgpack-1.4.2/appveyor.yml0000644000004100000410000000054514021120706015560 0ustar www-datawww-data--- install: - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% - ruby --version - gem --version - bundle install build: off test_script: - bundle exec rake -rdevkit environment: matrix: - ruby_version: "200" - ruby_version: "200-x64" - ruby_version: "21" - ruby_version: "21-x64" - ruby_version: "22" - ruby_version: "22-x64" msgpack-1.4.2/ext/0000755000004100000410000000000014021120706013764 5ustar www-datawww-datamsgpack-1.4.2/ext/msgpack/0000755000004100000410000000000014021120706015411 5ustar www-datawww-datamsgpack-1.4.2/ext/msgpack/packer_class.h0000644000004100000410000000172714021120706020223 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_PACKER_CLASS_H__ #define MSGPACK_RUBY_PACKER_CLASS_H__ #include "packer.h" extern VALUE cMessagePack_Packer; void MessagePack_Packer_module_init(VALUE mMessagePack); VALUE MessagePack_Packer_alloc(VALUE klass); VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self); #endif msgpack-1.4.2/ext/msgpack/buffer_class.h0000644000004100000410000000176614021120706020232 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_BUFFER_CLASS_H__ #define MSGPACK_RUBY_BUFFER_CLASS_H__ #include "buffer.h" extern VALUE cMessagePack_Buffer; void MessagePack_Buffer_module_init(VALUE mMessagePack); VALUE MessagePack_Buffer_wrap(msgpack_buffer_t* b, VALUE owner); void MessagePack_Buffer_set_options(msgpack_buffer_t* b, VALUE io, VALUE options); #endif msgpack-1.4.2/ext/msgpack/sysdep_endian.h0000644000004100000410000000346714021120706020421 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_SYSDEP_ENDIAN_H__ #define MSGPACK_RUBY_SYSDEP_ENDIAN_H__ /* including arpa/inet.h requires an extra dll on win32 */ #ifndef _WIN32 #include /* __BYTE_ORDER */ #endif /* * Use following command to add consitions here: * cpp -dM `echo "#include " > test.c; echo test.c` | grep ENDIAN */ #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) /* Mac OS X */ # if defined(_LITTLE_ENDIAN) \ || ( defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) \ && __BYTE_ORDER == __LITTLE_ENDIAN ) /* Linux */ \ || ( defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ) /* Solaris */ # define __LITTLE_ENDIAN__ # elif defined(_BIG_ENDIAN) \ || (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) \ && __BYTE_ORDER == __BIG_ENDIAN) /* Linux */ \ || (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) \ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) /* Solaris */ # define __BIG_ENDIAN__ # elif defined(_WIN32) /* Win32 */ # define __LITTLE_ENDIAN__ # endif #endif #endif msgpack-1.4.2/ext/msgpack/factory_class.c0000644000004100000410000001505314021120706020415 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "factory_class.h" #include "packer_ext_registry.h" #include "unpacker_ext_registry.h" #include "buffer_class.h" #include "packer_class.h" #include "unpacker_class.h" VALUE cMessagePack_Factory; struct msgpack_factory_t; typedef struct msgpack_factory_t msgpack_factory_t; struct msgpack_factory_t { msgpack_packer_ext_registry_t pkrg; msgpack_unpacker_ext_registry_t ukrg; bool has_symbol_ext_type; }; #define FACTORY(from, name) \ msgpack_factory_t *name = NULL; \ Data_Get_Struct(from, msgpack_factory_t, name); \ if(name == NULL) { \ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \ } static void Factory_free(msgpack_factory_t* fc) { if(fc == NULL) { return; } msgpack_packer_ext_registry_destroy(&fc->pkrg); msgpack_unpacker_ext_registry_destroy(&fc->ukrg); xfree(fc); } void Factory_mark(msgpack_factory_t* fc) { msgpack_packer_ext_registry_mark(&fc->pkrg); msgpack_unpacker_ext_registry_mark(&fc->ukrg); } static VALUE Factory_alloc(VALUE klass) { msgpack_factory_t* fc = ZALLOC_N(msgpack_factory_t, 1); VALUE self = Data_Wrap_Struct(klass, Factory_mark, Factory_free, fc); return self; } static VALUE Factory_initialize(int argc, VALUE* argv, VALUE self) { FACTORY(self, fc); msgpack_packer_ext_registry_init(&fc->pkrg); msgpack_unpacker_ext_registry_init(&fc->ukrg); fc->has_symbol_ext_type = false; switch (argc) { case 0: break; default: // TODO options is not supported yet rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } return Qnil; } VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self) { FACTORY(self, fc); VALUE packer = MessagePack_Packer_alloc(cMessagePack_Packer); MessagePack_Packer_initialize(argc, argv, packer); msgpack_packer_t* pk; Data_Get_Struct(packer, msgpack_packer_t, pk); msgpack_packer_ext_registry_destroy(&pk->ext_registry); msgpack_packer_ext_registry_dup(&fc->pkrg, &pk->ext_registry); pk->has_symbol_ext_type = fc->has_symbol_ext_type; return packer; } VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self) { FACTORY(self, fc); VALUE unpacker = MessagePack_Unpacker_alloc(cMessagePack_Unpacker); MessagePack_Unpacker_initialize(argc, argv, unpacker); msgpack_unpacker_t* uk; Data_Get_Struct(unpacker, msgpack_unpacker_t, uk); msgpack_unpacker_ext_registry_destroy(&uk->ext_registry); msgpack_unpacker_ext_registry_dup(&fc->ukrg, &uk->ext_registry); return unpacker; } static VALUE Factory_registered_types_internal(VALUE self) { FACTORY(self, fc); VALUE uk_mapping = rb_hash_new(); for(int i=0; i < 256; i++) { if(fc->ukrg.array[i] != Qnil) { rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg.array[i]); } } #ifdef HAVE_RB_HASH_DUP return rb_ary_new3(2, rb_hash_dup(fc->pkrg.hash), uk_mapping); #else return rb_ary_new3(2, rb_funcall(fc->pkrg.hash, rb_intern("dup"), 0), uk_mapping); #endif } static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self) { FACTORY(self, fc); int ext_type; VALUE ext_module; VALUE options; VALUE packer_arg, unpacker_arg; VALUE packer_proc, unpacker_proc; if (OBJ_FROZEN(self)) { rb_raise(rb_eRuntimeError, "can't modify frozen Factory"); } switch (argc) { case 2: /* register_type(0x7f, Time) */ packer_arg = ID2SYM(rb_intern("to_msgpack_ext")); unpacker_arg = ID2SYM(rb_intern("from_msgpack_ext")); break; case 3: /* register_type(0x7f, Time, packer: proc-like, unapcker: proc-like) */ options = argv[2]; if(rb_type(options) != T_HASH) { rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options)); } packer_arg = rb_hash_aref(options, ID2SYM(rb_intern("packer"))); unpacker_arg = rb_hash_aref(options, ID2SYM(rb_intern("unpacker"))); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)", argc); } ext_type = NUM2INT(argv[0]); if(ext_type < -128 || ext_type > 127) { rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type); } ext_module = argv[1]; if(rb_type(ext_module) != T_MODULE && rb_type(ext_module) != T_CLASS) { rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module)); } packer_proc = Qnil; unpacker_proc = Qnil; if(packer_arg != Qnil) { packer_proc = rb_funcall(packer_arg, rb_intern("to_proc"), 0); } if(unpacker_arg != Qnil) { if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) { unpacker_proc = rb_obj_method(ext_module, unpacker_arg); } else { unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call"))); } } msgpack_packer_ext_registry_put(&fc->pkrg, ext_module, ext_type, packer_proc, packer_arg); if (ext_module == rb_cSymbol) { fc->has_symbol_ext_type = true; } msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, unpacker_proc, unpacker_arg); return Qnil; } void MessagePack_Factory_module_init(VALUE mMessagePack) { cMessagePack_Factory = rb_define_class_under(mMessagePack, "Factory", rb_cObject); rb_define_alloc_func(cMessagePack_Factory, Factory_alloc); rb_define_method(cMessagePack_Factory, "initialize", Factory_initialize, -1); rb_define_method(cMessagePack_Factory, "packer", MessagePack_Factory_packer, -1); rb_define_method(cMessagePack_Factory, "unpacker", MessagePack_Factory_unpacker, -1); rb_define_private_method(cMessagePack_Factory, "registered_types_internal", Factory_registered_types_internal, 0); rb_define_method(cMessagePack_Factory, "register_type", Factory_register_type, -1); } msgpack-1.4.2/ext/msgpack/packer_class.c0000644000004100000410000003151414021120706020213 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "compat.h" #include "ruby.h" #include "packer.h" #include "packer_class.h" #include "buffer_class.h" #include "factory_class.h" VALUE cMessagePack_Packer; static ID s_to_msgpack; static ID s_write; //static VALUE s_packer_value; //static msgpack_packer_t* s_packer; #define PACKER(from, name) \ msgpack_packer_t* name; \ Data_Get_Struct(from, msgpack_packer_t, name); \ if(name == NULL) { \ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \ } static void Packer_free(msgpack_packer_t* pk) { if(pk == NULL) { return; } msgpack_packer_ext_registry_destroy(&pk->ext_registry); msgpack_packer_destroy(pk); xfree(pk); } static void Packer_mark(msgpack_packer_t* pk) { msgpack_packer_mark(pk); msgpack_packer_ext_registry_mark(&pk->ext_registry); } VALUE MessagePack_Packer_alloc(VALUE klass) { msgpack_packer_t* pk = ZALLOC_N(msgpack_packer_t, 1); msgpack_packer_init(pk); VALUE self = Data_Wrap_Struct(klass, Packer_mark, Packer_free, pk); msgpack_packer_set_to_msgpack_method(pk, s_to_msgpack, self); return self; } VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self) { VALUE io = Qnil; VALUE options = Qnil; if(argc == 0 || (argc == 1 && argv[0] == Qnil)) { /* Qnil */ } else if(argc == 1) { VALUE v = argv[0]; if(rb_type(v) == T_HASH) { options = v; } else { io = v; } } else if(argc == 2) { io = argv[0]; options = argv[1]; if(rb_type(options) != T_HASH) { rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options)); } } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); } PACKER(self, pk); msgpack_packer_ext_registry_init(&pk->ext_registry); pk->buffer_ref = MessagePack_Buffer_wrap(PACKER_BUFFER_(pk), self); MessagePack_Buffer_set_options(PACKER_BUFFER_(pk), io, options); if(options != Qnil) { VALUE v; v = rb_hash_aref(options, ID2SYM(rb_intern("compatibility_mode"))); msgpack_packer_set_compat(pk, RTEST(v)); } return self; } static VALUE Packer_compatibility_mode_p(VALUE self) { PACKER(self, pk); return pk->compatibility_mode ? Qtrue : Qfalse; } static VALUE Packer_buffer(VALUE self) { PACKER(self, pk); return pk->buffer_ref; } static VALUE Packer_write(VALUE self, VALUE v) { PACKER(self, pk); msgpack_packer_write_value(pk, v); return self; } static VALUE Packer_write_nil(VALUE self) { PACKER(self, pk); msgpack_packer_write_nil(pk); return self; } static VALUE Packer_write_true(VALUE self) { PACKER(self, pk); msgpack_packer_write_true(pk); return self; } static VALUE Packer_write_false(VALUE self) { PACKER(self, pk); msgpack_packer_write_false(pk); return self; } static VALUE Packer_write_float(VALUE self, VALUE obj) { PACKER(self, pk); msgpack_packer_write_float_value(pk, obj); return self; } static VALUE Packer_write_string(VALUE self, VALUE obj) { PACKER(self, pk); Check_Type(obj, T_STRING); msgpack_packer_write_string_value(pk, obj); return self; } static VALUE Packer_write_bin(VALUE self, VALUE obj) { PACKER(self, pk); Check_Type(obj, T_STRING); VALUE enc = rb_enc_from_encoding(rb_ascii8bit_encoding()); obj = rb_str_encode(obj, enc, 0, Qnil); msgpack_packer_write_string_value(pk, obj); return self; } static VALUE Packer_write_array(VALUE self, VALUE obj) { PACKER(self, pk); Check_Type(obj, T_ARRAY); msgpack_packer_write_array_value(pk, obj); return self; } static VALUE Packer_write_hash(VALUE self, VALUE obj) { PACKER(self, pk); Check_Type(obj, T_HASH); msgpack_packer_write_hash_value(pk, obj); return self; } static VALUE Packer_write_symbol(VALUE self, VALUE obj) { PACKER(self, pk); Check_Type(obj, T_SYMBOL); msgpack_packer_write_symbol_value(pk, obj); return self; } static VALUE Packer_write_int(VALUE self, VALUE obj) { PACKER(self, pk); if (FIXNUM_P(obj)) { msgpack_packer_write_fixnum_value(pk, obj); } else { Check_Type(obj, T_BIGNUM); msgpack_packer_write_bignum_value(pk, obj); } return self; } static VALUE Packer_write_extension(VALUE self, VALUE obj) { PACKER(self, pk); Check_Type(obj, T_STRUCT); int ext_type = FIX2INT(RSTRUCT_GET(obj, 0)); if(ext_type < -128 || ext_type > 127) { rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type); } VALUE payload = RSTRUCT_GET(obj, 1); StringValue(payload); msgpack_packer_write_ext(pk, ext_type, payload); return self; } static VALUE Packer_write_array_header(VALUE self, VALUE n) { PACKER(self, pk); msgpack_packer_write_array_header(pk, NUM2UINT(n)); return self; } static VALUE Packer_write_map_header(VALUE self, VALUE n) { PACKER(self, pk); msgpack_packer_write_map_header(pk, NUM2UINT(n)); return self; } static VALUE Packer_write_bin_header(VALUE self, VALUE n) { PACKER(self, pk); msgpack_packer_write_bin_header(pk, NUM2UINT(n)); return self; } static VALUE Packer_write_float32(VALUE self, VALUE numeric) { if(!rb_obj_is_kind_of(numeric, rb_cNumeric)) { rb_raise(rb_eArgError, "Expected numeric"); } PACKER(self, pk); msgpack_packer_write_float(pk, (float)rb_num2dbl(numeric)); return self; } static VALUE Packer_write_ext(VALUE self, VALUE type, VALUE data) { PACKER(self, pk); int ext_type = NUM2INT(type); if(ext_type < -128 || ext_type > 127) { rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type); } StringValue(data); msgpack_packer_write_ext(pk, ext_type, data); return self; } static VALUE Packer_flush(VALUE self) { PACKER(self, pk); msgpack_buffer_flush(PACKER_BUFFER_(pk)); return self; } static VALUE Packer_clear(VALUE self) { PACKER(self, pk); msgpack_buffer_clear(PACKER_BUFFER_(pk)); return Qnil; } static VALUE Packer_size(VALUE self) { PACKER(self, pk); size_t size = msgpack_buffer_all_readable_size(PACKER_BUFFER_(pk)); return SIZET2NUM(size); } static VALUE Packer_empty_p(VALUE self) { PACKER(self, pk); if(msgpack_buffer_top_readable_size(PACKER_BUFFER_(pk)) == 0) { return Qtrue; } else { return Qfalse; } } static VALUE Packer_to_str(VALUE self) { PACKER(self, pk); return msgpack_buffer_all_as_string(PACKER_BUFFER_(pk)); } static VALUE Packer_to_a(VALUE self) { PACKER(self, pk); return msgpack_buffer_all_as_string_array(PACKER_BUFFER_(pk)); } static VALUE Packer_write_to(VALUE self, VALUE io) { PACKER(self, pk); size_t sz = msgpack_buffer_flush_to_io(PACKER_BUFFER_(pk), io, s_write, true); return ULONG2NUM(sz); } //static VALUE Packer_append(VALUE self, VALUE string_or_buffer) //{ // PACKER(self, pk); // // // TODO if string_or_buffer is a Buffer // VALUE string = string_or_buffer; // // msgpack_buffer_append_string(PACKER_BUFFER_(pk), string); // // return self; //} static VALUE Packer_registered_types_internal(VALUE self) { PACKER(self, pk); #ifdef HAVE_RB_HASH_DUP return rb_hash_dup(pk->ext_registry.hash); #else return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0); #endif } static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self) { PACKER(self, pk); int ext_type; VALUE ext_module; VALUE proc; VALUE arg; switch (argc) { case 2: /* register_type(0x7f, Time) {|obj| block... } */ rb_need_block(); #ifdef HAVE_RB_BLOCK_LAMBDA proc = rb_block_lambda(); #else /* MRI 1.8 */ proc = rb_block_proc(); #endif arg = proc; break; case 3: /* register_type(0x7f, Time, :to_msgpack_ext) */ arg = argv[2]; proc = rb_funcall(arg, rb_intern("to_proc"), 0); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)", argc); } ext_type = NUM2INT(argv[0]); if(ext_type < -128 || ext_type > 127) { rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type); } ext_module = argv[1]; if(rb_type(ext_module) != T_MODULE && rb_type(ext_module) != T_CLASS) { rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module)); } msgpack_packer_ext_registry_put(&pk->ext_registry, ext_module, ext_type, proc, arg); if (ext_module == rb_cSymbol) { pk->has_symbol_ext_type = true; } return Qnil; } VALUE Packer_full_pack(VALUE self) { VALUE retval; PACKER(self, pk); if(msgpack_buffer_has_io(PACKER_BUFFER_(pk))) { msgpack_buffer_flush(PACKER_BUFFER_(pk)); retval = Qnil; } else { retval = msgpack_buffer_all_as_string(PACKER_BUFFER_(pk)); } msgpack_buffer_clear(PACKER_BUFFER_(pk)); /* to free rmem before GC */ return retval; } void MessagePack_Packer_module_init(VALUE mMessagePack) { s_to_msgpack = rb_intern("to_msgpack"); s_write = rb_intern("write"); msgpack_packer_static_init(); msgpack_packer_ext_registry_static_init(); cMessagePack_Packer = rb_define_class_under(mMessagePack, "Packer", rb_cObject); rb_define_alloc_func(cMessagePack_Packer, MessagePack_Packer_alloc); rb_define_method(cMessagePack_Packer, "initialize", MessagePack_Packer_initialize, -1); rb_define_method(cMessagePack_Packer, "compatibility_mode?", Packer_compatibility_mode_p, 0); rb_define_method(cMessagePack_Packer, "buffer", Packer_buffer, 0); rb_define_method(cMessagePack_Packer, "write", Packer_write, 1); rb_define_alias(cMessagePack_Packer, "pack", "write"); rb_define_method(cMessagePack_Packer, "write_nil", Packer_write_nil, 0); rb_define_method(cMessagePack_Packer, "write_true", Packer_write_true, 0); rb_define_method(cMessagePack_Packer, "write_false", Packer_write_false, 0); rb_define_method(cMessagePack_Packer, "write_float", Packer_write_float, 1); rb_define_method(cMessagePack_Packer, "write_string", Packer_write_string, 1); rb_define_method(cMessagePack_Packer, "write_bin", Packer_write_bin, 1); rb_define_method(cMessagePack_Packer, "write_array", Packer_write_array, 1); rb_define_method(cMessagePack_Packer, "write_hash", Packer_write_hash, 1); rb_define_method(cMessagePack_Packer, "write_symbol", Packer_write_symbol, 1); rb_define_method(cMessagePack_Packer, "write_int", Packer_write_int, 1); rb_define_method(cMessagePack_Packer, "write_extension", Packer_write_extension, 1); rb_define_method(cMessagePack_Packer, "write_array_header", Packer_write_array_header, 1); rb_define_method(cMessagePack_Packer, "write_map_header", Packer_write_map_header, 1); rb_define_method(cMessagePack_Packer, "write_bin_header", Packer_write_bin_header, 1); rb_define_method(cMessagePack_Packer, "write_ext", Packer_write_ext, 2); rb_define_method(cMessagePack_Packer, "write_float32", Packer_write_float32, 1); rb_define_method(cMessagePack_Packer, "flush", Packer_flush, 0); /* delegation methods */ rb_define_method(cMessagePack_Packer, "clear", Packer_clear, 0); rb_define_method(cMessagePack_Packer, "size", Packer_size, 0); rb_define_method(cMessagePack_Packer, "empty?", Packer_empty_p, 0); rb_define_method(cMessagePack_Packer, "write_to", Packer_write_to, 1); rb_define_method(cMessagePack_Packer, "to_str", Packer_to_str, 0); rb_define_alias(cMessagePack_Packer, "to_s", "to_str"); rb_define_method(cMessagePack_Packer, "to_a", Packer_to_a, 0); //rb_define_method(cMessagePack_Packer, "append", Packer_append, 1); //rb_define_alias(cMessagePack_Packer, "<<", "append"); rb_define_private_method(cMessagePack_Packer, "registered_types_internal", Packer_registered_types_internal, 0); rb_define_method(cMessagePack_Packer, "register_type", Packer_register_type, -1); //s_packer_value = MessagePack_Packer_alloc(cMessagePack_Packer); //rb_gc_register_address(&s_packer_value); //Data_Get_Struct(s_packer_value, msgpack_packer_t, s_packer); rb_define_method(cMessagePack_Packer, "full_pack", Packer_full_pack, 0); } msgpack-1.4.2/ext/msgpack/extension_value_class.h0000644000004100000410000000173214021120706022162 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2015 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_EXTENSION_VALUE_CLASS_H__ #define MSGPACK_RUBY_EXTENSION_VALUE_CLASS_H__ #include "compat.h" #include "sysdep.h" extern VALUE cMessagePack_ExtensionValue; VALUE MessagePack_ExtensionValue_new(int ext_type, VALUE payload); void MessagePack_ExtensionValue_module_init(VALUE mMessagePack); #endif msgpack-1.4.2/ext/msgpack/packer.h0000644000004100000410000004151614021120706017036 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_PACKER_H__ #define MSGPACK_RUBY_PACKER_H__ #include "buffer.h" #include "packer_ext_registry.h" #ifndef MSGPACK_PACKER_IO_FLUSH_THRESHOLD_TO_WRITE_STRING_BODY #define MSGPACK_PACKER_IO_FLUSH_THRESHOLD_TO_WRITE_STRING_BODY (1024) #endif struct msgpack_packer_t; typedef struct msgpack_packer_t msgpack_packer_t; struct msgpack_packer_t { msgpack_buffer_t buffer; bool compatibility_mode; bool has_symbol_ext_type; ID to_msgpack_method; VALUE to_msgpack_arg; VALUE buffer_ref; /* options */ bool comaptibility_mode; msgpack_packer_ext_registry_t ext_registry; }; #define PACKER_BUFFER_(pk) (&(pk)->buffer) void msgpack_packer_static_init(); void msgpack_packer_static_destroy(); void msgpack_packer_init(msgpack_packer_t* pk); void msgpack_packer_destroy(msgpack_packer_t* pk); void msgpack_packer_mark(msgpack_packer_t* pk); static inline void msgpack_packer_set_to_msgpack_method(msgpack_packer_t* pk, ID to_msgpack_method, VALUE to_msgpack_arg) { pk->to_msgpack_method = to_msgpack_method; pk->to_msgpack_arg = to_msgpack_arg; } void msgpack_packer_reset(msgpack_packer_t* pk); static inline void msgpack_packer_set_compat(msgpack_packer_t* pk, bool enable) { pk->compatibility_mode = enable; } static inline void msgpack_packer_write_nil(msgpack_packer_t* pk) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); msgpack_buffer_write_1(PACKER_BUFFER_(pk), 0xc0); } static inline void msgpack_packer_write_true(msgpack_packer_t* pk) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); msgpack_buffer_write_1(PACKER_BUFFER_(pk), 0xc3); } static inline void msgpack_packer_write_false(msgpack_packer_t* pk) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); msgpack_buffer_write_1(PACKER_BUFFER_(pk), 0xc2); } static inline void _msgpack_packer_write_fixint(msgpack_packer_t* pk, int8_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); msgpack_buffer_write_1(PACKER_BUFFER_(pk), v); } static inline void _msgpack_packer_write_uint8(msgpack_packer_t* pk, uint8_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xcc, v); } static inline void _msgpack_packer_write_uint16(msgpack_packer_t* pk, uint16_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); uint16_t be = _msgpack_be16(v); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xcd, (const void*)&be, 2); } static inline void _msgpack_packer_write_uint32(msgpack_packer_t* pk, uint32_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); uint32_t be = _msgpack_be32(v); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xce, (const void*)&be, 4); } static inline void _msgpack_packer_write_uint64(msgpack_packer_t* pk, uint64_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 9); uint64_t be = _msgpack_be64(v); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xcf, (const void*)&be, 8); } static inline void _msgpack_packer_write_int8(msgpack_packer_t* pk, int8_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd0, v); } static inline void _msgpack_packer_write_int16(msgpack_packer_t* pk, int16_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); uint16_t be = _msgpack_be16(v); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xd1, (const void*)&be, 2); } static inline void _msgpack_packer_write_int32(msgpack_packer_t* pk, int32_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); uint32_t be = _msgpack_be32(v); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xd2, (const void*)&be, 4); } static inline void _msgpack_packer_write_int64(msgpack_packer_t* pk, int64_t v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 9); uint64_t be = _msgpack_be64(v); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xd3, (const void*)&be, 8); } static inline void _msgpack_packer_write_long32(msgpack_packer_t* pk, long v) { if(v < -0x20L) { if(v < -0x8000L) { _msgpack_packer_write_int32(pk, (int32_t) v); } else if(v < -0x80L) { _msgpack_packer_write_int16(pk, (int16_t) v); } else { _msgpack_packer_write_int8(pk, (int8_t) v); } } else if(v <= 0x7fL) { _msgpack_packer_write_fixint(pk, (int8_t) v); } else { if(v <= 0xffL) { _msgpack_packer_write_uint8(pk, (uint8_t) v); } else if(v <= 0xffffL) { _msgpack_packer_write_uint16(pk, (uint16_t) v); } else { _msgpack_packer_write_uint32(pk, (uint32_t) v); } } } static inline void _msgpack_packer_write_long_long64(msgpack_packer_t* pk, long long v) { if(v < -0x20LL) { if(v < -0x8000LL) { if(v < -0x80000000LL) { _msgpack_packer_write_int64(pk, (int64_t) v); } else { _msgpack_packer_write_int32(pk, (int32_t) v); } } else { if(v < -0x80LL) { _msgpack_packer_write_int16(pk, (int16_t) v); } else { _msgpack_packer_write_int8(pk, (int8_t) v); } } } else if(v <= 0x7fLL) { _msgpack_packer_write_fixint(pk, (int8_t) v); } else { if(v <= 0xffffLL) { if(v <= 0xffLL) { _msgpack_packer_write_uint8(pk, (uint8_t) v); } else { _msgpack_packer_write_uint16(pk, (uint16_t) v); } } else { if(v <= 0xffffffffLL) { _msgpack_packer_write_uint32(pk, (uint32_t) v); } else { _msgpack_packer_write_uint64(pk, (uint64_t) v); } } } } static inline void msgpack_packer_write_long(msgpack_packer_t* pk, long v) { #if defined(SIZEOF_LONG) # if SIZEOF_LONG <= 4 _msgpack_packer_write_long32(pk, v); # else _msgpack_packer_write_long_long64(pk, v); # endif #elif defined(LONG_MAX) # if LONG_MAX <= 0x7fffffffL _msgpack_packer_write_long32(pk, v); # else _msgpack_packer_write_long_long64(pk, v); # endif #else if(sizeof(long) <= 4) { _msgpack_packer_write_long32(pk, v); } else { _msgpack_packer_write_long_long64(pk, v); } #endif } static inline void msgpack_packer_write_long_long(msgpack_packer_t* pk, long long v) { /* assuming sizeof(long long) == 8 */ _msgpack_packer_write_long_long64(pk, v); } static inline void msgpack_packer_write_u64(msgpack_packer_t* pk, uint64_t v) { if(v <= 0xffULL) { if(v <= 0x7fULL) { _msgpack_packer_write_fixint(pk, (int8_t) v); } else { _msgpack_packer_write_uint8(pk, (uint8_t) v); } } else { if(v <= 0xffffULL) { _msgpack_packer_write_uint16(pk, (uint16_t) v); } else if(v <= 0xffffffffULL) { _msgpack_packer_write_uint32(pk, (uint32_t) v); } else { _msgpack_packer_write_uint64(pk, (uint64_t) v); } } } static inline void msgpack_packer_write_float(msgpack_packer_t* pk, float v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); union { float f; uint32_t u32; char mem[4]; } castbuf = { v }; castbuf.u32 = _msgpack_be_float(castbuf.u32); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xca, castbuf.mem, 4); } static inline void msgpack_packer_write_double(msgpack_packer_t* pk, double v) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 9); union { double d; uint64_t u64; char mem[8]; } castbuf = { v }; castbuf.u64 = _msgpack_be_double(castbuf.u64); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xcb, castbuf.mem, 8); } static inline void msgpack_packer_write_raw_header(msgpack_packer_t* pk, unsigned int n) { if(n < 32) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); unsigned char h = 0xa0 | (uint8_t) n; msgpack_buffer_write_1(PACKER_BUFFER_(pk), h); } else if(n < 256 && !pk->compatibility_mode) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); unsigned char be = (uint8_t) n; msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xd9, (const void*)&be, 1); } else if(n < 65536) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); uint16_t be = _msgpack_be16(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xda, (const void*)&be, 2); } else { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); uint32_t be = _msgpack_be32(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xdb, (const void*)&be, 4); } } static inline void msgpack_packer_write_bin_header(msgpack_packer_t* pk, unsigned int n) { if(n < 256) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); unsigned char be = (uint8_t) n; msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc4, (const void*)&be, 1); } else if(n < 65536) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); uint16_t be = _msgpack_be16(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc5, (const void*)&be, 2); } else { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); uint32_t be = _msgpack_be32(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc6, (const void*)&be, 4); } } static inline void msgpack_packer_write_array_header(msgpack_packer_t* pk, unsigned int n) { if(n < 16) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); unsigned char h = 0x90 | (uint8_t) n; msgpack_buffer_write_1(PACKER_BUFFER_(pk), h); } else if(n < 65536) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); uint16_t be = _msgpack_be16(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xdc, (const void*)&be, 2); } else { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); uint32_t be = _msgpack_be32(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xdd, (const void*)&be, 4); } } static inline void msgpack_packer_write_map_header(msgpack_packer_t* pk, unsigned int n) { if(n < 16) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1); unsigned char h = 0x80 | (uint8_t) n; msgpack_buffer_write_1(PACKER_BUFFER_(pk), h); } else if(n < 65536) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); uint16_t be = _msgpack_be16(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xde, (const void*)&be, 2); } else { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 5); uint32_t be = _msgpack_be32(n); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xdf, (const void*)&be, 4); } } static inline void msgpack_packer_write_ext(msgpack_packer_t* pk, int ext_type, VALUE payload) { unsigned long len = RSTRING_LEN(payload); switch (len) { case 1: msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd4, ext_type); break; case 2: msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd5, ext_type); break; case 4: msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd6, ext_type); break; case 8: msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd7, ext_type); break; case 16: msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd8, ext_type); break; default: if(len < 256) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3); msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xc7, len); msgpack_buffer_write_1(PACKER_BUFFER_(pk), ext_type); } else if(len < 65536) { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 4); uint16_t be = _msgpack_be16(len); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc8, (const void*)&be, 2); msgpack_buffer_write_1(PACKER_BUFFER_(pk), ext_type); } else { msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 6); uint32_t be = _msgpack_be32(len); msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc9, (const void*)&be, 4); msgpack_buffer_write_1(PACKER_BUFFER_(pk), ext_type); } } msgpack_buffer_append_string(PACKER_BUFFER_(pk), payload); } static inline bool msgpack_packer_is_binary(VALUE v, int encindex) { return encindex == msgpack_rb_encindex_ascii8bit; } static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex) { return encindex == msgpack_rb_encindex_utf8 || encindex == msgpack_rb_encindex_usascii #ifdef ENC_CODERANGE_ASCIIONLY /* Because ENC_CODERANGE_ASCIIONLY does not scan string, it may return ENC_CODERANGE_UNKNOWN unlike */ /* rb_enc_str_asciionly_p. It is always faster than rb_str_encode if it is available. */ /* Very old Rubinius (< v1.3.1) doesn't have ENC_CODERANGE_ASCIIONLY. */ || (rb_enc_asciicompat(rb_enc_from_index(encindex)) && ENC_CODERANGE_ASCIIONLY(v)) #endif ; } static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v) { /* actual return type of RSTRING_LEN is long */ unsigned long len = RSTRING_LEN(v); if(len > 0xffffffffUL) { // TODO rb_eArgError? rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL); } int encindex = ENCODING_GET(v); if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) { /* write ASCII-8BIT string using Binary type */ msgpack_packer_write_bin_header(pk, (unsigned int)len); msgpack_buffer_append_string(PACKER_BUFFER_(pk), v); } else { /* write UTF-8, US-ASCII, or 7bit-safe ascii-compatible string using String type directly */ /* in compatibility mode, packer packs String values as is */ if(!pk->compatibility_mode && !msgpack_packer_is_utf8_compat_string(v, encindex)) { /* transcode other strings to UTF-8 and write using String type */ VALUE enc = rb_enc_from_encoding(rb_utf8_encoding()); /* rb_enc_from_encoding_index is not extern */ v = rb_str_encode(v, enc, 0, Qnil); len = RSTRING_LEN(v); } msgpack_packer_write_raw_header(pk, (unsigned int)len); msgpack_buffer_append_string(PACKER_BUFFER_(pk), v); } } static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v) { #ifdef HAVE_RB_SYM2STR /* rb_sym2str is added since MRI 2.2.0 */ msgpack_packer_write_string_value(pk, rb_sym2str(v)); #else VALUE str = rb_id2str(SYM2ID(v)); if (!str) { rb_raise(rb_eRuntimeError, "could not convert a symbol to string"); } msgpack_packer_write_string_value(pk, str); #endif } void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v); static inline void msgpack_packer_write_symbol_value(msgpack_packer_t* pk, VALUE v) { if (pk->has_symbol_ext_type) { msgpack_packer_write_other_value(pk, v); } else { msgpack_packer_write_symbol_string_value(pk, v); } } static inline void msgpack_packer_write_fixnum_value(msgpack_packer_t* pk, VALUE v) { #ifdef JRUBY msgpack_packer_write_long(pk, FIXNUM_P(v) ? FIX2LONG(v) : rb_num2ll(v)); #else msgpack_packer_write_long(pk, FIX2LONG(v)); #endif } static inline void msgpack_packer_write_bignum_value(msgpack_packer_t* pk, VALUE v) { if(RBIGNUM_POSITIVE_P(v)) { msgpack_packer_write_u64(pk, rb_big2ull(v)); } else { msgpack_packer_write_long_long(pk, rb_big2ll(v)); } } static inline void msgpack_packer_write_float_value(msgpack_packer_t* pk, VALUE v) { msgpack_packer_write_double(pk, rb_num2dbl(v)); } void msgpack_packer_write_array_value(msgpack_packer_t* pk, VALUE v); void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v); void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v); #endif msgpack-1.4.2/ext/msgpack/unpacker_class.c0000644000004100000410000003144614021120706020562 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "unpacker.h" #include "unpacker_class.h" #include "buffer_class.h" #include "factory_class.h" VALUE cMessagePack_Unpacker; //static VALUE s_unpacker_value; //static msgpack_unpacker_t* s_unpacker; static VALUE eUnpackError; static VALUE eMalformedFormatError; static VALUE eStackError; static VALUE eUnexpectedTypeError; static VALUE eUnknownExtTypeError; static VALUE mTypeError; // obsoleted. only for backward compatibility. See #86. #define UNPACKER(from, name) \ msgpack_unpacker_t *name = NULL; \ Data_Get_Struct(from, msgpack_unpacker_t, name); \ if(name == NULL) { \ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \ } static void Unpacker_free(msgpack_unpacker_t* uk) { if(uk == NULL) { return; } msgpack_unpacker_ext_registry_destroy(&uk->ext_registry); _msgpack_unpacker_destroy(uk); xfree(uk); } static void Unpacker_mark(msgpack_unpacker_t* uk) { msgpack_unpacker_mark(uk); msgpack_unpacker_ext_registry_mark(&uk->ext_registry); } VALUE MessagePack_Unpacker_alloc(VALUE klass) { msgpack_unpacker_t* uk = ZALLOC_N(msgpack_unpacker_t, 1); _msgpack_unpacker_init(uk); VALUE self = Data_Wrap_Struct(klass, Unpacker_mark, Unpacker_free, uk); return self; } VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self) { VALUE io = Qnil; VALUE options = Qnil; if(argc == 0 || (argc == 1 && argv[0] == Qnil)) { /* Qnil */ } else if(argc == 1) { VALUE v = argv[0]; if(rb_type(v) == T_HASH) { options = v; } else { io = v; } } else if(argc == 2) { io = argv[0]; options = argv[1]; if(rb_type(options) != T_HASH) { rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options)); } } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); } UNPACKER(self, uk); msgpack_unpacker_ext_registry_init(&uk->ext_registry); uk->buffer_ref = MessagePack_Buffer_wrap(UNPACKER_BUFFER_(uk), self); MessagePack_Buffer_set_options(UNPACKER_BUFFER_(uk), io, options); if(options != Qnil) { VALUE v; v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys"))); msgpack_unpacker_set_symbolized_keys(uk, RTEST(v)); v = rb_hash_aref(options, ID2SYM(rb_intern("freeze"))); msgpack_unpacker_set_freeze(uk, RTEST(v)); v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext"))); msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v)); } return self; } static VALUE Unpacker_symbolized_keys_p(VALUE self) { UNPACKER(self, uk); return uk->symbolize_keys ? Qtrue : Qfalse; } static VALUE Unpacker_freeze_p(VALUE self) { UNPACKER(self, uk); return uk->freeze ? Qtrue : Qfalse; } static VALUE Unpacker_allow_unknown_ext_p(VALUE self) { UNPACKER(self, uk); return uk->allow_unknown_ext ? Qtrue : Qfalse; } static void raise_unpacker_error(int r) { switch(r) { case PRIMITIVE_EOF: rb_raise(rb_eEOFError, "end of buffer reached"); case PRIMITIVE_INVALID_BYTE: rb_raise(eMalformedFormatError, "invalid byte"); case PRIMITIVE_STACK_TOO_DEEP: rb_raise(eStackError, "stack level too deep"); case PRIMITIVE_UNEXPECTED_TYPE: rb_raise(eUnexpectedTypeError, "unexpected type"); case PRIMITIVE_UNEXPECTED_EXT_TYPE: rb_raise(eUnknownExtTypeError, "unexpected extension type"); default: rb_raise(eUnpackError, "logically unknown error %d", r); } } static VALUE Unpacker_buffer(VALUE self) { UNPACKER(self, uk); return uk->buffer_ref; } static VALUE Unpacker_read(VALUE self) { UNPACKER(self, uk); int r = msgpack_unpacker_read(uk, 0); if(r < 0) { raise_unpacker_error(r); } return msgpack_unpacker_get_last_object(uk); } static VALUE Unpacker_skip(VALUE self) { UNPACKER(self, uk); int r = msgpack_unpacker_skip(uk, 0); if(r < 0) { raise_unpacker_error(r); } return Qnil; } static VALUE Unpacker_skip_nil(VALUE self) { UNPACKER(self, uk); int r = msgpack_unpacker_skip_nil(uk); if(r < 0) { raise_unpacker_error(r); } if(r) { return Qtrue; } return Qfalse; } static VALUE Unpacker_read_array_header(VALUE self) { UNPACKER(self, uk); uint32_t size; int r = msgpack_unpacker_read_array_header(uk, &size); if(r < 0) { raise_unpacker_error(r); } return ULONG2NUM(size); } static VALUE Unpacker_read_map_header(VALUE self) { UNPACKER(self, uk); uint32_t size; int r = msgpack_unpacker_read_map_header(uk, &size); if(r < 0) { raise_unpacker_error((int)r); } return ULONG2NUM(size); } static VALUE Unpacker_peek_next_type(VALUE self) { UNPACKER(self, uk); int r = msgpack_unpacker_peek_next_object_type(uk); if(r < 0) { raise_unpacker_error(r); } switch((enum msgpack_unpacker_object_type) r) { case TYPE_NIL: return rb_intern("nil"); case TYPE_BOOLEAN: return rb_intern("boolean"); case TYPE_INTEGER: return rb_intern("integer"); case TYPE_FLOAT: return rb_intern("float"); case TYPE_RAW: return rb_intern("raw"); case TYPE_ARRAY: return rb_intern("array"); case TYPE_MAP: return rb_intern("map"); default: rb_raise(eUnpackError, "logically unknown type %d", r); } } static VALUE Unpacker_feed(VALUE self, VALUE data) { UNPACKER(self, uk); StringValue(data); msgpack_buffer_append_string(UNPACKER_BUFFER_(uk), data); return self; } static VALUE Unpacker_feed_reference(VALUE self, VALUE data) { UNPACKER(self, uk); StringValue(data); msgpack_buffer_append_string_reference(UNPACKER_BUFFER_(uk), data); return self; } static VALUE Unpacker_each_impl(VALUE self) { UNPACKER(self, uk); while(true) { int r = msgpack_unpacker_read(uk, 0); if(r < 0) { if(r == PRIMITIVE_EOF) { return Qnil; } raise_unpacker_error(r); } VALUE v = msgpack_unpacker_get_last_object(uk); #ifdef JRUBY /* TODO JRuby's rb_yield behaves differently from Ruby 1.9.3 or Rubinius. */ if(rb_type(v) == T_ARRAY) { v = rb_ary_new3(1, v); } #endif rb_yield(v); } } static VALUE Unpacker_rescue_EOFError(VALUE self) { UNUSED(self); return Qnil; } static VALUE Unpacker_each(VALUE self) { UNPACKER(self, uk); #ifdef RETURN_ENUMERATOR RETURN_ENUMERATOR(self, 0, 0); #endif if(msgpack_buffer_has_io(UNPACKER_BUFFER_(uk))) { /* rescue EOFError only if io is set */ return rb_rescue2(Unpacker_each_impl, self, Unpacker_rescue_EOFError, self, rb_eEOFError, NULL); } else { return Unpacker_each_impl(self); } } static VALUE Unpacker_feed_each(VALUE self, VALUE data) { #ifdef RETURN_ENUMERATOR { VALUE argv[] = { data }; RETURN_ENUMERATOR(self, sizeof(argv) / sizeof(VALUE), argv); } #endif Unpacker_feed_reference(self, data); return Unpacker_each(self); } static VALUE Unpacker_reset(VALUE self) { UNPACKER(self, uk); _msgpack_unpacker_reset(uk); return Qnil; } static VALUE Unpacker_registered_types_internal(VALUE self) { UNPACKER(self, uk); VALUE mapping = rb_hash_new(); for(int i=0; i < 256; i++) { if(uk->ext_registry.array[i] != Qnil) { rb_hash_aset(mapping, INT2FIX(i - 128), uk->ext_registry.array[i]); } } return mapping; } static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self) { UNPACKER(self, uk); int ext_type; VALUE proc; VALUE arg; VALUE ext_module; switch (argc) { case 1: /* register_type(0x7f) {|data| block... } */ rb_need_block(); #ifdef HAVE_RB_BLOCK_LAMBDA proc = rb_block_lambda(); #else /* MRI 1.8 */ proc = rb_block_proc(); #endif arg = proc; ext_module = Qnil; break; case 3: /* register_type(0x7f, Time, :from_msgpack_ext) */ ext_module = argv[1]; arg = argv[2]; proc = rb_obj_method(ext_module, arg); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 3)", argc); } ext_type = NUM2INT(argv[0]); if(ext_type < -128 || ext_type > 127) { rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type); } msgpack_unpacker_ext_registry_put(&uk->ext_registry, ext_module, ext_type, proc, arg); return Qnil; } static VALUE Unpacker_full_unpack(VALUE self) { UNPACKER(self, uk); int r = msgpack_unpacker_read(uk, 0); if(r < 0) { raise_unpacker_error(r); } /* raise if extra bytes follow */ size_t extra = msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk)); if(extra > 0) { rb_raise(eMalformedFormatError, "%zd extra bytes after the deserialized object", extra); } return msgpack_unpacker_get_last_object(uk); } VALUE MessagePack_Unpacker_new(int argc, VALUE* argv) { VALUE self = MessagePack_Unpacker_alloc(cMessagePack_Unpacker); MessagePack_Unpacker_initialize(argc, argv, self); return self; } void MessagePack_Unpacker_module_init(VALUE mMessagePack) { msgpack_unpacker_static_init(); msgpack_unpacker_ext_registry_static_init(); mTypeError = rb_define_module_under(mMessagePack, "TypeError"); cMessagePack_Unpacker = rb_define_class_under(mMessagePack, "Unpacker", rb_cObject); eUnpackError = rb_define_class_under(mMessagePack, "UnpackError", rb_eStandardError); eMalformedFormatError = rb_define_class_under(mMessagePack, "MalformedFormatError", eUnpackError); eStackError = rb_define_class_under(mMessagePack, "StackError", eUnpackError); eUnexpectedTypeError = rb_define_class_under(mMessagePack, "UnexpectedTypeError", eUnpackError); rb_include_module(eUnexpectedTypeError, mTypeError); eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError); rb_define_alloc_func(cMessagePack_Unpacker, MessagePack_Unpacker_alloc); rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1); rb_define_method(cMessagePack_Unpacker, "symbolize_keys?", Unpacker_symbolized_keys_p, 0); rb_define_method(cMessagePack_Unpacker, "freeze?", Unpacker_freeze_p, 0); rb_define_method(cMessagePack_Unpacker, "allow_unknown_ext?", Unpacker_allow_unknown_ext_p, 0); rb_define_method(cMessagePack_Unpacker, "buffer", Unpacker_buffer, 0); rb_define_method(cMessagePack_Unpacker, "read", Unpacker_read, 0); rb_define_alias(cMessagePack_Unpacker, "unpack", "read"); rb_define_method(cMessagePack_Unpacker, "skip", Unpacker_skip, 0); rb_define_method(cMessagePack_Unpacker, "skip_nil", Unpacker_skip_nil, 0); rb_define_method(cMessagePack_Unpacker, "read_array_header", Unpacker_read_array_header, 0); rb_define_method(cMessagePack_Unpacker, "read_map_header", Unpacker_read_map_header, 0); //rb_define_method(cMessagePack_Unpacker, "peek_next_type", Unpacker_peek_next_type, 0); // TODO rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed, 1); rb_define_method(cMessagePack_Unpacker, "feed_reference", Unpacker_feed_reference, 1); rb_define_method(cMessagePack_Unpacker, "each", Unpacker_each, 0); rb_define_method(cMessagePack_Unpacker, "feed_each", Unpacker_feed_each, 1); rb_define_method(cMessagePack_Unpacker, "reset", Unpacker_reset, 0); rb_define_private_method(cMessagePack_Unpacker, "registered_types_internal", Unpacker_registered_types_internal, 0); rb_define_method(cMessagePack_Unpacker, "register_type", Unpacker_register_type, -1); //s_unpacker_value = MessagePack_Unpacker_alloc(cMessagePack_Unpacker); //rb_gc_register_address(&s_unpacker_value); //Data_Get_Struct(s_unpacker_value, msgpack_unpacker_t, s_unpacker); /* prefer reference than copying */ //msgpack_buffer_set_write_reference_threshold(UNPACKER_BUFFER_(s_unpacker), 0); rb_define_method(cMessagePack_Unpacker, "full_unpack", Unpacker_full_unpack, 0); } msgpack-1.4.2/ext/msgpack/extension_value_class.c0000644000004100000410000000241714021120706022156 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "factory_class.h" VALUE cMessagePack_ExtensionValue; VALUE MessagePack_ExtensionValue_new(int ext_type, VALUE payload) { return rb_struct_new(cMessagePack_ExtensionValue, INT2FIX(ext_type), payload); } void MessagePack_ExtensionValue_module_init(VALUE mMessagePack) { /* rb_struct_define_under is not available ruby < 2.1 */ //cMessagePack_ExtensionValue = rb_struct_define_under(mMessagePack, "ExtensionValue", "type", "payload", NULL); cMessagePack_ExtensionValue = rb_struct_define(NULL, "type", "payload", NULL); rb_define_const(mMessagePack, "ExtensionValue", cMessagePack_ExtensionValue); } msgpack-1.4.2/ext/msgpack/packer.c0000644000004100000410000001120314021120706017017 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "packer.h" #ifdef RUBINIUS static ID s_to_iter; static ID s_next; static ID s_key; static ID s_value; #endif static ID s_call; void msgpack_packer_static_init() { #ifdef RUBINIUS s_to_iter = rb_intern("to_iter"); s_next = rb_intern("next"); s_key = rb_intern("key"); s_value = rb_intern("value"); #endif s_call = rb_intern("call"); } void msgpack_packer_static_destroy() { } void msgpack_packer_init(msgpack_packer_t* pk) { memset(pk, 0, sizeof(msgpack_packer_t)); msgpack_buffer_init(PACKER_BUFFER_(pk)); } void msgpack_packer_destroy(msgpack_packer_t* pk) { msgpack_buffer_destroy(PACKER_BUFFER_(pk)); } void msgpack_packer_mark(msgpack_packer_t* pk) { /* See MessagePack_Buffer_wrap */ /* msgpack_buffer_mark(PACKER_BUFFER_(pk)); */ rb_gc_mark(pk->buffer_ref); } void msgpack_packer_reset(msgpack_packer_t* pk) { msgpack_buffer_clear(PACKER_BUFFER_(pk)); pk->buffer_ref = Qnil; } void msgpack_packer_write_array_value(msgpack_packer_t* pk, VALUE v) { /* actual return type of RARRAY_LEN is long */ unsigned long len = RARRAY_LEN(v); if(len > 0xffffffffUL) { rb_raise(rb_eArgError, "size of array is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL); } unsigned int len32 = (unsigned int)len; msgpack_packer_write_array_header(pk, len32); unsigned int i; for(i=0; i < len32; ++i) { VALUE e = rb_ary_entry(v, i); msgpack_packer_write_value(pk, e); } } static int write_hash_foreach(VALUE key, VALUE value, VALUE pk_value) { if (key == Qundef) { return ST_CONTINUE; } msgpack_packer_t* pk = (msgpack_packer_t*) pk_value; msgpack_packer_write_value(pk, key); msgpack_packer_write_value(pk, value); return ST_CONTINUE; } void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v) { /* actual return type of RHASH_SIZE is long (if SIZEOF_LONG == SIZEOF_VOIDP * or long long (if SIZEOF_LONG_LONG == SIZEOF_VOIDP. See st.h. */ unsigned long len = RHASH_SIZE(v); if(len > 0xffffffffUL) { rb_raise(rb_eArgError, "size of array is too long to pack: %ld bytes should be <= %lu", len, 0xffffffffUL); } unsigned int len32 = (unsigned int)len; msgpack_packer_write_map_header(pk, len32); #ifdef RUBINIUS VALUE iter = rb_funcall(v, s_to_iter, 0); VALUE entry = Qnil; while(RTEST(entry = rb_funcall(iter, s_next, 1, entry))) { VALUE key = rb_funcall(entry, s_key, 0); VALUE val = rb_funcall(entry, s_value, 0); write_hash_foreach(key, val, (VALUE) pk); } #else rb_hash_foreach(v, write_hash_foreach, (VALUE) pk); #endif } void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v) { int ext_type; VALUE proc = msgpack_packer_ext_registry_lookup(&pk->ext_registry, v, &ext_type); if(proc != Qnil) { VALUE payload = rb_funcall(proc, s_call, 1, v); StringValue(payload); msgpack_packer_write_ext(pk, ext_type, payload); } else { rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg); } } void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v) { switch(rb_type(v)) { case T_NIL: msgpack_packer_write_nil(pk); break; case T_TRUE: msgpack_packer_write_true(pk); break; case T_FALSE: msgpack_packer_write_false(pk); break; case T_FIXNUM: msgpack_packer_write_fixnum_value(pk, v); break; case T_SYMBOL: msgpack_packer_write_symbol_value(pk, v); break; case T_STRING: msgpack_packer_write_string_value(pk, v); break; case T_ARRAY: msgpack_packer_write_array_value(pk, v); break; case T_HASH: msgpack_packer_write_hash_value(pk, v); break; case T_BIGNUM: msgpack_packer_write_bignum_value(pk, v); break; case T_FLOAT: msgpack_packer_write_float_value(pk, v); break; default: msgpack_packer_write_other_value(pk, v); } } msgpack-1.4.2/ext/msgpack/buffer.h0000644000004100000410000003153214021120706017037 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_BUFFER_H__ #define MSGPACK_RUBY_BUFFER_H__ #include "compat.h" #include "sysdep.h" #ifndef MSGPACK_BUFFER_STRING_WRITE_REFERENCE_DEFAULT #define MSGPACK_BUFFER_STRING_WRITE_REFERENCE_DEFAULT (512*1024) #endif /* at least 23 (RSTRING_EMBED_LEN_MAX) bytes */ #ifndef MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM #define MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM 256 #endif #ifndef MSGPACK_BUFFER_STRING_READ_REFERENCE_DEFAULT #define MSGPACK_BUFFER_STRING_READ_REFERENCE_DEFAULT 256 #endif /* at least 23 (RSTRING_EMBED_LEN_MAX) bytes */ #ifndef MSGPACK_BUFFER_STRING_READ_REFERENCE_MINIMUM #define MSGPACK_BUFFER_STRING_READ_REFERENCE_MINIMUM 256 #endif #ifndef MSGPACK_BUFFER_IO_BUFFER_SIZE_DEFAULT #define MSGPACK_BUFFER_IO_BUFFER_SIZE_DEFAULT (32*1024) #endif #ifndef MSGPACK_BUFFER_IO_BUFFER_SIZE_MINIMUM #define MSGPACK_BUFFER_IO_BUFFER_SIZE_MINIMUM (1024) #endif #define NO_MAPPED_STRING ((VALUE)0) extern int msgpack_rb_encindex_utf8; extern int msgpack_rb_encindex_usascii; extern int msgpack_rb_encindex_ascii8bit; extern ID s_uminus; struct msgpack_buffer_chunk_t; typedef struct msgpack_buffer_chunk_t msgpack_buffer_chunk_t; struct msgpack_buffer_t; typedef struct msgpack_buffer_t msgpack_buffer_t; /* * msgpack_buffer_chunk_t * +----------------+ * | filled | free | * +---------+------+ * ^ first ^ last */ struct msgpack_buffer_chunk_t { char* first; char* last; void* mem; msgpack_buffer_chunk_t* next; VALUE mapped_string; /* RBString or NO_MAPPED_STRING */ }; union msgpack_buffer_cast_block_t { char buffer[8]; uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; int8_t i8; int16_t i16; int32_t i32; int64_t i64; float f; double d; }; struct msgpack_buffer_t { char* read_buffer; char* tail_buffer_end; msgpack_buffer_chunk_t tail; msgpack_buffer_chunk_t* head; msgpack_buffer_chunk_t* free_list; #ifndef DISABLE_RMEM char* rmem_last; char* rmem_end; void** rmem_owner; #endif union msgpack_buffer_cast_block_t cast_block; VALUE io; VALUE io_buffer; ID io_write_all_method; ID io_partial_read_method; size_t write_reference_threshold; size_t read_reference_threshold; size_t io_buffer_size; VALUE owner; }; /* * initialization functions */ void msgpack_buffer_static_init(); void msgpack_buffer_static_destroy(); void msgpack_buffer_init(msgpack_buffer_t* b); void msgpack_buffer_destroy(msgpack_buffer_t* b); void msgpack_buffer_mark(msgpack_buffer_t* b); void msgpack_buffer_clear(msgpack_buffer_t* b); static inline void msgpack_buffer_set_write_reference_threshold(msgpack_buffer_t* b, size_t length) { if(length < MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) { length = MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM; } b->write_reference_threshold = length; } static inline void msgpack_buffer_set_read_reference_threshold(msgpack_buffer_t* b, size_t length) { if(length < MSGPACK_BUFFER_STRING_READ_REFERENCE_MINIMUM) { length = MSGPACK_BUFFER_STRING_READ_REFERENCE_MINIMUM; } b->read_reference_threshold = length; } static inline void msgpack_buffer_set_io_buffer_size(msgpack_buffer_t* b, size_t length) { if(length < MSGPACK_BUFFER_IO_BUFFER_SIZE_MINIMUM) { length = MSGPACK_BUFFER_IO_BUFFER_SIZE_MINIMUM; } b->io_buffer_size = length; } static inline void msgpack_buffer_reset_io(msgpack_buffer_t* b) { b->io = Qnil; } static inline bool msgpack_buffer_has_io(msgpack_buffer_t* b) { return b->io != Qnil; } static inline void msgpack_buffer_reset(msgpack_buffer_t* b) { msgpack_buffer_clear(b); msgpack_buffer_reset_io(b); } /* * writer functions */ static inline size_t msgpack_buffer_writable_size(const msgpack_buffer_t* b) { return b->tail_buffer_end - b->tail.last; } static inline void msgpack_buffer_write_1(msgpack_buffer_t* b, int byte) { (*b->tail.last++) = (char) byte; } static inline void msgpack_buffer_write_2(msgpack_buffer_t* b, int byte1, unsigned char byte2) { *(b->tail.last++) = (char) byte1; *(b->tail.last++) = (char) byte2; } static inline void msgpack_buffer_write_byte_and_data(msgpack_buffer_t* b, int byte, const void* data, size_t length) { (*b->tail.last++) = (char) byte; memcpy(b->tail.last, data, length); b->tail.last += length; } void _msgpack_buffer_expand(msgpack_buffer_t* b, const char* data, size_t length, bool use_flush); size_t msgpack_buffer_flush_to_io(msgpack_buffer_t* b, VALUE io, ID write_method, bool consume); static inline size_t msgpack_buffer_flush(msgpack_buffer_t* b) { if(b->io == Qnil) { return 0; } return msgpack_buffer_flush_to_io(b, b->io, b->io_write_all_method, true); } static inline void msgpack_buffer_ensure_writable(msgpack_buffer_t* b, size_t require) { if(msgpack_buffer_writable_size(b) < require) { _msgpack_buffer_expand(b, NULL, require, true); } } static inline void _msgpack_buffer_append_impl(msgpack_buffer_t* b, const char* data, size_t length, bool flush_to_io) { if(length == 0) { return; } if(length <= msgpack_buffer_writable_size(b)) { memcpy(b->tail.last, data, length); b->tail.last += length; return; } _msgpack_buffer_expand(b, data, length, flush_to_io); } static inline void msgpack_buffer_append(msgpack_buffer_t* b, const char* data, size_t length) { _msgpack_buffer_append_impl(b, data, length, true); } static inline void msgpack_buffer_append_nonblock(msgpack_buffer_t* b, const char* data, size_t length) { _msgpack_buffer_append_impl(b, data, length, false); } void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string); static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE string) { size_t length = RSTRING_LEN(string); if(length > b->write_reference_threshold) { _msgpack_buffer_append_long_string(b, string); } else { msgpack_buffer_append(b, RSTRING_PTR(string), length); } return length; } static inline size_t msgpack_buffer_append_string_reference(msgpack_buffer_t* b, VALUE string) { size_t length = RSTRING_LEN(string); if(length > MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) { _msgpack_buffer_append_long_string(b, string); } else { msgpack_buffer_append(b, RSTRING_PTR(string), length); } return length; } /* * IO functions */ size_t _msgpack_buffer_feed_from_io(msgpack_buffer_t* b); size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string, size_t length); size_t _msgpack_buffer_skip_from_io(msgpack_buffer_t* b, size_t length); /* * reader functions */ static inline size_t msgpack_buffer_top_readable_size(const msgpack_buffer_t* b) { return b->head->last - b->read_buffer; } size_t msgpack_buffer_all_readable_size(const msgpack_buffer_t* b); bool _msgpack_buffer_shift_chunk(msgpack_buffer_t* b); static inline void _msgpack_buffer_consumed(msgpack_buffer_t* b, size_t length) { b->read_buffer += length; if(b->read_buffer >= b->head->last) { _msgpack_buffer_shift_chunk(b); } } static inline int msgpack_buffer_peek_top_1(msgpack_buffer_t* b) { return (int) (unsigned char) b->read_buffer[0]; } static inline int msgpack_buffer_read_top_1(msgpack_buffer_t* b) { int r = (int) (unsigned char) b->read_buffer[0]; _msgpack_buffer_consumed(b, 1); return r; } static inline int msgpack_buffer_read_1(msgpack_buffer_t* b) { if(msgpack_buffer_top_readable_size(b) <= 0) { if(b->io == Qnil) { return -1; } _msgpack_buffer_feed_from_io(b); } int r = (int) (unsigned char) b->read_buffer[0]; _msgpack_buffer_consumed(b, 1); return r; } /* * bulk read / skip functions */ size_t msgpack_buffer_read_nonblock(msgpack_buffer_t* b, char* buffer, size_t length); static inline bool msgpack_buffer_ensure_readable(msgpack_buffer_t* b, size_t require) { if(msgpack_buffer_top_readable_size(b) < require) { size_t sz = msgpack_buffer_all_readable_size(b); if(sz < require) { if(b->io == Qnil) { return false; } do { size_t rl = _msgpack_buffer_feed_from_io(b); sz += rl; } while(sz < require); } } return true; } bool _msgpack_buffer_read_all2(msgpack_buffer_t* b, char* buffer, size_t length); static inline bool msgpack_buffer_read_all(msgpack_buffer_t* b, char* buffer, size_t length) { size_t avail = msgpack_buffer_top_readable_size(b); if(avail < length) { return _msgpack_buffer_read_all2(b, buffer, length); } memcpy(buffer, b->read_buffer, length); _msgpack_buffer_consumed(b, length); return true; } static inline size_t msgpack_buffer_skip_nonblock(msgpack_buffer_t* b, size_t length) { size_t avail = msgpack_buffer_top_readable_size(b); if(avail < length) { return msgpack_buffer_read_nonblock(b, NULL, length); } _msgpack_buffer_consumed(b, length); return length; } static inline union msgpack_buffer_cast_block_t* msgpack_buffer_read_cast_block(msgpack_buffer_t* b, size_t n) { if(!msgpack_buffer_read_all(b, b->cast_block.buffer, n)) { return NULL; } return &b->cast_block; } size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string, size_t length); static inline size_t msgpack_buffer_read_to_string(msgpack_buffer_t* b, VALUE string, size_t length) { if(length == 0) { return 0; } size_t avail = msgpack_buffer_top_readable_size(b); if(avail > 0) { return msgpack_buffer_read_to_string_nonblock(b, string, length); } else if(b->io != Qnil) { return _msgpack_buffer_read_from_io_to_string(b, string, length); } else { return 0; } } static inline size_t msgpack_buffer_skip(msgpack_buffer_t* b, size_t length) { if(length == 0) { return 0; } size_t avail = msgpack_buffer_top_readable_size(b); if(avail > 0) { return msgpack_buffer_skip_nonblock(b, length); } else if(b->io != Qnil) { return _msgpack_buffer_skip_from_io(b, length); } else { return 0; } } VALUE msgpack_buffer_all_as_string(msgpack_buffer_t* b); VALUE msgpack_buffer_all_as_string_array(msgpack_buffer_t* b); static inline VALUE _msgpack_buffer_refer_head_mapped_string(msgpack_buffer_t* b, size_t length) { size_t offset = b->read_buffer - b->head->first; return rb_str_substr(b->head->mapped_string, offset, length); } static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen, bool utf8) { #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE /* optimize */ if(!will_be_frozen && b->head->mapped_string != NO_MAPPED_STRING && length >= b->read_reference_threshold) { VALUE result = _msgpack_buffer_refer_head_mapped_string(b, length); if (utf8) ENCODING_SET(result, msgpack_rb_encindex_utf8); _msgpack_buffer_consumed(b, length); return result; } #endif VALUE result; #ifdef HAVE_RB_ENC_INTERNED_STR if (will_be_frozen) { result = rb_enc_interned_str(b->read_buffer, length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding()); } else { if (utf8) { result = rb_utf8_str_new(b->read_buffer, length); } else { result = rb_str_new(b->read_buffer, length); } } _msgpack_buffer_consumed(b, length); return result; #else if (utf8) { result = rb_utf8_str_new(b->read_buffer, length); } else { result = rb_str_new(b->read_buffer, length); } #if STR_UMINUS_DEDUPE if (will_be_frozen) { #if STR_UMINUS_DEDUPE_FROZEN // Starting from MRI 2.8 it is preferable to freeze the string // before deduplication so that it can be interned directly // otherwise it would be duplicated first which is wasteful. rb_str_freeze(result); #endif //STR_UMINUS_DEDUPE_FROZEN // MRI 2.5 and older do not deduplicate strings that are already // frozen. result = rb_funcall(result, s_uminus, 0); } #endif // STR_UMINUS_DEDUPE _msgpack_buffer_consumed(b, length); return result; #endif // HAVE_RB_ENC_INTERNED_STR } #endif msgpack-1.4.2/ext/msgpack/rmem.c0000644000004100000410000000525314021120706016522 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "rmem.h" void msgpack_rmem_init(msgpack_rmem_t* pm) { memset(pm, 0, sizeof(msgpack_rmem_t)); pm->head.pages = xmalloc(MSGPACK_RMEM_PAGE_SIZE * 32); pm->head.mask = 0xffffffff; /* all bit is 1 = available */ } void msgpack_rmem_destroy(msgpack_rmem_t* pm) { msgpack_rmem_chunk_t* c = pm->array_first; msgpack_rmem_chunk_t* cend = pm->array_last; for(; c != cend; c++) { xfree(c->pages); } xfree(pm->head.pages); xfree(pm->array_first); } void* _msgpack_rmem_alloc2(msgpack_rmem_t* pm) { msgpack_rmem_chunk_t* c = pm->array_first; msgpack_rmem_chunk_t* last = pm->array_last; for(; c != last; c++) { if(_msgpack_rmem_chunk_available(c)) { void* mem = _msgpack_rmem_chunk_alloc(c); /* move to head */ msgpack_rmem_chunk_t tmp = pm->head; pm->head = *c; *c = tmp; return mem; } } if(c == pm->array_end) { size_t capacity = c - pm->array_first; size_t length = last - pm->array_first; capacity = (capacity == 0) ? 8 : capacity * 2; msgpack_rmem_chunk_t* array = xrealloc(pm->array_first, capacity * sizeof(msgpack_rmem_chunk_t)); pm->array_first = array; pm->array_last = array + length; pm->array_end = array + capacity; } /* allocate new chunk */ c = pm->array_last++; /* move to head */ msgpack_rmem_chunk_t tmp = pm->head; pm->head = *c; *c = tmp; pm->head.mask = 0xffffffff & (~1); /* "& (~1)" means first chunk is already allocated */ pm->head.pages = xmalloc(MSGPACK_RMEM_PAGE_SIZE * 32); return pm->head.pages; } void _msgpack_rmem_chunk_free(msgpack_rmem_t* pm, msgpack_rmem_chunk_t* c) { if(pm->array_first->mask == 0xffffffff) { /* free and move to last */ pm->array_last--; xfree(c->pages); *c = *pm->array_last; return; } /* move to first */ msgpack_rmem_chunk_t tmp = *pm->array_first; *pm->array_first = *c; *c = tmp; } msgpack-1.4.2/ext/msgpack/compat.h0000644000004100000410000000604214021120706017047 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_COMPAT_H__ #define MSGPACK_RUBY_COMPAT_H__ #include #include "ruby.h" #include "ruby/encoding.h" #if defined(HAVE_RUBY_ST_H) # include "ruby/st.h" /* ruby hash on Ruby 1.9 */ #elif defined(HAVE_ST_H) # include "st.h" /* ruby hash on Ruby 1.8 */ #endif /* * ZALLOC_N (ruby 2.2 or later) */ #ifndef RB_ZALLOC_N # define RB_ZALLOC_N(type,n) ((type*)ruby_xcalloc((size_t)(n),sizeof(type))) #endif #ifndef ZALLOC_N # define ZALLOC_N(type,n) RB_ZALLOC_N(type,n) #endif /* * define STR_DUP_LIKELY_DOES_COPY * check rb_str_dup actually copies the string or not */ #if defined(RUBY_VM) && defined(FL_ALL) && defined(FL_USER1) && defined(FL_USER3) /* MRI 1.9 */ # define STR_DUP_LIKELY_DOES_COPY(str) FL_ALL(str, FL_USER1|FL_USER3) /* same as STR_ASSOC_P(str) */ #elif defined(FL_TEST) && defined(ELTS_SHARED) /* MRI 1.8 */ # define STR_DUP_LIKELY_DOES_COPY(str) (!FL_TEST(str, ELTS_SHARED)) //#elif defined(RUBINIUS) || defined(JRUBY) /* Rubinius and JRuby */ #else # define STR_DUP_LIKELY_DOES_COPY(str) (1) #endif /* * SIZET2NUM */ #ifndef SIZET2NUM /* MRI 1.8 */ # define SIZET2NUM(v) ULL2NUM(v) #endif /* * rb_errinfo() */ #if defined(RUBY_VM) /* MRI 1.9 */ # define COMPAT_RERAISE rb_exc_raise(rb_errinfo()) #elif defined(JRUBY) /* JRuby */ # define COMPAT_RERAISE rb_exc_raise(rb_gv_get("$!")) #else /* MRI 1.8 and Rubinius */ # define COMPAT_RERAISE rb_exc_raise(ruby_errinfo) #endif /* * RBIGNUM_POSITIVE_P */ #ifndef RBIGNUM_POSITIVE_P # if defined(RUBINIUS) /* Rubinius <= v1.2.3 */ # define RBIGNUM_POSITIVE_P(b) (rb_funcall(b, rb_intern(">="), 1, INT2FIX(0)) == Qtrue) # elif defined(JRUBY) /* JRuby */ # define RBIGNUM_POSITIVE_P(b) (rb_funcall(b, rb_intern(">="), 1, INT2FIX(0)) == Qtrue) # define rb_big2ull(b) rb_num2ull(b) /*#define rb_big2ll(b) rb_num2ll(b)*/ # else /* MRI 1.8 */ # define RBIGNUM_POSITIVE_P(b) (RBIGNUM(b)->sign) # endif #endif /* * RSTRING_PTR, RSTRING_LEN */ #ifndef RSTRING_PTR /* MRI 1.8.5 */ # define RSTRING_PTR(s) (RSTRING(s)->ptr) #endif #ifndef RSTRING_LEN /* MRI 1.8.5 */ # define RSTRING_LEN(s) (RSTRING(s)->len) #endif /* * RSTRUCT_GET */ #ifndef RSTRUCT_GET # ifdef RSTRUCT_PTR /* MRI <= 2.0.0 */ # define RSTRUCT_GET(st, idx) (RSTRUCT_PTR(st)[idx]) # else /* Rubinius */ # define RSTRUCT_GET(st, idx) (rb_struct_aref(st, INT2FIX(idx))) # endif #endif #endif msgpack-1.4.2/ext/msgpack/unpacker.h0000644000004100000410000000661014021120706017375 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_UNPACKER_H__ #define MSGPACK_RUBY_UNPACKER_H__ #include "buffer.h" #include "unpacker_ext_registry.h" #ifndef MSGPACK_UNPACKER_STACK_CAPACITY #define MSGPACK_UNPACKER_STACK_CAPACITY 128 #endif struct msgpack_unpacker_t; typedef struct msgpack_unpacker_t msgpack_unpacker_t; enum stack_type_t { STACK_TYPE_ARRAY, STACK_TYPE_MAP_KEY, STACK_TYPE_MAP_VALUE, }; typedef struct { size_t count; enum stack_type_t type; VALUE object; VALUE key; } msgpack_unpacker_stack_t; #define MSGPACK_UNPACKER_STACK_SIZE (8+4+8+8) /* assumes size_t <= 64bit, enum <= 32bit, VALUE <= 64bit */ struct msgpack_unpacker_t { msgpack_buffer_t buffer; unsigned int head_byte; msgpack_unpacker_stack_t* stack; size_t stack_depth; size_t stack_capacity; VALUE last_object; VALUE reading_raw; size_t reading_raw_remaining; int reading_raw_type; VALUE buffer_ref; msgpack_unpacker_ext_registry_t ext_registry; /* options */ bool symbolize_keys; bool freeze; bool allow_unknown_ext; }; #define UNPACKER_BUFFER_(uk) (&(uk)->buffer) enum msgpack_unpacker_object_type { TYPE_NIL = 0, TYPE_BOOLEAN, TYPE_INTEGER, TYPE_FLOAT, TYPE_RAW, TYPE_ARRAY, TYPE_MAP, }; void msgpack_unpacker_static_init(); void msgpack_unpacker_static_destroy(); void _msgpack_unpacker_init(msgpack_unpacker_t* uk); void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk); void msgpack_unpacker_mark(msgpack_unpacker_t* uk); void _msgpack_unpacker_reset(msgpack_unpacker_t* uk); static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk, bool enable) { uk->symbolize_keys = enable; } static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable) { uk->freeze = enable; } static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk, bool enable) { uk->allow_unknown_ext = enable; } /* error codes */ #define PRIMITIVE_CONTAINER_START 1 #define PRIMITIVE_OBJECT_COMPLETE 0 #define PRIMITIVE_EOF -1 #define PRIMITIVE_INVALID_BYTE -2 #define PRIMITIVE_STACK_TOO_DEEP -3 #define PRIMITIVE_UNEXPECTED_TYPE -4 #define PRIMITIVE_UNEXPECTED_EXT_TYPE -5 int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth); int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth); static inline VALUE msgpack_unpacker_get_last_object(msgpack_unpacker_t* uk) { return uk->last_object; } int msgpack_unpacker_peek_next_object_type(msgpack_unpacker_t* uk); int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk); int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint32_t* result_size); int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_size); #endif msgpack-1.4.2/ext/msgpack/factory_class.h0000644000004100000410000000202414021120706020414 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2015 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_FACTORY_CLASS_H__ #define MSGPACK_RUBY_FACTORY_CLASS_H__ #include "compat.h" #include "sysdep.h" extern VALUE cMessagePack_Factory; extern VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self); extern VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self); void MessagePack_Factory_module_init(VALUE mMessagePack); #endif msgpack-1.4.2/ext/msgpack/buffer.c0000644000004100000410000004362114021120706017034 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "buffer.h" #include "rmem.h" #ifndef HAVE_RB_STR_REPLACE static ID s_replace; #endif int msgpack_rb_encindex_utf8; int msgpack_rb_encindex_usascii; int msgpack_rb_encindex_ascii8bit; ID s_uminus; #ifndef DISABLE_RMEM static msgpack_rmem_t s_rmem; #endif void msgpack_buffer_static_init() { s_uminus = rb_intern("-@"); msgpack_rb_encindex_utf8 = rb_utf8_encindex(); msgpack_rb_encindex_usascii = rb_usascii_encindex(); msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex(); #ifndef DISABLE_RMEM msgpack_rmem_init(&s_rmem); #endif #ifndef HAVE_RB_STR_REPLACE s_replace = rb_intern("replace"); #endif } void msgpack_buffer_static_destroy() { #ifndef DISABLE_RMEM msgpack_rmem_destroy(&s_rmem); #endif } void msgpack_buffer_init(msgpack_buffer_t* b) { memset(b, 0, sizeof(msgpack_buffer_t)); b->head = &b->tail; b->write_reference_threshold = MSGPACK_BUFFER_STRING_WRITE_REFERENCE_DEFAULT; b->read_reference_threshold = MSGPACK_BUFFER_STRING_READ_REFERENCE_DEFAULT; b->io_buffer_size = MSGPACK_BUFFER_IO_BUFFER_SIZE_DEFAULT; b->io = Qnil; b->io_buffer = Qnil; } static void _msgpack_buffer_chunk_destroy(msgpack_buffer_chunk_t* c) { if(c->mem != NULL) { #ifndef DISABLE_RMEM if(!msgpack_rmem_free(&s_rmem, c->mem)) { xfree(c->mem); } /* no needs to update rmem_owner because chunks will not be * free()ed (left in free_list) and thus *rmem_owner is * always valid. */ #else xfree(c->mem); #endif } c->first = NULL; c->last = NULL; c->mem = NULL; } void msgpack_buffer_destroy(msgpack_buffer_t* b) { /* head is always available */ msgpack_buffer_chunk_t* c = b->head; while(c != &b->tail) { msgpack_buffer_chunk_t* n = c->next; _msgpack_buffer_chunk_destroy(c); xfree(c); c = n; } _msgpack_buffer_chunk_destroy(c); c = b->free_list; while(c != NULL) { msgpack_buffer_chunk_t* n = c->next; xfree(c); c = n; } } void msgpack_buffer_mark(msgpack_buffer_t* b) { /* head is always available */ msgpack_buffer_chunk_t* c = b->head; while(c != &b->tail) { rb_gc_mark(c->mapped_string); c = c->next; } rb_gc_mark(c->mapped_string); rb_gc_mark(b->io); rb_gc_mark(b->io_buffer); rb_gc_mark(b->owner); } bool _msgpack_buffer_shift_chunk(msgpack_buffer_t* b) { _msgpack_buffer_chunk_destroy(b->head); if(b->head == &b->tail) { /* list becomes empty. don't add head to free_list * because head should be always available */ b->tail_buffer_end = NULL; b->read_buffer = NULL; return false; } /* add head to free_list */ msgpack_buffer_chunk_t* next_head = b->head->next; b->head->next = b->free_list; b->free_list = b->head; b->head = next_head; b->read_buffer = next_head->first; return true; } void msgpack_buffer_clear(msgpack_buffer_t* b) { while(_msgpack_buffer_shift_chunk(b)) { ; } } size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string, size_t length) { size_t avail = msgpack_buffer_top_readable_size(b); #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE /* optimize */ if(length <= avail && RSTRING_LEN(string) == 0 && b->head->mapped_string != NO_MAPPED_STRING && length >= b->read_reference_threshold) { VALUE s = _msgpack_buffer_refer_head_mapped_string(b, length); #ifndef HAVE_RB_STR_REPLACE /* TODO MRI 1.8 */ rb_funcall(string, s_replace, 1, s); #else rb_str_replace(string, s); #endif /* here doesn't have to call ENCODING_SET because * encoding of s is always ASCII-8BIT */ _msgpack_buffer_consumed(b, length); return length; } #endif size_t const length_orig = length; while(true) { if(length <= avail) { rb_str_buf_cat(string, b->read_buffer, length); _msgpack_buffer_consumed(b, length); return length_orig; } rb_str_buf_cat(string, b->read_buffer, avail); length -= avail; if(!_msgpack_buffer_shift_chunk(b)) { return length_orig - length; } avail = msgpack_buffer_top_readable_size(b); } } size_t msgpack_buffer_read_nonblock(msgpack_buffer_t* b, char* buffer, size_t length) { /* buffer == NULL means skip */ size_t const length_orig = length; while(true) { size_t avail = msgpack_buffer_top_readable_size(b); if(length <= avail) { if(buffer != NULL) { memcpy(buffer, b->read_buffer, length); } _msgpack_buffer_consumed(b, length); return length_orig; } if(buffer != NULL) { memcpy(buffer, b->read_buffer, avail); buffer += avail; } length -= avail; if(!_msgpack_buffer_shift_chunk(b)) { return length_orig - length; } } } size_t msgpack_buffer_all_readable_size(const msgpack_buffer_t* b) { size_t sz = msgpack_buffer_top_readable_size(b); if(b->head == &b->tail) { return sz; } msgpack_buffer_chunk_t* c = b->head->next; while(true) { sz += c->last - c->first; if(c == &b->tail) { return sz; } c = c->next; } } bool _msgpack_buffer_read_all2(msgpack_buffer_t* b, char* buffer, size_t length) { if(!msgpack_buffer_ensure_readable(b, length)) { return false; } msgpack_buffer_read_nonblock(b, buffer, length); return true; } static inline msgpack_buffer_chunk_t* _msgpack_buffer_alloc_new_chunk(msgpack_buffer_t* b) { msgpack_buffer_chunk_t* reuse = b->free_list; if(reuse == NULL) { return xmalloc(sizeof(msgpack_buffer_chunk_t)); } b->free_list = b->free_list->next; return reuse; } static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b) { if(b->head == &b->tail) { if(b->tail.first == NULL) { /* empty buffer */ return; } msgpack_buffer_chunk_t* nc = _msgpack_buffer_alloc_new_chunk(b); *nc = b->tail; b->head = nc; nc->next = &b->tail; } else { /* search node before tail */ msgpack_buffer_chunk_t* before_tail = b->head; while(before_tail->next != &b->tail) { before_tail = before_tail->next; } msgpack_buffer_chunk_t* nc = _msgpack_buffer_alloc_new_chunk(b); #ifndef DISABLE_RMEM #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT if(b->rmem_last == b->tail_buffer_end) { /* reuse unused rmem space */ size_t unused = b->tail_buffer_end - b->tail.last; b->rmem_last -= unused; } #endif #endif /* rebuild tail */ *nc = b->tail; before_tail->next = nc; nc->next = &b->tail; } } static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string) { VALUE mapped_string = rb_str_dup(string); ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit); _msgpack_buffer_add_new_chunk(b); char* data = RSTRING_PTR(mapped_string); size_t length = RSTRING_LEN(mapped_string); b->tail.first = (char*) data; b->tail.last = (char*) data + length; b->tail.mapped_string = mapped_string; b->tail.mem = NULL; /* msgpack_buffer_writable_size should return 0 for mapped chunk */ b->tail_buffer_end = b->tail.last; /* consider read_buffer */ if(b->head == &b->tail) { b->read_buffer = b->tail.first; } } void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string) { size_t length = RSTRING_LEN(string); if(b->io != Qnil) { msgpack_buffer_flush(b); if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) { rb_funcall(b->io, b->io_write_all_method, 1, string); } else if(!STR_DUP_LIKELY_DOES_COPY(string)) { VALUE s = rb_str_dup(string); ENCODING_SET(s, msgpack_rb_encindex_ascii8bit); rb_funcall(b->io, b->io_write_all_method, 1, s); } else { msgpack_buffer_append(b, RSTRING_PTR(string), length); } } else if(!STR_DUP_LIKELY_DOES_COPY(string)) { _msgpack_buffer_append_reference(b, string); } else { msgpack_buffer_append(b, RSTRING_PTR(string), length); } } static inline void* _msgpack_buffer_chunk_malloc( msgpack_buffer_t* b, msgpack_buffer_chunk_t* c, size_t required_size, size_t* allocated_size) { #ifndef DISABLE_RMEM if(required_size <= MSGPACK_RMEM_PAGE_SIZE) { #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT if((size_t)(b->rmem_end - b->rmem_last) < required_size) { #endif /* alloc new rmem page */ *allocated_size = MSGPACK_RMEM_PAGE_SIZE; char* buffer = msgpack_rmem_alloc(&s_rmem); c->mem = buffer; /* update rmem owner */ b->rmem_owner = &c->mem; b->rmem_last = b->rmem_end = buffer + MSGPACK_RMEM_PAGE_SIZE; return buffer; #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT } else { /* reuse unused rmem */ *allocated_size = (size_t)(b->rmem_end - b->rmem_last); char* buffer = b->rmem_last; b->rmem_last = b->rmem_end; /* update rmem owner */ c->mem = *b->rmem_owner; *b->rmem_owner = NULL; b->rmem_owner = &c->mem; return buffer; } #endif } #else if(required_size < 72) { required_size = 72; } #endif // TODO alignment? *allocated_size = required_size; void* mem = xmalloc(required_size); c->mem = mem; return mem; } static inline void* _msgpack_buffer_chunk_realloc( msgpack_buffer_t* b, msgpack_buffer_chunk_t* c, void* mem, size_t required_size, size_t* current_size) { if(mem == NULL) { return _msgpack_buffer_chunk_malloc(b, c, required_size, current_size); } size_t next_size = *current_size * 2; while(next_size < required_size) { next_size *= 2; } *current_size = next_size; mem = xrealloc(mem, next_size); c->mem = mem; return mem; } void _msgpack_buffer_expand(msgpack_buffer_t* b, const char* data, size_t length, bool flush_to_io) { if(flush_to_io && b->io != Qnil) { msgpack_buffer_flush(b); if(msgpack_buffer_writable_size(b) >= length) { /* data == NULL means ensure_writable */ if(data != NULL) { size_t tail_avail = msgpack_buffer_writable_size(b); memcpy(b->tail.last, data, length); b->tail.last += tail_avail; } return; } } /* data == NULL means ensure_writable */ if(data != NULL) { size_t tail_avail = msgpack_buffer_writable_size(b); memcpy(b->tail.last, data, tail_avail); b->tail.last += tail_avail; data += tail_avail; length -= tail_avail; } size_t capacity = b->tail.last - b->tail.first; /* can't realloc mapped chunk or rmem page */ if(b->tail.mapped_string != NO_MAPPED_STRING #ifndef DISABLE_RMEM || capacity <= MSGPACK_RMEM_PAGE_SIZE #endif ) { /* allocate new chunk */ _msgpack_buffer_add_new_chunk(b); char* mem = _msgpack_buffer_chunk_malloc(b, &b->tail, length, &capacity); char* last = mem; if(data != NULL) { memcpy(mem, data, length); last += length; } /* rebuild tail chunk */ b->tail.first = mem; b->tail.last = last; b->tail.mapped_string = NO_MAPPED_STRING; b->tail_buffer_end = mem + capacity; /* consider read_buffer */ if(b->head == &b->tail) { b->read_buffer = b->tail.first; } } else { /* realloc malloc()ed chunk or NULL */ size_t tail_filled = b->tail.last - b->tail.first; char* mem = _msgpack_buffer_chunk_realloc(b, &b->tail, b->tail.first, tail_filled+length, &capacity); char* last = mem + tail_filled; if(data != NULL) { memcpy(last, data, length); last += length; } /* consider read_buffer */ if(b->head == &b->tail) { size_t read_offset = b->read_buffer - b->head->first; b->read_buffer = mem + read_offset; } /* rebuild tail chunk */ b->tail.first = mem; b->tail.last = last; b->tail_buffer_end = mem + capacity; } } static inline VALUE _msgpack_buffer_head_chunk_as_string(msgpack_buffer_t* b) { size_t length = b->head->last - b->read_buffer; if(length == 0) { return rb_str_buf_new(0); } if(b->head->mapped_string != NO_MAPPED_STRING) { return _msgpack_buffer_refer_head_mapped_string(b, length); } return rb_str_new(b->read_buffer, length); } static inline VALUE _msgpack_buffer_chunk_as_string(msgpack_buffer_chunk_t* c) { size_t chunk_size = c->last - c->first; if(chunk_size == 0) { return rb_str_buf_new(0); } if(c->mapped_string != NO_MAPPED_STRING) { return rb_str_dup(c->mapped_string); } return rb_str_new(c->first, chunk_size); } VALUE msgpack_buffer_all_as_string(msgpack_buffer_t* b) { if(b->head == &b->tail) { return _msgpack_buffer_head_chunk_as_string(b); } size_t length = msgpack_buffer_all_readable_size(b); VALUE string = rb_str_new(NULL, length); char* buffer = RSTRING_PTR(string); size_t avail = msgpack_buffer_top_readable_size(b); memcpy(buffer, b->read_buffer, avail); buffer += avail; length -= avail; msgpack_buffer_chunk_t* c = b->head->next; while(true) { avail = c->last - c->first; memcpy(buffer, c->first, avail); if(length <= avail) { return string; } buffer += avail; length -= avail; c = c->next; } } VALUE msgpack_buffer_all_as_string_array(msgpack_buffer_t* b) { if(b->head == &b->tail) { VALUE s = msgpack_buffer_all_as_string(b); VALUE ary = rb_ary_new3(1, s); return ary; } /* TODO optimize ary construction */ VALUE ary = rb_ary_new(); VALUE s = _msgpack_buffer_head_chunk_as_string(b); rb_ary_push(ary, s); msgpack_buffer_chunk_t* c = b->head->next; while(true) { s = _msgpack_buffer_chunk_as_string(c); rb_ary_push(ary, s); if(c == &b->tail) { return ary; } c = c->next; } return ary; } size_t msgpack_buffer_flush_to_io(msgpack_buffer_t* b, VALUE io, ID write_method, bool consume) { if(msgpack_buffer_top_readable_size(b) == 0) { return 0; } VALUE s = _msgpack_buffer_head_chunk_as_string(b); rb_funcall(io, write_method, 1, s); size_t sz = RSTRING_LEN(s); if(consume) { while(_msgpack_buffer_shift_chunk(b)) { s = _msgpack_buffer_chunk_as_string(b->head); rb_funcall(io, write_method, 1, s); sz += RSTRING_LEN(s); } return sz; } else { if(b->head == &b->tail) { return sz; } msgpack_buffer_chunk_t* c = b->head->next; while(true) { s = _msgpack_buffer_chunk_as_string(c); rb_funcall(io, write_method, 1, s); sz += RSTRING_LEN(s); if(c == &b->tail) { return sz; } c = c->next; } } } size_t _msgpack_buffer_feed_from_io(msgpack_buffer_t* b) { if(b->io_buffer == Qnil) { b->io_buffer = rb_funcall(b->io, b->io_partial_read_method, 1, LONG2NUM(b->io_buffer_size)); if(b->io_buffer == Qnil) { rb_raise(rb_eEOFError, "IO reached end of file"); } StringValue(b->io_buffer); } else { VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(b->io_buffer_size), b->io_buffer); if(ret == Qnil) { rb_raise(rb_eEOFError, "IO reached end of file"); } } size_t len = RSTRING_LEN(b->io_buffer); if(len == 0) { rb_raise(rb_eEOFError, "IO reached end of file"); } /* TODO zero-copy optimize? */ msgpack_buffer_append_nonblock(b, RSTRING_PTR(b->io_buffer), len); return len; } size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string, size_t length) { if(RSTRING_LEN(string) == 0) { /* direct read */ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), string); if(ret == Qnil) { return 0; } return RSTRING_LEN(string); } /* copy via io_buffer */ if(b->io_buffer == Qnil) { b->io_buffer = rb_str_buf_new(0); } VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer); if(ret == Qnil) { return 0; } size_t rl = RSTRING_LEN(b->io_buffer); rb_str_buf_cat(string, (const void*)RSTRING_PTR(b->io_buffer), rl); return rl; } size_t _msgpack_buffer_skip_from_io(msgpack_buffer_t* b, size_t length) { if(b->io_buffer == Qnil) { b->io_buffer = rb_str_buf_new(0); } VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer); if(ret == Qnil) { return 0; } return RSTRING_LEN(b->io_buffer); } msgpack-1.4.2/ext/msgpack/sysdep.h0000644000004100000410000000637314021120706017102 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_SYSDEP_H__ #define MSGPACK_RUBY_SYSDEP_H__ #include "sysdep_types.h" #include "sysdep_endian.h" #define UNUSED(var) ((void)var) #ifdef __LITTLE_ENDIAN__ /* _msgpack_be16 */ #ifdef _WIN32 # if defined(ntohs) # define _msgpack_be16(x) ntohs(x) # elif defined(_byteswap_ushort) || (defined(_MSC_VER) && _MSC_VER >= 1400) # define _msgpack_be16(x) ((uint16_t)_byteswap_ushort((unsigned short)x)) # else # define _msgpack_be16(x) ( \ ((((uint16_t)x) << 8) ) | \ ((((uint16_t)x) >> 8) ) ) # endif #else # define _msgpack_be16(x) ntohs(x) #endif /* _msgpack_be32 */ #ifdef _WIN32 # if defined(ntohl) # define _msgpack_be32(x) ntohl(x) # elif defined(_byteswap_ulong) || (defined(_MSC_VER) && _MSC_VER >= 1400) # define _msgpack_be32(x) ((uint32_t)_byteswap_ulong((unsigned long)x)) # else # define _msgpack_be32(x) \ ( ((((uint32_t)x) << 24) ) | \ ((((uint32_t)x) << 8) & 0x00ff0000U ) | \ ((((uint32_t)x) >> 8) & 0x0000ff00U ) | \ ((((uint32_t)x) >> 24) ) ) # endif #else # define _msgpack_be32(x) ntohl(x) #endif /* _msgpack_be64 */ #if defined(_byteswap_uint64) || (defined(_MSC_VER) && _MSC_VER >= 1400) # define _msgpack_be64(x) (_byteswap_uint64(x)) #elif defined(bswap_64) # define _msgpack_be64(x) bswap_64(x) #elif defined(__DARWIN_OSSwapInt64) # define _msgpack_be64(x) __DARWIN_OSSwapInt64(x) #else #define _msgpack_be64(x) \ ( ((((uint64_t)x) << 56) ) | \ ((((uint64_t)x) << 40) & 0x00ff000000000000ULL ) | \ ((((uint64_t)x) << 24) & 0x0000ff0000000000ULL ) | \ ((((uint64_t)x) << 8) & 0x000000ff00000000ULL ) | \ ((((uint64_t)x) >> 8) & 0x00000000ff000000ULL ) | \ ((((uint64_t)x) >> 24) & 0x0000000000ff0000ULL ) | \ ((((uint64_t)x) >> 40) & 0x000000000000ff00ULL ) | \ ((((uint64_t)x) >> 56) ) ) #endif #else /* big endian */ #define _msgpack_be16(x) (x) #define _msgpack_be32(x) (x) #define _msgpack_be64(x) (x) #endif /* _msgpack_be_float */ #define _msgpack_be_float(x) _msgpack_be32(x) /* _msgpack_be_double */ #if defined(__arm__) && !(__ARM_EABI__) /* ARM OABI */ #define _msgpack_be_double(x) \ ( (((x) & 0xFFFFFFFFUL) << 32UL) | ((x) >> 32UL) ) #else /* the other ABI */ #define _msgpack_be_double(x) _msgpack_be64(x) #endif /* _msgpack_bsp32 */ #if defined(_MSC_VER) #define _msgpack_bsp32(name, val) \ long name; \ _BitScanForward(&name, val) #else #define _msgpack_bsp32(name, val) \ int name = __builtin_ctz(val) /* TODO default impl for _msgpack_bsp32 */ #endif #endif msgpack-1.4.2/ext/msgpack/extconf.rb0000644000004100000410000000360114021120706017404 0ustar www-datawww-datarequire 'mkmf' have_header("ruby/st.h") have_header("st.h") have_func("rb_str_replace", ["ruby.h"]) have_func("rb_intern_str", ["ruby.h"]) have_func("rb_enc_interned_str", "ruby.h") have_func("rb_sym2str", ["ruby.h"]) have_func("rb_str_intern", ["ruby.h"]) have_func("rb_block_lambda", ["ruby.h"]) have_func("rb_hash_dup", ["ruby.h"]) have_func("rb_hash_clear", ["ruby.h"]) unless RUBY_PLATFORM.include? 'mswin' $CFLAGS << %[ -I.. -Wall -O3 -g -std=gnu99] end #$CFLAGS << %[ -DDISABLE_RMEM] #$CFLAGS << %[ -DDISABLE_RMEM_REUSE_INTERNAL_FRAGMENT] #$CFLAGS << %[ -DDISABLE_BUFFER_READ_REFERENCE_OPTIMIZE] #$CFLAGS << %[ -DDISABLE_BUFFER_READ_TO_S_OPTIMIZE] if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' # msgpack-ruby doesn't modify data came from RSTRING_PTR(str) $CFLAGS << %[ -DRSTRING_NOT_MODIFIED] # Rubinius C extensions don't grab GVL while rmem is not thread safe $CFLAGS << %[ -DDISABLE_RMEM] end # checking if Hash#[]= (rb_hash_aset) dedupes string keys h = {} x = {} r = rand.to_s h[%W(#{r}).join('')] = :foo x[%W(#{r}).join('')] = :foo if x.keys[0].equal?(h.keys[0]) $CFLAGS << ' -DHASH_ASET_DEDUPE=1 ' else $CFLAGS << ' -DHASH_ASET_DEDUPE=0 ' end # checking if String#-@ (str_uminus) dedupes... ' begin a = -(%w(t e s t).join) b = -(%w(t e s t).join) if a.equal?(b) $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 ' else $CFLAGS += ' -DSTR_UMINUS_DEDUPE=0 ' end rescue NoMethodError $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 ' end # checking if String#-@ (str_uminus) directly interns frozen strings... ' begin s = rand.to_s.freeze if (-s).equal?(s) && (-s.dup).equal?(s) $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 ' else $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 ' end rescue NoMethodError $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 ' end if warnflags = CONFIG['warnflags'] warnflags.slice!(/ -Wdeclaration-after-statement/) end create_makefile('msgpack/msgpack') msgpack-1.4.2/ext/msgpack/rbinit.c0000644000004100000410000000220614021120706017044 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "buffer_class.h" #include "packer_class.h" #include "unpacker_class.h" #include "factory_class.h" #include "extension_value_class.h" void Init_msgpack(void) { VALUE mMessagePack = rb_define_module("MessagePack"); MessagePack_Buffer_module_init(mMessagePack); MessagePack_Packer_module_init(mMessagePack); MessagePack_Unpacker_module_init(mMessagePack); MessagePack_Factory_module_init(mMessagePack); MessagePack_ExtensionValue_module_init(mMessagePack); } msgpack-1.4.2/ext/msgpack/rmem.h0000644000004100000410000000571714021120706016534 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_RMEM_H__ #define MSGPACK_RUBY_RMEM_H__ #include "compat.h" #include "sysdep.h" #ifndef MSGPACK_RMEM_PAGE_SIZE #define MSGPACK_RMEM_PAGE_SIZE (4*1024) #endif struct msgpack_rmem_t; typedef struct msgpack_rmem_t msgpack_rmem_t; struct msgpack_rmem_chunk_t; typedef struct msgpack_rmem_chunk_t msgpack_rmem_chunk_t; /* * a chunk contains 32 pages. * size of each buffer is MSGPACK_RMEM_PAGE_SIZE bytes. */ struct msgpack_rmem_chunk_t { unsigned int mask; char* pages; }; struct msgpack_rmem_t { msgpack_rmem_chunk_t head; msgpack_rmem_chunk_t* array_first; msgpack_rmem_chunk_t* array_last; msgpack_rmem_chunk_t* array_end; }; /* assert MSGPACK_RMEM_PAGE_SIZE % sysconf(_SC_PAGE_SIZE) == 0 */ void msgpack_rmem_init(msgpack_rmem_t* pm); void msgpack_rmem_destroy(msgpack_rmem_t* pm); void* _msgpack_rmem_alloc2(msgpack_rmem_t* pm); #define _msgpack_rmem_chunk_available(c) ((c)->mask != 0) static inline void* _msgpack_rmem_chunk_alloc(msgpack_rmem_chunk_t* c) { _msgpack_bsp32(pos, c->mask); (c)->mask &= ~(1 << pos); return ((char*)(c)->pages) + (pos * (MSGPACK_RMEM_PAGE_SIZE)); } static inline bool _msgpack_rmem_chunk_try_free(msgpack_rmem_chunk_t* c, void* mem) { ptrdiff_t pdiff = ((char*)(mem)) - ((char*)(c)->pages); if(0 <= pdiff && pdiff < MSGPACK_RMEM_PAGE_SIZE * 32) { size_t pos = pdiff / MSGPACK_RMEM_PAGE_SIZE; (c)->mask |= (1 << pos); return true; } return false; } static inline void* msgpack_rmem_alloc(msgpack_rmem_t* pm) { if(_msgpack_rmem_chunk_available(&pm->head)) { return _msgpack_rmem_chunk_alloc(&pm->head); } return _msgpack_rmem_alloc2(pm); } void _msgpack_rmem_chunk_free(msgpack_rmem_t* pm, msgpack_rmem_chunk_t* c); static inline bool msgpack_rmem_free(msgpack_rmem_t* pm, void* mem) { if(_msgpack_rmem_chunk_try_free(&pm->head, mem)) { return true; } /* search from last */ msgpack_rmem_chunk_t* c = pm->array_last - 1; msgpack_rmem_chunk_t* before_first = pm->array_first - 1; for(; c != before_first; c--) { if(_msgpack_rmem_chunk_try_free(c, mem)) { if(c != pm->array_first && c->mask == 0xffffffff) { _msgpack_rmem_chunk_free(pm, c); } return true; } } return false; } #endif msgpack-1.4.2/ext/msgpack/unpacker.c0000644000004100000410000006243714021120706017401 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "unpacker.h" #include "rmem.h" #include "extension_value_class.h" #if !defined(DISABLE_RMEM) && !defined(DISABLE_UNPACKER_STACK_RMEM) && \ MSGPACK_UNPACKER_STACK_CAPACITY * MSGPACK_UNPACKER_STACK_SIZE <= MSGPACK_RMEM_PAGE_SIZE #define UNPACKER_STACK_RMEM #endif static int RAW_TYPE_STRING = 256; static int RAW_TYPE_BINARY = 257; static ID s_call; #ifdef UNPACKER_STACK_RMEM static msgpack_rmem_t s_stack_rmem; #endif void msgpack_unpacker_static_init() { #ifdef UNPACKER_STACK_RMEM msgpack_rmem_init(&s_stack_rmem); #endif s_call = rb_intern("call"); } void msgpack_unpacker_static_destroy() { #ifdef UNPACKER_STACK_RMEM msgpack_rmem_destroy(&s_stack_rmem); #endif } #define HEAD_BYTE_REQUIRED 0xc1 void _msgpack_unpacker_init(msgpack_unpacker_t* uk) { memset(uk, 0, sizeof(msgpack_unpacker_t)); msgpack_buffer_init(UNPACKER_BUFFER_(uk)); uk->head_byte = HEAD_BYTE_REQUIRED; uk->last_object = Qnil; uk->reading_raw = Qnil; #ifdef UNPACKER_STACK_RMEM uk->stack = msgpack_rmem_alloc(&s_stack_rmem); /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/ #else /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_t));*/ uk->stack = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t)); #endif uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY; } void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk) { #ifdef UNPACKER_STACK_RMEM msgpack_rmem_free(&s_stack_rmem, uk->stack); #else xfree(uk->stack); #endif msgpack_buffer_destroy(UNPACKER_BUFFER_(uk)); } void msgpack_unpacker_mark(msgpack_unpacker_t* uk) { rb_gc_mark(uk->last_object); rb_gc_mark(uk->reading_raw); msgpack_unpacker_stack_t* s = uk->stack; msgpack_unpacker_stack_t* send = uk->stack + uk->stack_depth; for(; s < send; s++) { rb_gc_mark(s->object); rb_gc_mark(s->key); } /* See MessagePack_Buffer_wrap */ /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */ rb_gc_mark(uk->buffer_ref); } void _msgpack_unpacker_reset(msgpack_unpacker_t* uk) { msgpack_buffer_clear(UNPACKER_BUFFER_(uk)); uk->head_byte = HEAD_BYTE_REQUIRED; /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/ uk->stack_depth = 0; uk->last_object = Qnil; uk->reading_raw = Qnil; uk->reading_raw_remaining = 0; } /* head byte functions */ static int read_head_byte(msgpack_unpacker_t* uk) { int r = msgpack_buffer_read_1(UNPACKER_BUFFER_(uk)); if(r == -1) { return PRIMITIVE_EOF; } return uk->head_byte = r; } static inline int get_head_byte(msgpack_unpacker_t* uk) { int b = uk->head_byte; if(b == HEAD_BYTE_REQUIRED) { b = read_head_byte(uk); } return b; } static inline void reset_head_byte(msgpack_unpacker_t* uk) { uk->head_byte = HEAD_BYTE_REQUIRED; } static inline int object_complete(msgpack_unpacker_t* uk, VALUE object) { if(uk->freeze) { rb_obj_freeze(object); } uk->last_object = object; reset_head_byte(uk); return PRIMITIVE_OBJECT_COMPLETE; } static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str) { VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type); if(proc != Qnil) { VALUE obj = rb_funcall(proc, s_call, 1, str); return object_complete(uk, obj); } if(uk->allow_unknown_ext) { VALUE obj = MessagePack_ExtensionValue_new(ext_type, str); return object_complete(uk, obj); } return PRIMITIVE_UNEXPECTED_EXT_TYPE; } /* stack funcs */ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk) { return &uk->stack[uk->stack_depth-1]; } static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object) { reset_head_byte(uk); if(uk->stack_capacity - uk->stack_depth <= 0) { return PRIMITIVE_STACK_TOO_DEEP; } msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth]; next->count = count; next->type = type; next->object = object; next->key = Qnil; uk->stack_depth++; return PRIMITIVE_CONTAINER_START; } static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk) { return --uk->stack_depth; } static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk) { return uk->stack_depth == 0; } #ifdef USE_CASE_RANGE #define SWITCH_RANGE_BEGIN(BYTE) { switch(BYTE) { #define SWITCH_RANGE(BYTE, FROM, TO) } case FROM ... TO: { #define SWITCH_RANGE_DEFAULT } default: { #define SWITCH_RANGE_END } } #else #define SWITCH_RANGE_BEGIN(BYTE) { if(0) { #define SWITCH_RANGE(BYTE, FROM, TO) } else if(FROM <= (BYTE) && (BYTE) <= TO) { #define SWITCH_RANGE_DEFAULT } else { #define SWITCH_RANGE_END } } #endif #define READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n) \ union msgpack_buffer_cast_block_t* cb = msgpack_buffer_read_cast_block(UNPACKER_BUFFER_(uk), n); \ if(cb == NULL) { \ return PRIMITIVE_EOF; \ } static inline bool is_reading_map_key(msgpack_unpacker_t* uk) { if(uk->stack_depth > 0) { msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk); if(top->type == STACK_TYPE_MAP_KEY) { return true; } } return false; } static int read_raw_body_cont(msgpack_unpacker_t* uk) { size_t length = uk->reading_raw_remaining; if(uk->reading_raw == Qnil) { uk->reading_raw = rb_str_buf_new(length); } do { size_t n = msgpack_buffer_read_to_string(UNPACKER_BUFFER_(uk), uk->reading_raw, length); if(n == 0) { return PRIMITIVE_EOF; } /* update reading_raw_remaining everytime because * msgpack_buffer_read_to_string raises IOError */ uk->reading_raw_remaining = length = length - n; } while(length > 0); int ret; if(uk->reading_raw_type == RAW_TYPE_STRING) { ENCODING_SET(uk->reading_raw, msgpack_rb_encindex_utf8); ret = object_complete(uk, uk->reading_raw); } else if (uk->reading_raw_type == RAW_TYPE_BINARY) { ret = object_complete(uk, uk->reading_raw); } else { ret = object_complete_ext(uk, uk->reading_raw_type, uk->reading_raw); } uk->reading_raw = Qnil; return ret; } static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type) { /* assuming uk->reading_raw == Qnil */ /* try optimized read */ size_t length = uk->reading_raw_remaining; if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) { /* don't use zerocopy for hash keys but get a frozen string directly * because rb_hash_aset freezes keys and it causes copying */ bool will_freeze = uk->freeze || is_reading_map_key(uk); VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING); int ret; if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) { ret = object_complete(uk, string); } else { ret = object_complete_ext(uk, raw_type, string); } # if !HASH_ASET_DEDUPE if(will_freeze) { rb_obj_freeze(string); } # endif uk->reading_raw_remaining = 0; return ret; } uk->reading_raw_type = raw_type; return read_raw_body_cont(uk); } static int read_primitive(msgpack_unpacker_t* uk) { if(uk->reading_raw_remaining > 0) { return read_raw_body_cont(uk); } int b = get_head_byte(uk); if(b < 0) { return b; } SWITCH_RANGE_BEGIN(b) SWITCH_RANGE(b, 0x00, 0x7f) // Positive Fixnum return object_complete(uk, INT2NUM(b)); SWITCH_RANGE(b, 0xe0, 0xff) // Negative Fixnum return object_complete(uk, INT2NUM((int8_t)b)); SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr int count = b & 0x1f; if(count == 0) { return object_complete(uk, rb_utf8_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_STRING); SWITCH_RANGE(b, 0x90, 0x9f) // FixArray int count = b & 0x0f; if(count == 0) { return object_complete(uk, rb_ary_new()); } return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(count)); SWITCH_RANGE(b, 0x80, 0x8f) // FixMap int count = b & 0x0f; if(count == 0) { return object_complete(uk, rb_hash_new()); } return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new()); SWITCH_RANGE(b, 0xc0, 0xdf) // Variable switch(b) { case 0xc0: // nil return object_complete(uk, Qnil); //case 0xc1: // string case 0xc2: // false return object_complete(uk, Qfalse); case 0xc3: // true return object_complete(uk, Qtrue); case 0xc7: // ext 8 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); uint8_t length = cb->u8; int ext_type = (signed char) cb->buffer[1]; if(length == 0) { return object_complete_ext(uk, ext_type, rb_str_buf_new(0)); } uk->reading_raw_remaining = length; return read_raw_body_begin(uk, ext_type); } case 0xc8: // ext 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 3); uint16_t length = _msgpack_be16(cb->u16); int ext_type = (signed char) cb->buffer[2]; if(length == 0) { return object_complete_ext(uk, ext_type, rb_str_buf_new(0)); } uk->reading_raw_remaining = length; return read_raw_body_begin(uk, ext_type); } case 0xc9: // ext 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 5); uint32_t length = _msgpack_be32(cb->u32); int ext_type = (signed char) cb->buffer[4]; if(length == 0) { return object_complete_ext(uk, ext_type, rb_str_buf_new(0)); } uk->reading_raw_remaining = length; return read_raw_body_begin(uk, ext_type); } case 0xca: // float { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); cb->u32 = _msgpack_be_float(cb->u32); return object_complete(uk, rb_float_new(cb->f)); } case 0xcb: // double { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8); cb->u64 = _msgpack_be_double(cb->u64); return object_complete(uk, rb_float_new(cb->d)); } case 0xcc: // unsigned int 8 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); uint8_t u8 = cb->u8; return object_complete(uk, INT2NUM((int)u8)); } case 0xcd: // unsigned int 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); uint16_t u16 = _msgpack_be16(cb->u16); return object_complete(uk, INT2NUM((int)u16)); } case 0xce: // unsigned int 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); uint32_t u32 = _msgpack_be32(cb->u32); return object_complete(uk, ULONG2NUM((unsigned long)u32)); } case 0xcf: // unsigned int 64 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8); uint64_t u64 = _msgpack_be64(cb->u64); return object_complete(uk, rb_ull2inum(u64)); } case 0xd0: // signed int 8 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); int8_t i8 = cb->i8; return object_complete(uk, INT2NUM((int)i8)); } case 0xd1: // signed int 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); int16_t i16 = _msgpack_be16(cb->i16); return object_complete(uk, INT2NUM((int)i16)); } case 0xd2: // signed int 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); int32_t i32 = _msgpack_be32(cb->i32); return object_complete(uk, LONG2NUM((long)i32)); } case 0xd3: // signed int 64 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8); int64_t i64 = _msgpack_be64(cb->i64); return object_complete(uk, rb_ll2inum(i64)); } case 0xd4: // fixext 1 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); int ext_type = cb->i8; uk->reading_raw_remaining = 1; return read_raw_body_begin(uk, ext_type); } case 0xd5: // fixext 2 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); int ext_type = cb->i8; uk->reading_raw_remaining = 2; return read_raw_body_begin(uk, ext_type); } case 0xd6: // fixext 4 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); int ext_type = cb->i8; uk->reading_raw_remaining = 4; return read_raw_body_begin(uk, ext_type); } case 0xd7: // fixext 8 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); int ext_type = cb->i8; uk->reading_raw_remaining = 8; return read_raw_body_begin(uk, ext_type); } case 0xd8: // fixext 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); int ext_type = cb->i8; uk->reading_raw_remaining = 16; return read_raw_body_begin(uk, ext_type); } case 0xd9: // raw 8 / str 8 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); uint8_t count = cb->u8; if(count == 0) { return object_complete(uk, rb_utf8_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_STRING); } case 0xda: // raw 16 / str 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); uint16_t count = _msgpack_be16(cb->u16); if(count == 0) { return object_complete(uk, rb_utf8_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_STRING); } case 0xdb: // raw 32 / str 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); uint32_t count = _msgpack_be32(cb->u32); if(count == 0) { return object_complete(uk, rb_utf8_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_STRING); } case 0xc4: // bin 8 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1); uint8_t count = cb->u8; if(count == 0) { return object_complete(uk, rb_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_BINARY); } case 0xc5: // bin 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); uint16_t count = _msgpack_be16(cb->u16); if(count == 0) { return object_complete(uk, rb_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_BINARY); } case 0xc6: // bin 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); uint32_t count = _msgpack_be32(cb->u32); if(count == 0) { return object_complete(uk, rb_str_new_static("", 0)); } /* read_raw_body_begin sets uk->reading_raw */ uk->reading_raw_remaining = count; return read_raw_body_begin(uk, RAW_TYPE_BINARY); } case 0xdc: // array 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); uint16_t count = _msgpack_be16(cb->u16); if(count == 0) { return object_complete(uk, rb_ary_new()); } return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(count)); } case 0xdd: // array 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); uint32_t count = _msgpack_be32(cb->u32); if(count == 0) { return object_complete(uk, rb_ary_new()); } return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(count)); } case 0xde: // map 16 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); uint16_t count = _msgpack_be16(cb->u16); if(count == 0) { return object_complete(uk, rb_hash_new()); } return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new()); } case 0xdf: // map 32 { READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); uint32_t count = _msgpack_be32(cb->u32); if(count == 0) { return object_complete(uk, rb_hash_new()); } return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new()); } default: return PRIMITIVE_INVALID_BYTE; } SWITCH_RANGE_DEFAULT return PRIMITIVE_INVALID_BYTE; SWITCH_RANGE_END } int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint32_t* result_size) { int b = get_head_byte(uk); if(b < 0) { return b; } if(0x90 <= b && b <= 0x9f) { *result_size = b & 0x0f; } else if(b == 0xdc) { /* array 16 */ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); *result_size = _msgpack_be16(cb->u16); } else if(b == 0xdd) { /* array 32 */ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); *result_size = _msgpack_be32(cb->u32); } else { return PRIMITIVE_UNEXPECTED_TYPE; } reset_head_byte(uk); return 0; } int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_size) { int b = get_head_byte(uk); if(b < 0) { return b; } if(0x80 <= b && b <= 0x8f) { *result_size = b & 0x0f; } else if(b == 0xde) { /* map 16 */ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2); *result_size = _msgpack_be16(cb->u16); } else if(b == 0xdf) { /* map 32 */ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4); *result_size = _msgpack_be32(cb->u32); } else { return PRIMITIVE_UNEXPECTED_TYPE; } reset_head_byte(uk); return 0; } int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth) { while(true) { int r = read_primitive(uk); if(r < 0) { return r; } if(r == PRIMITIVE_CONTAINER_START) { continue; } /* PRIMITIVE_OBJECT_COMPLETE */ if(msgpack_unpacker_stack_is_empty(uk)) { return PRIMITIVE_OBJECT_COMPLETE; } container_completed: { msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk); switch(top->type) { case STACK_TYPE_ARRAY: rb_ary_push(top->object, uk->last_object); break; case STACK_TYPE_MAP_KEY: top->key = uk->last_object; top->type = STACK_TYPE_MAP_VALUE; break; case STACK_TYPE_MAP_VALUE: if(uk->symbolize_keys && rb_type(top->key) == T_STRING) { /* here uses rb_intern_str instead of rb_intern so that Ruby VM can GC unused symbols */ #ifdef HAVE_RB_STR_INTERN /* rb_str_intern is added since MRI 2.2.0 */ rb_hash_aset(top->object, rb_str_intern(top->key), uk->last_object); #else #ifndef HAVE_RB_INTERN_STR /* MRI 1.8 doesn't have rb_intern_str or rb_intern2 */ rb_hash_aset(top->object, ID2SYM(rb_intern(RSTRING_PTR(top->key))), uk->last_object); #else rb_hash_aset(top->object, ID2SYM(rb_intern_str(top->key)), uk->last_object); #endif #endif } else { rb_hash_aset(top->object, top->key, uk->last_object); } top->type = STACK_TYPE_MAP_KEY; break; } size_t count = --top->count; if(count == 0) { object_complete(uk, top->object); if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) { return PRIMITIVE_OBJECT_COMPLETE; } goto container_completed; } } } } int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth) { while(true) { int r = read_primitive(uk); if(r < 0) { return r; } if(r == PRIMITIVE_CONTAINER_START) { continue; } /* PRIMITIVE_OBJECT_COMPLETE */ if(msgpack_unpacker_stack_is_empty(uk)) { return PRIMITIVE_OBJECT_COMPLETE; } container_completed: { msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk); /* this section optimized out */ // TODO object_complete still creates objects which should be optimized out size_t count = --top->count; if(count == 0) { object_complete(uk, Qnil); if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) { return PRIMITIVE_OBJECT_COMPLETE; } goto container_completed; } } } } int msgpack_unpacker_peek_next_object_type(msgpack_unpacker_t* uk) { int b = get_head_byte(uk); if(b < 0) { return b; } SWITCH_RANGE_BEGIN(b) SWITCH_RANGE(b, 0x00, 0x7f) // Positive Fixnum return TYPE_INTEGER; SWITCH_RANGE(b, 0xe0, 0xff) // Negative Fixnum return TYPE_INTEGER; SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw return TYPE_RAW; SWITCH_RANGE(b, 0x90, 0x9f) // FixArray return TYPE_ARRAY; SWITCH_RANGE(b, 0x80, 0x8f) // FixMap return TYPE_MAP; SWITCH_RANGE(b, 0xc0, 0xdf) // Variable switch(b) { case 0xc0: // nil return TYPE_NIL; case 0xc2: // false case 0xc3: // true return TYPE_BOOLEAN; case 0xca: // float case 0xcb: // double return TYPE_FLOAT; case 0xcc: // unsigned int 8 case 0xcd: // unsigned int 16 case 0xce: // unsigned int 32 case 0xcf: // unsigned int 64 return TYPE_INTEGER; case 0xd0: // signed int 8 case 0xd1: // signed int 16 case 0xd2: // signed int 32 case 0xd3: // signed int 64 return TYPE_INTEGER; case 0xd9: // raw 8 / str 8 case 0xda: // raw 16 / str 16 case 0xdb: // raw 32 / str 32 return TYPE_RAW; case 0xc4: // bin 8 case 0xc5: // bin 16 case 0xc6: // bin 32 return TYPE_RAW; case 0xdc: // array 16 case 0xdd: // array 32 return TYPE_ARRAY; case 0xde: // map 16 case 0xdf: // map 32 return TYPE_MAP; default: return PRIMITIVE_INVALID_BYTE; } SWITCH_RANGE_DEFAULT return PRIMITIVE_INVALID_BYTE; SWITCH_RANGE_END } int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk) { int b = get_head_byte(uk); if(b < 0) { return b; } if(b == 0xc0) { return 1; } return 0; } msgpack-1.4.2/ext/msgpack/packer_ext_registry.h0000644000004100000410000001054714021120706021646 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2015 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_PACKER_EXT_REGISTRY_H__ #define MSGPACK_RUBY_PACKER_EXT_REGISTRY_H__ #include "compat.h" #include "ruby.h" struct msgpack_packer_ext_registry_t; typedef struct msgpack_packer_ext_registry_t msgpack_packer_ext_registry_t; struct msgpack_packer_ext_registry_t { VALUE hash; VALUE cache; // lookup cache for ext types inherited from a super class }; void msgpack_packer_ext_registry_static_init(); void msgpack_packer_ext_registry_static_destroy(); void msgpack_packer_ext_registry_init(msgpack_packer_ext_registry_t* pkrg); static inline void msgpack_packer_ext_registry_destroy(msgpack_packer_ext_registry_t* pkrg) { } void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg); void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src, msgpack_packer_ext_registry_t* dst); VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg, VALUE ext_module, int ext_type, VALUE proc, VALUE arg); static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg) { VALUE *args = (VALUE *) arg; if(key == Qundef) { return ST_CONTINUE; } if(rb_class_inherited_p(args[0], key) == Qtrue) { args[1] = key; return ST_STOP; } return ST_CONTINUE; } static inline VALUE msgpack_packer_ext_registry_fetch(msgpack_packer_ext_registry_t* pkrg, VALUE lookup_class, int* ext_type_result) { // fetch lookup_class from hash, which is a hash to register classes VALUE type = rb_hash_lookup(pkrg->hash, lookup_class); if(type != Qnil) { *ext_type_result = FIX2INT(rb_ary_entry(type, 0)); return rb_ary_entry(type, 1); } // fetch lookup_class from cache, which stores results of searching ancestors from pkrg->hash VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class); if(type_inht != Qnil) { *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0)); return rb_ary_entry(type_inht, 1); } return Qnil; } static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_registry_t* pkrg, VALUE instance, int* ext_type_result) { VALUE lookup_class; VALUE type; /* * 1. check whether singleton_class of this instance is registered (or resolved in past) or not. * * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen * String have no singleton class and raise a TypeError when trying to get * it. See implementation of #singleton_class in ruby's source code: * VALUE rb_singleton_class(VALUE obj); * * Since all but symbols are already filtered out when reaching this code * only symbols are checked here. */ if (!SYMBOL_P(instance)) { lookup_class = rb_singleton_class(instance); type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result); if(type != Qnil) { return type; } } /* * 2. check the class of instance is registered (or resolved in past) or not. */ type = msgpack_packer_ext_registry_fetch(pkrg, rb_obj_class(instance), ext_type_result); if(type != Qnil) { return type; } /* * 3. check all keys whether it is an ancestor of lookup_class, or not */ VALUE args[2]; args[0] = lookup_class; args[1] = Qnil; rb_hash_foreach(pkrg->hash, msgpack_packer_ext_find_superclass, (VALUE) args); VALUE superclass = args[1]; if(superclass != Qnil) { VALUE superclass_type = rb_hash_lookup(pkrg->hash, superclass); rb_hash_aset(pkrg->cache, lookup_class, superclass_type); *ext_type_result = FIX2INT(rb_ary_entry(superclass_type, 0)); return rb_ary_entry(superclass_type, 1); } return Qnil; } #endif msgpack-1.4.2/ext/msgpack/buffer_class.c0000644000004100000410000003000214021120706020206 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "compat.h" #include "ruby.h" #include "buffer.h" #include "buffer_class.h" VALUE cMessagePack_Buffer; static ID s_read; static ID s_readpartial; static ID s_write; static ID s_append; static ID s_close; #define BUFFER(from, name) \ msgpack_buffer_t *name = NULL; \ Data_Get_Struct(from, msgpack_buffer_t, name); \ if(name == NULL) { \ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \ } #define CHECK_STRING_TYPE(value) \ value = rb_check_string_type(value); \ if( NIL_P(value) ) { \ rb_raise(rb_eTypeError, "instance of String needed"); \ } static void Buffer_free(void* data) { if(data == NULL) { return; } msgpack_buffer_t* b = (msgpack_buffer_t*) data; msgpack_buffer_destroy(b); xfree(b); } static VALUE Buffer_alloc(VALUE klass) { msgpack_buffer_t* b = ZALLOC_N(msgpack_buffer_t, 1); msgpack_buffer_init(b); return Data_Wrap_Struct(klass, msgpack_buffer_mark, Buffer_free, b); } static ID get_partial_read_method(VALUE io) { if(rb_respond_to(io, s_readpartial)) { return s_readpartial; } else if(rb_respond_to(io, s_read)) { return s_read; } else { return s_read; } } static ID get_write_all_method(VALUE io) { if(rb_respond_to(io, s_write)) { return s_write; } else if(rb_respond_to(io, s_append)) { return s_append; } else { return s_write; } } void MessagePack_Buffer_set_options(msgpack_buffer_t* b, VALUE io, VALUE options) { b->io = io; b->io_partial_read_method = get_partial_read_method(io); b->io_write_all_method = get_write_all_method(io); if(options != Qnil) { VALUE v; v = rb_hash_aref(options, ID2SYM(rb_intern("read_reference_threshold"))); if(v != Qnil) { msgpack_buffer_set_read_reference_threshold(b, NUM2ULONG(v)); } v = rb_hash_aref(options, ID2SYM(rb_intern("write_reference_threshold"))); if(v != Qnil) { msgpack_buffer_set_write_reference_threshold(b, NUM2ULONG(v)); } v = rb_hash_aref(options, ID2SYM(rb_intern("io_buffer_size"))); if(v != Qnil) { msgpack_buffer_set_io_buffer_size(b, NUM2ULONG(v)); } } } VALUE MessagePack_Buffer_wrap(msgpack_buffer_t* b, VALUE owner) { b->owner = owner; return Data_Wrap_Struct(cMessagePack_Buffer, msgpack_buffer_mark, NULL, b); } static VALUE Buffer_initialize(int argc, VALUE* argv, VALUE self) { VALUE io = Qnil; VALUE options = Qnil; if(argc == 0 || (argc == 1 && argv[0] == Qnil)) { /* Qnil */ } else if(argc == 1) { VALUE v = argv[0]; if(rb_type(v) == T_HASH) { options = v; } else { io = v; } } else if(argc == 2) { io = argv[0]; options = argv[1]; if(rb_type(options) != T_HASH) { rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(io)); } } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc); } BUFFER(self, b); MessagePack_Buffer_set_options(b, io, options); return self; } static VALUE Buffer_clear(VALUE self) { BUFFER(self, b); msgpack_buffer_clear(b); return Qnil; } static VALUE Buffer_size(VALUE self) { BUFFER(self, b); size_t size = msgpack_buffer_all_readable_size(b); return SIZET2NUM(size); } static VALUE Buffer_empty_p(VALUE self) { BUFFER(self, b); if(msgpack_buffer_top_readable_size(b) == 0) { return Qtrue; } else { return Qfalse; } } static VALUE Buffer_write(VALUE self, VALUE string_or_buffer) { BUFFER(self, b); VALUE string = string_or_buffer; // TODO optimize if string_or_buffer is a Buffer StringValue(string); size_t length = msgpack_buffer_append_string(b, string); return SIZET2NUM(length); } static VALUE Buffer_append(VALUE self, VALUE string_or_buffer) { BUFFER(self, b); VALUE string = string_or_buffer; // TODO optimize if string_or_buffer is a Buffer StringValue(string); msgpack_buffer_append_string(b, string); return self; } #define MAKE_EMPTY_STRING(orig) \ if(orig == Qnil) { \ orig = rb_str_buf_new(0); \ } else { \ rb_str_resize(orig, 0); \ } static VALUE read_until_eof_rescue(VALUE args) { msgpack_buffer_t* b = (void*) ((VALUE*) args)[0]; VALUE out = ((VALUE*) args)[1]; unsigned long max = ((VALUE*) args)[2]; size_t* sz = (void*) ((VALUE*) args)[3]; while(true) { size_t rl; if(max == 0) { if(out == Qnil) { rl = msgpack_buffer_skip(b, b->io_buffer_size); } else { rl = msgpack_buffer_read_to_string(b, out, b->io_buffer_size); } if(rl == 0) { break; } *sz += rl; } else { if(out == Qnil) { rl = msgpack_buffer_skip(b, max); } else { rl = msgpack_buffer_read_to_string(b, out, max); } if(rl == 0) { break; } *sz += rl; if(max <= rl) { break; } else { max -= rl; } } } return Qnil; } static VALUE read_until_eof_error(VALUE args) { /* ignore EOFError */ UNUSED(args); return Qnil; } static inline size_t read_until_eof(msgpack_buffer_t* b, VALUE out, unsigned long max) { if(msgpack_buffer_has_io(b)) { size_t sz = 0; VALUE args[4] = { (VALUE)(void*) b, out, (VALUE) max, (VALUE)(void*) &sz }; rb_rescue2(read_until_eof_rescue, (VALUE)(void*) args, read_until_eof_error, (VALUE)(void*) args, rb_eEOFError, NULL); return sz; } else { if(max == 0) { max = ULONG_MAX; } if(out == Qnil) { return msgpack_buffer_skip_nonblock(b, max); } else { return msgpack_buffer_read_to_string_nonblock(b, out, max); } } } static inline VALUE read_all(msgpack_buffer_t* b, VALUE out) { #ifndef DISABLE_BUFFER_READ_TO_S_OPTIMIZE if(out == Qnil && !msgpack_buffer_has_io(b)) { /* same as to_s && clear; optimize */ VALUE str = msgpack_buffer_all_as_string(b); msgpack_buffer_clear(b); return str; } #endif MAKE_EMPTY_STRING(out); read_until_eof(b, out, 0); return out; } static VALUE Buffer_skip(VALUE self, VALUE sn) { BUFFER(self, b); unsigned long n = FIX2ULONG(sn); /* do nothing */ if(n == 0) { return ULONG2NUM(0); } size_t sz = read_until_eof(b, Qnil, n); return ULONG2NUM(sz); } static VALUE Buffer_skip_all(VALUE self, VALUE sn) { BUFFER(self, b); unsigned long n = FIX2ULONG(sn); /* do nothing */ if(n == 0) { return self; } if(!msgpack_buffer_ensure_readable(b, n)) { rb_raise(rb_eEOFError, "end of buffer reached"); } msgpack_buffer_skip_nonblock(b, n); return self; } static VALUE Buffer_read_all(int argc, VALUE* argv, VALUE self) { VALUE out = Qnil; unsigned long n = 0; bool all = false; switch(argc) { case 2: out = argv[1]; /* pass through */ case 1: n = FIX2ULONG(argv[0]); break; case 0: all = true; break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); } BUFFER(self, b); if(out != Qnil) { CHECK_STRING_TYPE(out); } if(all) { return read_all(b, out); } if(n == 0) { /* do nothing */ MAKE_EMPTY_STRING(out); return out; } if(!msgpack_buffer_ensure_readable(b, n)) { rb_raise(rb_eEOFError, "end of buffer reached"); } MAKE_EMPTY_STRING(out); msgpack_buffer_read_to_string_nonblock(b, out, n); return out; } static VALUE Buffer_read(int argc, VALUE* argv, VALUE self) { VALUE out = Qnil; unsigned long n = -1; bool all = false; switch(argc) { case 2: out = argv[1]; /* pass through */ case 1: n = FIX2ULONG(argv[0]); break; case 0: all = true; break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); } BUFFER(self, b); if(out != Qnil) { CHECK_STRING_TYPE(out); } if(all) { return read_all(b, out); } if(n == 0) { /* do nothing */ MAKE_EMPTY_STRING(out); return out; } #ifndef DISABLE_BUFFER_READ_TO_S_OPTIMIZE if(!msgpack_buffer_has_io(b) && out == Qnil && msgpack_buffer_all_readable_size(b) <= n) { /* same as to_s && clear; optimize */ VALUE str = msgpack_buffer_all_as_string(b); msgpack_buffer_clear(b); if(RSTRING_LEN(str) == 0) { return Qnil; } else { return str; } } #endif MAKE_EMPTY_STRING(out); read_until_eof(b, out, n); if(RSTRING_LEN(out) == 0) { return Qnil; } else { return out; } } static VALUE Buffer_to_str(VALUE self) { BUFFER(self, b); return msgpack_buffer_all_as_string(b); } static VALUE Buffer_to_a(VALUE self) { BUFFER(self, b); return msgpack_buffer_all_as_string_array(b); } static VALUE Buffer_flush(VALUE self) { BUFFER(self, b); msgpack_buffer_flush(b); return self; } static VALUE Buffer_io(VALUE self) { BUFFER(self, b); return b->io; } static VALUE Buffer_close(VALUE self) { BUFFER(self, b); if(b->io != Qnil) { return rb_funcall(b->io, s_close, 0); } return Qnil; } static VALUE Buffer_write_to(VALUE self, VALUE io) { BUFFER(self, b); size_t sz = msgpack_buffer_flush_to_io(b, io, s_write, true); return ULONG2NUM(sz); } void MessagePack_Buffer_module_init(VALUE mMessagePack) { s_read = rb_intern("read"); s_readpartial = rb_intern("readpartial"); s_write = rb_intern("write"); s_append = rb_intern("<<"); s_close = rb_intern("close"); msgpack_buffer_static_init(); cMessagePack_Buffer = rb_define_class_under(mMessagePack, "Buffer", rb_cObject); rb_define_alloc_func(cMessagePack_Buffer, Buffer_alloc); rb_define_method(cMessagePack_Buffer, "initialize", Buffer_initialize, -1); rb_define_method(cMessagePack_Buffer, "clear", Buffer_clear, 0); rb_define_method(cMessagePack_Buffer, "size", Buffer_size, 0); rb_define_method(cMessagePack_Buffer, "empty?", Buffer_empty_p, 0); rb_define_method(cMessagePack_Buffer, "write", Buffer_write, 1); rb_define_method(cMessagePack_Buffer, "<<", Buffer_append, 1); rb_define_method(cMessagePack_Buffer, "skip", Buffer_skip, 1); rb_define_method(cMessagePack_Buffer, "skip_all", Buffer_skip_all, 1); rb_define_method(cMessagePack_Buffer, "read", Buffer_read, -1); rb_define_method(cMessagePack_Buffer, "read_all", Buffer_read_all, -1); rb_define_method(cMessagePack_Buffer, "io", Buffer_io, 0); rb_define_method(cMessagePack_Buffer, "flush", Buffer_flush, 0); rb_define_method(cMessagePack_Buffer, "close", Buffer_close, 0); rb_define_method(cMessagePack_Buffer, "write_to", Buffer_write_to, 1); rb_define_method(cMessagePack_Buffer, "to_str", Buffer_to_str, 0); rb_define_alias(cMessagePack_Buffer, "to_s", "to_str"); rb_define_method(cMessagePack_Buffer, "to_a", Buffer_to_a, 0); } msgpack-1.4.2/ext/msgpack/unpacker_ext_registry.h0000644000004100000410000000354514021120706022211 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2015 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_UNPACKER_EXT_REGISTRY_H__ #define MSGPACK_RUBY_UNPACKER_EXT_REGISTRY_H__ #include "compat.h" #include "ruby.h" struct msgpack_unpacker_ext_registry_t; typedef struct msgpack_unpacker_ext_registry_t msgpack_unpacker_ext_registry_t; struct msgpack_unpacker_ext_registry_t { VALUE array[256]; //int bitmap; }; void msgpack_unpacker_ext_registry_static_init(); void msgpack_unpacker_ext_registry_static_destroy(); void msgpack_unpacker_ext_registry_init(msgpack_unpacker_ext_registry_t* ukrg); static inline void msgpack_unpacker_ext_registry_destroy(msgpack_unpacker_ext_registry_t* ukrg) { } void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg); void msgpack_unpacker_ext_registry_dup(msgpack_unpacker_ext_registry_t* src, msgpack_unpacker_ext_registry_t* dst); VALUE msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t* ukrg, VALUE ext_module, int ext_type, VALUE proc, VALUE arg); static inline VALUE msgpack_unpacker_ext_registry_lookup(msgpack_unpacker_ext_registry_t* ukrg, int ext_type) { VALUE e = ukrg->array[ext_type + 128]; if(e == Qnil) { return Qnil; } return rb_ary_entry(e, 1); } #endif msgpack-1.4.2/ext/msgpack/unpacker_ext_registry.c0000644000004100000410000000330514021120706022176 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2015 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "unpacker_ext_registry.h" static ID s_call; static ID s_dup; void msgpack_unpacker_ext_registry_static_init() { s_call = rb_intern("call"); s_dup = rb_intern("dup"); } void msgpack_unpacker_ext_registry_static_destroy() { } void msgpack_unpacker_ext_registry_init(msgpack_unpacker_ext_registry_t* ukrg) { for(int i=0; i < 256; i++) { ukrg->array[i] = Qnil; } } void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg) { for(int i=0; i < 256; i++) { rb_gc_mark(ukrg->array[i]); } } void msgpack_unpacker_ext_registry_dup(msgpack_unpacker_ext_registry_t* src, msgpack_unpacker_ext_registry_t* dst) { for(int i=0; i < 256; i++) { dst->array[i] = src->array[i]; } } VALUE msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t* ukrg, VALUE ext_module, int ext_type, VALUE proc, VALUE arg) { VALUE e = rb_ary_new3(3, ext_module, proc, arg); VALUE before = ukrg->array[ext_type + 128]; ukrg->array[ext_type + 128] = e; return before; } msgpack-1.4.2/ext/msgpack/packer_ext_registry.c0000644000004100000410000000416714021120706021642 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2015 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "packer_ext_registry.h" static ID s_call; void msgpack_packer_ext_registry_static_init() { s_call = rb_intern("call"); } void msgpack_packer_ext_registry_static_destroy() { } void msgpack_packer_ext_registry_init(msgpack_packer_ext_registry_t* pkrg) { pkrg->hash = rb_hash_new(); pkrg->cache = rb_hash_new(); } void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg) { rb_gc_mark(pkrg->hash); rb_gc_mark(pkrg->cache); } void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src, msgpack_packer_ext_registry_t* dst) { #ifdef HAVE_RB_HASH_DUP dst->hash = rb_hash_dup(src->hash); dst->cache = rb_hash_dup(src->cache); #else dst->hash = rb_funcall(src->hash, rb_intern("dup"), 0); dst->cache = rb_funcall(src->cache, rb_intern("dup"), 0); #endif } #ifndef HAVE_RB_HASH_CLEAR static int __rb_hash_clear_clear_i(key, value, dummy) VALUE key, value, dummy; { return ST_DELETE; } #endif VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg, VALUE ext_module, int ext_type, VALUE proc, VALUE arg) { VALUE e = rb_ary_new3(3, INT2FIX(ext_type), proc, arg); /* clear lookup cache not to miss added type */ #ifdef HAVE_RB_HASH_CLEAR rb_hash_clear(pkrg->cache); #else if(FIX2INT(rb_funcall(pkrg->cache, rb_intern("size"), 0)) > 0) { rb_hash_foreach(pkrg->cache, __rb_hash_clear_clear_i, 0); } #endif return rb_hash_aset(pkrg->hash, ext_module, e); } msgpack-1.4.2/ext/msgpack/sysdep_types.h0000644000004100000410000000227714021120706020325 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_SYSDEP_TYPES_H__ #define MSGPACK_RUBY_SYSDEP_TYPES_H__ #include #include #include #if defined(_MSC_VER) && _MSC_VER < 1600 typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #elif defined(_MSC_VER) // && _MSC_VER >= 1600 #include #else #include #include #endif #endif msgpack-1.4.2/ext/msgpack/unpacker_class.h0000644000004100000410000000174514021120706020566 0ustar www-datawww-data/* * MessagePack for Ruby * * Copyright (C) 2008-2013 Sadayuki Furuhashi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_RUBY_UNPACKER_CLASS_H__ #define MSGPACK_RUBY_UNPACKER_CLASS_H__ #include "unpacker.h" extern VALUE cMessagePack_Unpacker; void MessagePack_Unpacker_module_init(VALUE mMessagePack); VALUE MessagePack_Unpacker_alloc(VALUE klass); VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self); #endif msgpack-1.4.2/ext/java/0000755000004100000410000000000014021120706014705 5ustar www-datawww-datamsgpack-1.4.2/ext/java/org/0000755000004100000410000000000014021120706015474 5ustar www-datawww-datamsgpack-1.4.2/ext/java/org/msgpack/0000755000004100000410000000000014021120706017121 5ustar www-datawww-datamsgpack-1.4.2/ext/java/org/msgpack/jruby/0000755000004100000410000000000014021120706020254 5ustar www-datawww-datamsgpack-1.4.2/ext/java/org/msgpack/jruby/Decoder.java0000644000004100000410000002460314021120706022471 0ustar www-datawww-datapackage org.msgpack.jruby; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; import java.util.Iterator; import java.util.Arrays; import org.jruby.Ruby; import org.jruby.RubyObject; import org.jruby.RubyClass; import org.jruby.RubyBignum; import org.jruby.RubyString; import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.exceptions.RaiseException; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; import org.jcodings.Encoding; import org.jcodings.specific.UTF8Encoding; import static org.msgpack.jruby.Types.*; public class Decoder implements Iterator { private final Ruby runtime; private final Encoding binaryEncoding; private final Encoding utf8Encoding; private final RubyClass unpackErrorClass; private final RubyClass underflowErrorClass; private final RubyClass malformedFormatErrorClass; private final RubyClass stackErrorClass; private final RubyClass unexpectedTypeErrorClass; private final RubyClass unknownExtTypeErrorClass; private ExtensionRegistry registry; private ByteBuffer buffer; private boolean symbolizeKeys; private boolean freeze; private boolean allowUnknownExt; public Decoder(Ruby runtime) { this(runtime, null, new byte[] {}, 0, 0, false, false, false); } public Decoder(Ruby runtime, ExtensionRegistry registry) { this(runtime, registry, new byte[] {}, 0, 0, false, false, false); } public Decoder(Ruby runtime, byte[] bytes) { this(runtime, null, bytes, 0, bytes.length, false, false, false); } public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes) { this(runtime, registry, bytes, 0, bytes.length, false, false, false); } public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) { this(runtime, registry, bytes, 0, bytes.length, symbolizeKeys, freeze, allowUnknownExt); } public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length) { this(runtime, registry, bytes, offset, length, false, false, false); } public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) { this.runtime = runtime; this.registry = registry; this.symbolizeKeys = symbolizeKeys; this.freeze = freeze; this.allowUnknownExt = allowUnknownExt; this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding(); this.utf8Encoding = UTF8Encoding.INSTANCE; this.unpackErrorClass = runtime.getModule("MessagePack").getClass("UnpackError"); this.underflowErrorClass = runtime.getModule("MessagePack").getClass("UnderflowError"); this.malformedFormatErrorClass = runtime.getModule("MessagePack").getClass("MalformedFormatError"); this.stackErrorClass = runtime.getModule("MessagePack").getClass("StackError"); this.unexpectedTypeErrorClass = runtime.getModule("MessagePack").getClass("UnexpectedTypeError"); this.unknownExtTypeErrorClass = runtime.getModule("MessagePack").getClass("UnknownExtTypeError"); this.symbolizeKeys = symbolizeKeys; this.allowUnknownExt = allowUnknownExt; feed(bytes, offset, length); } public void feed(byte[] bytes) { feed(bytes, 0, bytes.length); } public void feed(byte[] bytes, int offset, int length) { if (buffer == null) { buffer = ByteBuffer.wrap(bytes, offset, length); } else { ByteBuffer newBuffer = ByteBuffer.allocate(buffer.remaining() + length); newBuffer.put(buffer); newBuffer.put(bytes, offset, length); newBuffer.flip(); buffer = newBuffer; } } public void reset() { buffer = null; } public int offset() { return buffer.position(); } private IRubyObject consumeUnsignedLong() { long value = buffer.getLong(); if (value < 0) { return RubyBignum.newBignum(runtime, BigInteger.valueOf(value & ((1L<<63)-1)).setBit(63)); } else { return runtime.newFixnum(value); } } private IRubyObject consumeString(int size, Encoding encoding) { byte[] bytes = readBytes(size); ByteList byteList = new ByteList(bytes, encoding); RubyString string = runtime.newString(byteList); if (this.freeze) { string.setFrozen(true); string = runtime.freezeAndDedupString(string); } return string; } private IRubyObject consumeArray(int size) { IRubyObject[] elements = new IRubyObject[size]; for (int i = 0; i < size; i++) { elements[i] = next(); } return runtime.newArray(elements); } private IRubyObject consumeHash(int size) { RubyHash hash = RubyHash.newHash(runtime); for (int i = 0; i < size; i++) { IRubyObject key = next(); if (this.symbolizeKeys && key instanceof RubyString) { key = ((RubyString) key).intern(); } hash.fastASet(key, next()); } return hash; } private IRubyObject consumeExtension(int size) { int type = buffer.get(); byte[] payload = readBytes(size); if (registry != null) { IRubyObject proc = registry.lookupUnpackerByTypeId(type); if (proc != null) { ByteList byteList = new ByteList(payload, runtime.getEncodingService().getAscii8bitEncoding()); return proc.callMethod(runtime.getCurrentContext(), "call", runtime.newString(byteList)); } } if (this.allowUnknownExt) { return ExtensionValue.newExtensionValue(runtime, type, payload); } throw runtime.newRaiseException(unknownExtTypeErrorClass, "unexpected extension type"); } private byte[] readBytes(int size) { byte[] payload = new byte[size]; buffer.get(payload); return payload; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public boolean hasNext() { return buffer.remaining() > 0; } public IRubyObject read_array_header() { int position = buffer.position(); try { byte b = buffer.get(); if ((b & 0xf0) == 0x90) { return runtime.newFixnum(b & 0x0f); } else if (b == ARY16) { return runtime.newFixnum(buffer.getShort() & 0xffff); } else if (b == ARY32) { return runtime.newFixnum(buffer.getInt()); } throw runtime.newRaiseException(unexpectedTypeErrorClass, "unexpected type"); } catch (RaiseException re) { buffer.position(position); throw re; } catch (BufferUnderflowException bue) { buffer.position(position); throw runtime.newRaiseException(underflowErrorClass, "Not enough bytes available"); } } public IRubyObject read_map_header() { int position = buffer.position(); try { byte b = buffer.get(); if ((b & 0xf0) == 0x80) { return runtime.newFixnum(b & 0x0f); } else if (b == MAP16) { return runtime.newFixnum(buffer.getShort() & 0xffff); } else if (b == MAP32) { return runtime.newFixnum(buffer.getInt()); } throw runtime.newRaiseException(unexpectedTypeErrorClass, "unexpected type"); } catch (RaiseException re) { buffer.position(position); throw re; } catch (BufferUnderflowException bue) { buffer.position(position); throw runtime.newRaiseException(underflowErrorClass, "Not enough bytes available"); } } @Override public IRubyObject next() { IRubyObject next = consumeNext(); if (freeze) { next.setFrozen(true); } return next; } private IRubyObject consumeNext() { int position = buffer.position(); try { byte b = buffer.get(); outer: switch ((b >> 4) & 0xf) { case 0x8: return consumeHash(b & 0x0f); case 0x9: return consumeArray(b & 0x0f); case 0xa: case 0xb: return consumeString(b & 0x1f, utf8Encoding); case 0xc: switch (b) { case NIL: return runtime.getNil(); case FALSE: return runtime.getFalse(); case TRUE: return runtime.getTrue(); case BIN8: return consumeString(buffer.get() & 0xff, binaryEncoding); case BIN16: return consumeString(buffer.getShort() & 0xffff, binaryEncoding); case BIN32: return consumeString(buffer.getInt(), binaryEncoding); case VAREXT8: return consumeExtension(buffer.get() & 0xff); case VAREXT16: return consumeExtension(buffer.getShort() & 0xffff); case VAREXT32: return consumeExtension(buffer.getInt()); case FLOAT32: return runtime.newFloat(buffer.getFloat()); case FLOAT64: return runtime.newFloat(buffer.getDouble()); case UINT8: return runtime.newFixnum(buffer.get() & 0xffL); case UINT16: return runtime.newFixnum(buffer.getShort() & 0xffffL); case UINT32: return runtime.newFixnum(buffer.getInt() & 0xffffffffL); case UINT64: return consumeUnsignedLong(); default: break outer; } case 0xd: switch (b) { case INT8: return runtime.newFixnum(buffer.get()); case INT16: return runtime.newFixnum(buffer.getShort()); case INT32: return runtime.newFixnum(buffer.getInt()); case INT64: return runtime.newFixnum(buffer.getLong()); case FIXEXT1: return consumeExtension(1); case FIXEXT2: return consumeExtension(2); case FIXEXT4: return consumeExtension(4); case FIXEXT8: return consumeExtension(8); case FIXEXT16: return consumeExtension(16); case STR8: return consumeString(buffer.get() & 0xff, utf8Encoding); case STR16: return consumeString(buffer.getShort() & 0xffff, utf8Encoding); case STR32: return consumeString(buffer.getInt(), utf8Encoding); case ARY16: return consumeArray(buffer.getShort() & 0xffff); case ARY32: return consumeArray(buffer.getInt()); case MAP16: return consumeHash(buffer.getShort() & 0xffff); case MAP32: return consumeHash(buffer.getInt()); default: break outer; } case 0xe: case 0xf: return runtime.newFixnum((0x1f & b) - 0x20); default: return runtime.newFixnum(b); } buffer.position(position); throw runtime.newRaiseException(malformedFormatErrorClass, "Illegal byte sequence"); } catch (RaiseException re) { buffer.position(position); throw re; } catch (BufferUnderflowException bue) { buffer.position(position); throw runtime.newRaiseException(underflowErrorClass, "Not enough bytes available"); } } } msgpack-1.4.2/ext/java/org/msgpack/jruby/ExtensionValue.java0000644000004100000410000000756514021120706024105 0ustar www-datawww-datapackage org.msgpack.jruby; import java.util.Arrays; import java.nio.ByteBuffer; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.RubyFixnum; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.util.ByteList; import static org.jruby.runtime.Visibility.PRIVATE; import org.jcodings.Encoding; import static org.msgpack.jruby.Types.*; @JRubyClass(name="MessagePack::ExtensionValue") public class ExtensionValue extends RubyObject { private final Encoding binaryEncoding; private RubyFixnum type; private RubyString payload; public ExtensionValue(Ruby runtime, RubyClass type) { super(runtime, type); this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding(); } public static class ExtensionValueAllocator implements ObjectAllocator { public IRubyObject allocate(Ruby runtime, RubyClass klass) { return new ExtensionValue(runtime, klass); } } public static ExtensionValue newExtensionValue(Ruby runtime, int type, byte[] payload) { ExtensionValue v = new ExtensionValue(runtime, runtime.getModule("MessagePack").getClass("ExtensionValue")); ByteList byteList = new ByteList(payload, runtime.getEncodingService().getAscii8bitEncoding()); v.initialize(runtime.getCurrentContext(), runtime.newFixnum(type), runtime.newString(byteList)); return v; } @JRubyMethod(name = "initialize", required = 2, visibility = PRIVATE) public IRubyObject initialize(ThreadContext ctx, IRubyObject type, IRubyObject payload) { this.type = (RubyFixnum) type; this.payload = (RubyString) payload; return this; } @JRubyMethod(name = {"to_s", "inspect"}) @Override public IRubyObject to_s() { IRubyObject payloadStr = payload.callMethod(getRuntime().getCurrentContext(), "inspect"); return getRuntime().newString(String.format("#", type.getLongValue(), payloadStr)); } @JRubyMethod(name = "hash") @Override public RubyFixnum hash() { long hash = payload.hashCode() ^ (type.getLongValue() << 56); return RubyFixnum.newFixnum(getRuntime(), hash); } @JRubyMethod(name = "eql?") public IRubyObject eql_p(ThreadContext ctx, IRubyObject o) { Ruby runtime = ctx.runtime; if (this == o) { return runtime.getTrue(); } if (o instanceof ExtensionValue) { ExtensionValue other = (ExtensionValue) o; if (!this.type.eql_p(other.type).isTrue()) return runtime.getFalse(); if (runtime.is1_8()) { return this.payload.str_eql_p(ctx, other.payload); } else { return this.payload.str_eql_p19(ctx, other.payload); } } return runtime.getFalse(); } @JRubyMethod(name = "==") public IRubyObject op_equal(ThreadContext ctx, IRubyObject o) { Ruby runtime = ctx.runtime; if (this == o) { return runtime.getTrue(); } if (o instanceof ExtensionValue) { ExtensionValue other = (ExtensionValue) o; if (!this.type.op_equal(ctx, other.type).isTrue()) return runtime.getFalse(); if (runtime.is1_8()) { return this.payload.op_equal(ctx, other.payload); } else { return this.payload.op_equal19(ctx, other.payload); } } return runtime.getFalse(); } @JRubyMethod(name = "type") public IRubyObject get_type() { return type; } @JRubyMethod public IRubyObject payload() { return payload; } @JRubyMethod(name = "type=", required = 1) public IRubyObject set_type(final IRubyObject tpe) { type = (RubyFixnum)tpe; return tpe; } @JRubyMethod(name = "payload=", required = 1) public IRubyObject set_payload(final IRubyObject pld) { payload = (RubyString)pld; return pld; } } msgpack-1.4.2/ext/java/org/msgpack/jruby/MessagePackLibrary.java0000644000004100000410000000532114021120706024630 0ustar www-datawww-datapackage org.msgpack.jruby; import org.jruby.Ruby; import org.jruby.RubyModule; import org.jruby.RubyClass; import org.jruby.RubyString; import org.jruby.RubyNil; import org.jruby.RubyBoolean; import org.jruby.RubyHash; import org.jruby.runtime.load.Library; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Block; import org.jruby.runtime.Visibility; import org.jruby.anno.JRubyModule; import org.jruby.anno.JRubyMethod; import org.jruby.internal.runtime.methods.CallConfiguration; import org.jruby.internal.runtime.methods.DynamicMethod; public class MessagePackLibrary implements Library { public void load(Ruby runtime, boolean wrap) { RubyModule msgpackModule = runtime.defineModule("MessagePack"); RubyClass standardErrorClass = runtime.getStandardError(); RubyClass unpackErrorClass = msgpackModule.defineClassUnder("UnpackError", standardErrorClass, standardErrorClass.getAllocator()); RubyClass underflowErrorClass = msgpackModule.defineClassUnder("UnderflowError", unpackErrorClass, unpackErrorClass.getAllocator()); RubyClass malformedFormatErrorClass = msgpackModule.defineClassUnder("MalformedFormatError", unpackErrorClass, unpackErrorClass.getAllocator()); RubyClass stackErrorClass = msgpackModule.defineClassUnder("StackError", unpackErrorClass, unpackErrorClass.getAllocator()); RubyModule typeErrorModule = msgpackModule.defineModuleUnder("TypeError"); RubyClass unexpectedTypeErrorClass = msgpackModule.defineClassUnder("UnexpectedTypeError", unpackErrorClass, unpackErrorClass.getAllocator()); unexpectedTypeErrorClass.includeModule(typeErrorModule); RubyClass unknownExtTypeErrorClass = msgpackModule.defineClassUnder("UnknownExtTypeError", unpackErrorClass, unpackErrorClass.getAllocator()); RubyClass extensionValueClass = msgpackModule.defineClassUnder("ExtensionValue", runtime.getObject(), new ExtensionValue.ExtensionValueAllocator()); extensionValueClass.defineAnnotatedMethods(ExtensionValue.class); RubyClass packerClass = msgpackModule.defineClassUnder("Packer", runtime.getObject(), new Packer.PackerAllocator()); packerClass.defineAnnotatedMethods(Packer.class); RubyClass unpackerClass = msgpackModule.defineClassUnder("Unpacker", runtime.getObject(), new Unpacker.UnpackerAllocator()); unpackerClass.defineAnnotatedMethods(Unpacker.class); RubyClass bufferClass = msgpackModule.defineClassUnder("Buffer", runtime.getObject(), new Buffer.BufferAllocator()); bufferClass.defineAnnotatedMethods(Buffer.class); RubyClass factoryClass = msgpackModule.defineClassUnder("Factory", runtime.getObject(), new Factory.FactoryAllocator()); factoryClass.defineAnnotatedMethods(Factory.class); } } msgpack-1.4.2/ext/java/org/msgpack/jruby/Factory.java0000644000004100000410000001041314021120706022525 0ustar www-datawww-datapackage org.msgpack.jruby; import org.jruby.Ruby; import org.jruby.RubyModule; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.RubyIO; import org.jruby.RubyInteger; import org.jruby.RubyFixnum; import org.jruby.RubyString; import org.jruby.RubySymbol; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.ObjectAllocator; import org.jruby.util.ByteList; import static org.jruby.runtime.Visibility.PRIVATE; @JRubyClass(name="MessagePack::Factory") public class Factory extends RubyObject { private final Ruby runtime; private final ExtensionRegistry extensionRegistry; private boolean hasSymbolExtType; public Factory(Ruby runtime, RubyClass type) { super(runtime, type); this.runtime = runtime; this.extensionRegistry = new ExtensionRegistry(); this.hasSymbolExtType = false; } static class FactoryAllocator implements ObjectAllocator { public IRubyObject allocate(Ruby runtime, RubyClass type) { return new Factory(runtime, type); } } public ExtensionRegistry extensionRegistry() { return extensionRegistry.dup(); } @JRubyMethod(name = "initialize") public IRubyObject initialize(ThreadContext ctx) { return this; } @JRubyMethod(name = "packer", optional = 1) public Packer packer(ThreadContext ctx, IRubyObject[] args) { return Packer.newPacker(ctx, extensionRegistry(), hasSymbolExtType, args); } @JRubyMethod(name = "unpacker", optional = 2) public Unpacker unpacker(ThreadContext ctx, IRubyObject[] args) { return Unpacker.newUnpacker(ctx, extensionRegistry(), args); } @JRubyMethod(name = "registered_types_internal", visibility = PRIVATE) public IRubyObject registeredTypesInternal(ThreadContext ctx) { return RubyArray.newArray(ctx.getRuntime(), new IRubyObject[] { extensionRegistry.toInternalPackerRegistry(ctx), extensionRegistry.toInternalUnpackerRegistry(ctx) }); } @JRubyMethod(name = "register_type", required = 2, optional = 1) public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args) { Ruby runtime = ctx.getRuntime(); IRubyObject type = args[0]; IRubyObject mod = args[1]; IRubyObject packerArg; IRubyObject unpackerArg; if (isFrozen()) { throw runtime.newRuntimeError("can't modify frozen Factory"); } if (args.length == 2) { packerArg = runtime.newSymbol("to_msgpack_ext"); unpackerArg = runtime.newSymbol("from_msgpack_ext"); } else if (args.length == 3) { if (args[args.length - 1] instanceof RubyHash) { RubyHash options = (RubyHash) args[args.length - 1]; packerArg = options.fastARef(runtime.newSymbol("packer")); unpackerArg = options.fastARef(runtime.newSymbol("unpacker")); } else { throw runtime.newArgumentError(String.format("expected Hash but found %s.", args[args.length - 1].getType().getName())); } } else { throw runtime.newArgumentError(String.format("wrong number of arguments (%d for 2..3)", 2 + args.length)); } long typeId = ((RubyFixnum) type).getLongValue(); if (typeId < -128 || typeId > 127) { throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId)); } if (!(mod instanceof RubyModule)) { throw runtime.newArgumentError(String.format("expected Module/Class but found %s.", mod.getType().getName())); } RubyModule extModule = (RubyModule) mod; IRubyObject packerProc = runtime.getNil(); IRubyObject unpackerProc = runtime.getNil(); if (packerArg != null) { packerProc = packerArg.callMethod(ctx, "to_proc"); } if (unpackerArg != null) { if (unpackerArg instanceof RubyString || unpackerArg instanceof RubySymbol) { unpackerProc = extModule.method(unpackerArg.callMethod(ctx, "to_sym")); } else { unpackerProc = unpackerArg.callMethod(ctx, "method", runtime.newSymbol("call")); } } extensionRegistry.put(extModule, (int) typeId, packerProc, packerArg, unpackerProc, unpackerArg); if (extModule == runtime.getSymbol()) { hasSymbolExtType = true; } return runtime.getNil(); } } msgpack-1.4.2/ext/java/org/msgpack/jruby/Packer.java0000644000004100000410000002156114021120706022331 0ustar www-datawww-datapackage org.msgpack.jruby; import org.jruby.Ruby; import org.jruby.RubyModule; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.RubyIO; import org.jruby.RubyNumeric; import org.jruby.RubyInteger; import org.jruby.RubyFixnum; import org.jruby.runtime.Block; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.ObjectAllocator; import org.jruby.util.ByteList; import org.jruby.util.TypeConverter; import org.msgpack.jruby.ExtensionValue; import org.jcodings.Encoding; import static org.jruby.runtime.Visibility.PRIVATE; @JRubyClass(name="MessagePack::Packer") public class Packer extends RubyObject { public ExtensionRegistry registry; private Buffer buffer; private Encoder encoder; private boolean hasSymbolExtType; private Encoding binaryEncoding; public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType) { super(runtime, type); this.registry = registry; this.hasSymbolExtType = hasSymbolExtType; } static class PackerAllocator implements ObjectAllocator { public IRubyObject allocate(Ruby runtime, RubyClass type) { return new Packer(runtime, type, null, false); } } @JRubyMethod(name = "initialize", optional = 2) public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) { boolean compatibilityMode = false; if (args.length > 0 && args[args.length - 1] instanceof RubyHash) { RubyHash options = (RubyHash) args[args.length - 1]; IRubyObject mode = options.fastARef(ctx.getRuntime().newSymbol("compatibility_mode")); compatibilityMode = (mode != null) && mode.isTrue(); } if (registry == null) { // registry is null when allocate -> initialize // registry is already initialized (and somthing might be registered) when newPacker from Factory this.registry = new ExtensionRegistry(); } this.encoder = new Encoder(ctx.getRuntime(), compatibilityMode, registry, hasSymbolExtType); this.buffer = new Buffer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Buffer")); this.buffer.initialize(ctx, args); this.binaryEncoding = ctx.getRuntime().getEncodingService().getAscii8bitEncoding(); return this; } public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, boolean hasSymbolExtType, IRubyObject[] args) { Packer packer = new Packer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Packer"), extRegistry, hasSymbolExtType); packer.initialize(ctx, args); return packer; } @JRubyMethod(name = "compatibility_mode?") public IRubyObject isCompatibilityMode(ThreadContext ctx) { return encoder.isCompatibilityMode() ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse(); } @JRubyMethod(name = "registered_types_internal", visibility = PRIVATE) public IRubyObject registeredTypesInternal(ThreadContext ctx) { return registry.toInternalPackerRegistry(ctx); } @JRubyMethod(name = "register_type", required = 2, optional = 1) public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) { Ruby runtime = ctx.getRuntime(); IRubyObject type = args[0]; IRubyObject mod = args[1]; IRubyObject arg; IRubyObject proc; if (args.length == 2) { if (! block.isGiven()) { throw runtime.newLocalJumpErrorNoBlock(); } proc = block.getProcObject(); arg = proc; } else if (args.length == 3) { arg = args[2]; proc = arg.callMethod(ctx, "to_proc"); } else { throw runtime.newArgumentError(String.format("wrong number of arguments (%d for 2..3)", 2 + args.length)); } long typeId = ((RubyFixnum) type).getLongValue(); if (typeId < -128 || typeId > 127) { throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId)); } if (!(mod instanceof RubyModule)) { throw runtime.newArgumentError(String.format("expected Module/Class but found %s.", mod.getType().getName())); } RubyModule extModule = (RubyModule) mod; registry.put(extModule, (int) typeId, proc, arg, null, null); if (extModule == runtime.getSymbol()) { encoder.hasSymbolExtType = true; } return runtime.getNil(); } @JRubyMethod(name = "write", alias = { "pack" }) public IRubyObject write(ThreadContext ctx, IRubyObject obj) { buffer.write(ctx, encoder.encode(obj, this)); return this; } @JRubyMethod(name = "write_float") public IRubyObject writeFloat(ThreadContext ctx, IRubyObject obj) { checkType(ctx, obj, org.jruby.RubyFloat.class); return write(ctx, obj); } @JRubyMethod(name = "write_array") public IRubyObject writeArray(ThreadContext ctx, IRubyObject obj) { checkType(ctx, obj, org.jruby.RubyArray.class); return write(ctx, obj); } @JRubyMethod(name = "write_string") public IRubyObject writeString(ThreadContext ctx, IRubyObject obj) { checkType(ctx, obj, org.jruby.RubyString.class); return write(ctx, obj); } @JRubyMethod(name = "write_bin") public IRubyObject writeBin(ThreadContext ctx, IRubyObject obj) { checkType(ctx, obj, org.jruby.RubyString.class); obj = ((org.jruby.RubyString) obj).encode(ctx, ctx.runtime.getEncodingService().getEncoding(binaryEncoding)); return write(ctx, obj); } @JRubyMethod(name = "write_hash") public IRubyObject writeHash(ThreadContext ctx, IRubyObject obj) { checkType(ctx, obj, org.jruby.RubyHash.class); return write(ctx, obj); } @JRubyMethod(name = "write_symbol") public IRubyObject writeSymbol(ThreadContext ctx, IRubyObject obj) { checkType(ctx, obj, org.jruby.RubySymbol.class); return write(ctx, obj); } @JRubyMethod(name = "write_int") public IRubyObject writeInt(ThreadContext ctx, IRubyObject obj) { if (!(obj instanceof RubyFixnum)) { checkType(ctx, obj, org.jruby.RubyBignum.class); } return write(ctx, obj); } @JRubyMethod(name = "write_extension") public IRubyObject writeExtension(ThreadContext ctx, IRubyObject obj) { if (!(obj instanceof ExtensionValue)) { throw ctx.runtime.newTypeError("Expected extension"); } return write(ctx, obj); } @JRubyMethod(name = "write_true") public IRubyObject writeTrue(ThreadContext ctx) { return write(ctx, ctx.getRuntime().getTrue()); } @JRubyMethod(name = "write_false") public IRubyObject writeFalse(ThreadContext ctx) { return write(ctx, ctx.getRuntime().getFalse()); } @JRubyMethod(name = "write_nil") public IRubyObject writeNil(ThreadContext ctx) { write(ctx, null); return this; } @JRubyMethod(name = "write_float32") public IRubyObject writeFloat32(ThreadContext ctx, IRubyObject numeric) { Ruby runtime = ctx.runtime; if (!(numeric instanceof RubyNumeric)) { throw runtime.newArgumentError("Expected numeric"); } buffer.write(ctx, encoder.encodeFloat32((RubyNumeric) numeric)); return this; } @JRubyMethod(name = "write_array_header") public IRubyObject writeArrayHeader(ThreadContext ctx, IRubyObject size) { int s = (int) size.convertToInteger().getLongValue(); buffer.write(ctx, encoder.encodeArrayHeader(s)); return this; } @JRubyMethod(name = "write_map_header") public IRubyObject writeMapHeader(ThreadContext ctx, IRubyObject size) { int s = (int) size.convertToInteger().getLongValue(); buffer.write(ctx, encoder.encodeMapHeader(s)); return this; } @JRubyMethod(name = "write_bin_header") public IRubyObject writeBinHeader(ThreadContext ctx, IRubyObject size) { int s = (int) size.convertToInteger().getLongValue(); buffer.write(ctx, encoder.encodeBinHeader(s)); return this; } @JRubyMethod(name = "full_pack") public IRubyObject fullPack(ThreadContext ctx) { if (buffer.hasIo()) { return null; } return toS(ctx); } @JRubyMethod(name = "to_s", alias = { "to_str" }) public IRubyObject toS(ThreadContext ctx) { return buffer.toS(ctx); } @JRubyMethod(name = "buffer") public IRubyObject buffer(ThreadContext ctx) { return buffer; } @JRubyMethod(name = "flush") public IRubyObject flush(ThreadContext ctx) { return buffer.flush(ctx); } @JRubyMethod(name = "size") public IRubyObject size(ThreadContext ctx) { return buffer.size(ctx); } @JRubyMethod(name = "clear") public IRubyObject clear(ThreadContext ctx) { return buffer.clear(ctx); } private void checkType(ThreadContext ctx, IRubyObject obj, Class expectedType) { if (!expectedType.isInstance(obj)) { String expectedName = expectedType.getName().substring("org.jruby.Ruby".length()); throw ctx.runtime.newTypeError(String.format("wrong argument type %s (expected %s)", obj.getMetaClass().toString(), expectedName)); } } } msgpack-1.4.2/ext/java/org/msgpack/jruby/ExtensionRegistry.java0000644000004100000410000001405414021120706024630 0ustar www-datawww-datapackage org.msgpack.jruby; import org.jruby.Ruby; import org.jruby.RubyHash; import org.jruby.RubyArray; import org.jruby.RubyModule; import org.jruby.RubyFixnum; import org.jruby.RubySymbol; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import java.util.Map; import java.util.HashMap; public class ExtensionRegistry { private final Map extensionsByModule; private final Map extensionsByAncestor; private final ExtensionEntry[] extensionsByTypeId; public ExtensionRegistry() { this(new HashMap()); } private ExtensionRegistry(Map extensionsByModule) { this.extensionsByModule = new HashMap(extensionsByModule); this.extensionsByAncestor = new HashMap(); this.extensionsByTypeId = new ExtensionEntry[256]; for (ExtensionEntry entry : extensionsByModule.values()) { if (entry.hasUnpacker()) { extensionsByTypeId[entry.getTypeId() + 128] = entry; } } } public ExtensionRegistry dup() { return new ExtensionRegistry(extensionsByModule); } public IRubyObject toInternalPackerRegistry(ThreadContext ctx) { RubyHash hash = RubyHash.newHash(ctx.getRuntime()); for (RubyModule extensionModule : extensionsByModule.keySet()) { ExtensionEntry entry = extensionsByModule.get(extensionModule); if (entry.hasPacker()) { hash.put(extensionModule, entry.toPackerTuple(ctx)); } } return hash; } public IRubyObject toInternalUnpackerRegistry(ThreadContext ctx) { RubyHash hash = RubyHash.newHash(ctx.getRuntime()); for (int typeIdIndex = 0 ; typeIdIndex < 256 ; typeIdIndex++) { ExtensionEntry entry = extensionsByTypeId[typeIdIndex]; if (entry != null && entry.hasUnpacker()) { IRubyObject typeId = RubyFixnum.newFixnum(ctx.getRuntime(), typeIdIndex - 128); hash.put(typeId, entry.toUnpackerTuple(ctx)); } } return hash; } public void put(RubyModule mod, int typeId, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) { ExtensionEntry entry = new ExtensionEntry(mod, typeId, packerProc, packerArg, unpackerProc, unpackerArg); extensionsByModule.put(mod, entry); extensionsByTypeId[typeId + 128] = entry; extensionsByAncestor.clear(); } public IRubyObject lookupUnpackerByTypeId(int typeId) { ExtensionEntry e = extensionsByTypeId[typeId + 128]; if (e != null && e.hasUnpacker()) { return e.getUnpackerProc(); } else { return null; } } public IRubyObject[] lookupPackerForObject(IRubyObject object) { RubyModule lookupClass = null; IRubyObject[] pair; /* * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen * String have no singleton class and raise a TypeError when trying to get * it. * * Since all but symbols are already filtered out when reaching this code * only symbols are checked here. */ if (!(object instanceof RubySymbol)) { lookupClass = object.getSingletonClass(); pair = fetchEntryByModule(lookupClass); if (pair != null) { return pair; } } pair = fetchEntryByModule(object.getType()); if (pair != null) { return pair; } if (lookupClass == null) { lookupClass = object.getType(); // only for Symbol } ExtensionEntry e = findEntryByModuleOrAncestor(lookupClass); if (e != null && e.hasPacker()) { extensionsByAncestor.put(e.getExtensionModule(), e); return e.toPackerProcTypeIdPair(lookupClass.getRuntime().getCurrentContext()); } return null; } private IRubyObject[] fetchEntryByModule(final RubyModule mod) { ExtensionEntry e = extensionsByModule.get(mod); if (e == null) { e = extensionsByAncestor.get(mod); } if (e != null && e.hasPacker()) { return e.toPackerProcTypeIdPair(mod.getRuntime().getCurrentContext()); } return null; } private ExtensionEntry findEntryByModuleOrAncestor(final RubyModule mod) { ThreadContext ctx = mod.getRuntime().getCurrentContext(); for (RubyModule extensionModule : extensionsByModule.keySet()) { RubyArray ancestors = (RubyArray) mod.callMethod(ctx, "ancestors"); if (ancestors.callMethod(ctx, "include?", extensionModule).isTrue()) { return extensionsByModule.get(extensionModule); } } return null; } private static class ExtensionEntry { private final RubyModule mod; private final int typeId; private final IRubyObject packerProc; private final IRubyObject packerArg; private final IRubyObject unpackerProc; private final IRubyObject unpackerArg; public ExtensionEntry(RubyModule mod, int typeId, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) { this.mod = mod; this.typeId = typeId; this.packerProc = packerProc; this.packerArg = packerArg; this.unpackerProc = unpackerProc; this.unpackerArg = unpackerArg; } public RubyModule getExtensionModule() { return mod; } public int getTypeId() { return typeId; } public boolean hasPacker() { return packerProc != null; } public boolean hasUnpacker() { return unpackerProc != null; } public IRubyObject getPackerProc() { return packerProc; } public IRubyObject getUnpackerProc() { return unpackerProc; } public RubyArray toPackerTuple(ThreadContext ctx) { return RubyArray.newArray(ctx.getRuntime(), new IRubyObject[] {RubyFixnum.newFixnum(ctx.getRuntime(), typeId), packerProc, packerArg}); } public RubyArray toUnpackerTuple(ThreadContext ctx) { return RubyArray.newArray(ctx.getRuntime(), new IRubyObject[] {mod, unpackerProc, unpackerArg}); } public IRubyObject[] toPackerProcTypeIdPair(ThreadContext ctx) { return new IRubyObject[] {packerProc, RubyFixnum.newFixnum(ctx.getRuntime(), typeId)}; } } } msgpack-1.4.2/ext/java/org/msgpack/jruby/Buffer.java0000644000004100000410000001470614021120706022340 0ustar www-datawww-datapackage org.msgpack.jruby; import java.nio.ByteBuffer; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.RubyHash; import org.jruby.RubyIO; import org.jruby.RubyInteger; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.ObjectAllocator; import org.jruby.util.ByteList; import org.jcodings.Encoding; @JRubyClass(name="MessagePack::Buffer") public class Buffer extends RubyObject { private IRubyObject io; private ByteBuffer buffer; private boolean writeMode; private Encoding binaryEncoding; private static final int CACHE_LINE_SIZE = 64; private static final int ARRAY_HEADER_SIZE = 24; public Buffer(Ruby runtime, RubyClass type) { super(runtime, type); } static class BufferAllocator implements ObjectAllocator { public IRubyObject allocate(Ruby runtime, RubyClass type) { return new Buffer(runtime, type); } } @JRubyMethod(name = "initialize", optional = 2) public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) { if (args.length > 0) { IRubyObject io = args[0]; if (io.respondsTo("close") && (io.respondsTo("read") || (io.respondsTo("write") && io.respondsTo("flush")))) { this.io = io; } } this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE); this.writeMode = true; this.binaryEncoding = ctx.getRuntime().getEncodingService().getAscii8bitEncoding(); return this; } private void ensureRemainingCapacity(int c) { if (!writeMode) { buffer.compact(); writeMode = true; } if (buffer.remaining() < c) { int newLength = Math.max(buffer.capacity() + (buffer.capacity() >> 1), buffer.capacity() + c); newLength += CACHE_LINE_SIZE - ((ARRAY_HEADER_SIZE + newLength) % CACHE_LINE_SIZE); buffer = ByteBuffer.allocate(newLength).put(buffer.array(), 0, buffer.position()); } } private void ensureReadMode() { if (writeMode) { buffer.flip(); writeMode = false; } } private int rawSize() { if (writeMode) { return buffer.position(); } else { return buffer.limit() - buffer.position(); } } @JRubyMethod(name = "clear") public IRubyObject clear(ThreadContext ctx) { if (!writeMode) { buffer.compact(); writeMode = true; } buffer.clear(); return ctx.getRuntime().getNil(); } @JRubyMethod(name = "size") public IRubyObject size(ThreadContext ctx) { return ctx.getRuntime().newFixnum(rawSize()); } @JRubyMethod(name = "empty?") public IRubyObject isEmpty(ThreadContext ctx) { return rawSize() == 0 ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse(); } private IRubyObject bufferWrite(ThreadContext ctx, IRubyObject str) { ByteList bytes = str.asString().getByteList(); int length = bytes.length(); ensureRemainingCapacity(length); buffer.put(bytes.unsafeBytes(), bytes.begin(), length); return ctx.getRuntime().newFixnum(length); } @JRubyMethod(name = "write", alias = {"<<"}) public IRubyObject write(ThreadContext ctx, IRubyObject str) { if (io == null) { return bufferWrite(ctx, str); } else { return io.callMethod(ctx, "write", str); } } private void feed(ThreadContext ctx) { if (io != null) { bufferWrite(ctx, io.callMethod(ctx, "read")); } } private IRubyObject readCommon(ThreadContext ctx, IRubyObject[] args, boolean raiseOnUnderflow) { feed(ctx); int length = rawSize(); if (args != null && args.length == 1) { length = (int) args[0].convertToInteger().getLongValue(); } if (raiseOnUnderflow && rawSize() < length) { throw ctx.getRuntime().newEOFError(); } int readLength = Math.min(length, rawSize()); if (readLength == 0 && length > 0) { return ctx.getRuntime().getNil(); } else if (readLength == 0) { return ctx.getRuntime().newString(); } else { ensureReadMode(); byte[] bytes = new byte[readLength]; buffer.get(bytes); ByteList byteList = new ByteList(bytes, binaryEncoding); return ctx.getRuntime().newString(byteList); } } @JRubyMethod(name = "read", optional = 1) public IRubyObject read(ThreadContext ctx, IRubyObject[] args) { return readCommon(ctx, args, false); } @JRubyMethod(name = "read_all", optional = 1) public IRubyObject readAll(ThreadContext ctx, IRubyObject[] args) { return readCommon(ctx, args, true); } private IRubyObject skipCommon(ThreadContext ctx, IRubyObject _length, boolean raiseOnUnderflow) { feed(ctx); int length = (int) _length.convertToInteger().getLongValue(); if (raiseOnUnderflow && rawSize() < length) { throw ctx.getRuntime().newEOFError(); } ensureReadMode(); int skipLength = Math.min(length, rawSize()); buffer.position(buffer.position() + skipLength); return ctx.getRuntime().newFixnum(skipLength); } @JRubyMethod(name = "skip") public IRubyObject skip(ThreadContext ctx, IRubyObject length) { return skipCommon(ctx, length, false); } @JRubyMethod(name = "skip_all") public IRubyObject skipAll(ThreadContext ctx, IRubyObject length) { return skipCommon(ctx, length, true); } public boolean hasIo() { return io != null; } @JRubyMethod(name = "to_s", alias = {"to_str"}) public IRubyObject toS(ThreadContext ctx) { ensureReadMode(); int length = buffer.limit() - buffer.position(); ByteList str = new ByteList(buffer.array(), buffer.position(), length, binaryEncoding, true); return ctx.getRuntime().newString(str); } @JRubyMethod(name = "to_a") public IRubyObject toA(ThreadContext ctx) { return ctx.getRuntime().newArray(toS(ctx)); } @JRubyMethod(name = "io") public IRubyObject getIo(ThreadContext ctx) { return io == null ? ctx.getRuntime().getNil() : io; } @JRubyMethod(name = "flush") public IRubyObject flush(ThreadContext ctx) { if (io == null) { return ctx.getRuntime().getNil(); } else { return io.callMethod(ctx, "flush"); } } @JRubyMethod(name = "close") public IRubyObject close(ThreadContext ctx) { if (io == null) { return ctx.getRuntime().getNil(); } else { return io.callMethod(ctx, "close"); } } @JRubyMethod(name = "write_to") public IRubyObject writeTo(ThreadContext ctx, IRubyObject io) { return io.callMethod(ctx, "write", readCommon(ctx, null, false)); } } msgpack-1.4.2/ext/java/org/msgpack/jruby/Unpacker.java0000644000004100000410000002441314021120706022673 0ustar www-datawww-datapackage org.msgpack.jruby; import java.util.Arrays; import org.jruby.Ruby; import org.jruby.RubyModule; import org.jruby.RubyClass; import org.jruby.RubyString; import org.jruby.RubyObject; import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.RubyNumeric; import org.jruby.RubyFixnum; import org.jruby.RubyProc; import org.jruby.RubyIO; import org.jruby.exceptions.RaiseException; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.util.ByteList; import org.jruby.ext.stringio.StringIO; import static org.jruby.runtime.Visibility.PRIVATE; @JRubyClass(name="MessagePack::Unpacker") public class Unpacker extends RubyObject { private final ExtensionRegistry registry; private IRubyObject stream; private IRubyObject data; private Decoder decoder; private final RubyClass underflowErrorClass; private boolean symbolizeKeys; private boolean freeze; private boolean allowUnknownExt; public Unpacker(Ruby runtime, RubyClass type) { this(runtime, type, new ExtensionRegistry()); } public Unpacker(Ruby runtime, RubyClass type, ExtensionRegistry registry) { super(runtime, type); this.registry = registry; this.underflowErrorClass = runtime.getModule("MessagePack").getClass("UnderflowError"); } static class UnpackerAllocator implements ObjectAllocator { public IRubyObject allocate(Ruby runtime, RubyClass klass) { return new Unpacker(runtime, klass); } } @JRubyMethod(name = "initialize", optional = 2, visibility = PRIVATE) public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) { symbolizeKeys = false; allowUnknownExt = false; freeze = false; if (args.length > 0) { if (args[args.length - 1] instanceof RubyHash) { RubyHash options = (RubyHash) args[args.length - 1]; IRubyObject sk = options.fastARef(ctx.getRuntime().newSymbol("symbolize_keys")); if (sk != null) { symbolizeKeys = sk.isTrue(); } IRubyObject f = options.fastARef(ctx.getRuntime().newSymbol("freeze")); if (f != null) { freeze = f.isTrue(); } IRubyObject au = options.fastARef(ctx.getRuntime().newSymbol("allow_unknown_ext")); if (au != null) { allowUnknownExt = au.isTrue(); } } if (args[0] != ctx.getRuntime().getNil() && !(args[0] instanceof RubyHash)) { setStream(ctx, args[0]); } } return this; } public static Unpacker newUnpacker(ThreadContext ctx, ExtensionRegistry extRegistry, IRubyObject[] args) { Unpacker unpacker = new Unpacker(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Unpacker"), extRegistry); unpacker.initialize(ctx, args); return unpacker; } @JRubyMethod(name = "symbolize_keys?") public IRubyObject isSymbolizeKeys(ThreadContext ctx) { return symbolizeKeys ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse(); } @JRubyMethod(name = "freeze?") public IRubyObject isFreeze(ThreadContext ctx) { return freeze ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse(); } @JRubyMethod(name = "allow_unknown_ext?") public IRubyObject isAllowUnknownExt(ThreadContext ctx) { return allowUnknownExt ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse(); } @JRubyMethod(name = "registered_types_internal", visibility = PRIVATE) public IRubyObject registeredTypesInternal(ThreadContext ctx) { return registry.toInternalUnpackerRegistry(ctx); } @JRubyMethod(name = "register_type", required = 1, optional = 2) public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) { Ruby runtime = ctx.getRuntime(); IRubyObject type = args[0]; RubyModule extModule; IRubyObject arg; IRubyObject proc; if (args.length == 1) { if (! block.isGiven()) { throw runtime.newLocalJumpErrorNoBlock(); } proc = RubyProc.newProc(runtime, block, block.type); if (proc == null) System.err.println("proc from Block is null"); arg = proc; extModule = null; } else if (args.length == 3) { extModule = (RubyModule) args[1]; arg = args[2]; proc = extModule.method(arg); } else { throw runtime.newArgumentError(String.format("wrong number of arguments (%d for 1 or 3)", 2 + args.length)); } long typeId = ((RubyFixnum) type).getLongValue(); if (typeId < -128 || typeId > 127) { throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId)); } registry.put(extModule, (int) typeId, null, null, proc, arg); return runtime.getNil(); } @JRubyMethod(required = 2) public IRubyObject execute(ThreadContext ctx, IRubyObject data, IRubyObject offset) { return executeLimit(ctx, data, offset, null); } @JRubyMethod(name = "execute_limit", required = 3) public IRubyObject executeLimit(ThreadContext ctx, IRubyObject str, IRubyObject off, IRubyObject lim) { RubyString input = str.asString(); int offset = RubyNumeric.fix2int(off); int limit = lim == null || lim.isNil() ? -1 : RubyNumeric.fix2int(lim); ByteList byteList = input.getByteList(); if (limit == -1) { limit = byteList.length() - offset; } Decoder decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt); try { data = null; data = decoder.next(); } catch (RaiseException re) { if (re.getException().getType() != underflowErrorClass) { throw re; } } return ctx.getRuntime().newFixnum(decoder.offset()); } @JRubyMethod(name = "data") public IRubyObject getData(ThreadContext ctx) { if (data == null) { return ctx.getRuntime().getNil(); } else { return data; } } @JRubyMethod(name = "finished?") public IRubyObject finished_p(ThreadContext ctx) { return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue(); } @JRubyMethod(required = 1, name = "feed", alias = { "feed_reference" }) public IRubyObject feed(ThreadContext ctx, IRubyObject data) { ByteList byteList = data.asString().getByteList(); if (decoder == null) { decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt); } else { decoder.feed(byteList.unsafeBytes(), byteList.begin(), byteList.length()); } return this; } @JRubyMethod(name = "full_unpack") public IRubyObject fullUnpack(ThreadContext ctx) { return decoder.next(); } @JRubyMethod(name = "feed_each", required = 1) public IRubyObject feedEach(ThreadContext ctx, IRubyObject data, Block block) { feed(ctx, data); if (block.isGiven()) { each(ctx, block); return ctx.getRuntime().getNil(); } else { return callMethod(ctx, "to_enum"); } } @JRubyMethod public IRubyObject each(ThreadContext ctx, Block block) { if (block.isGiven()) { if (decoder != null) { try { while (decoder.hasNext()) { block.yield(ctx, decoder.next()); } } catch (RaiseException re) { if (re.getException().getType() != underflowErrorClass) { throw re; } } } return this; } else { return callMethod(ctx, "to_enum"); } } @JRubyMethod public IRubyObject fill(ThreadContext ctx) { return ctx.getRuntime().getNil(); } @JRubyMethod public IRubyObject reset(ThreadContext ctx) { if (decoder != null) { decoder.reset(); } return ctx.getRuntime().getNil(); } @JRubyMethod(name = "read", alias = { "unpack" }) public IRubyObject read(ThreadContext ctx) { if (decoder == null) { throw ctx.getRuntime().newEOFError(); } try { return decoder.next(); } catch (RaiseException re) { if (re.getException().getType() != underflowErrorClass) { throw re; } else { throw ctx.getRuntime().newEOFError(); } } } @JRubyMethod(name = "skip") public IRubyObject skip(ThreadContext ctx) { throw ctx.getRuntime().newNotImplementedError("Not supported yet in JRuby implementation"); } @JRubyMethod(name = "skip_nil") public IRubyObject skipNil(ThreadContext ctx) { throw ctx.getRuntime().newNotImplementedError("Not supported yet in JRuby implementation"); } @JRubyMethod public IRubyObject read_array_header(ThreadContext ctx) { if (decoder != null) { try { return decoder.read_array_header(); } catch (RaiseException re) { if (re.getException().getType() != underflowErrorClass) { throw re; } else { throw ctx.getRuntime().newEOFError(); } } } return ctx.getRuntime().getNil(); } @JRubyMethod public IRubyObject read_map_header(ThreadContext ctx) { if (decoder != null) { try { return decoder.read_map_header(); } catch (RaiseException re) { if (re.getException().getType() != underflowErrorClass) { throw re; } else { throw ctx.getRuntime().newEOFError(); } } } return ctx.getRuntime().getNil(); } @JRubyMethod(name = "stream") public IRubyObject getStream(ThreadContext ctx) { if (stream == null) { return ctx.getRuntime().getNil(); } else { return stream; } } @JRubyMethod(name = "stream=", required = 1) public IRubyObject setStream(ThreadContext ctx, IRubyObject stream) { RubyString str; if (stream instanceof StringIO) { str = stream.callMethod(ctx, "string").asString(); } else if (stream instanceof RubyIO) { str = stream.callMethod(ctx, "read").asString(); } else if (stream.respondsTo("read")) { str = stream.callMethod(ctx, "read").asString(); } else { throw ctx.getRuntime().newTypeError(stream, "IO"); } ByteList byteList = str.getByteList(); this.stream = stream; this.decoder = null; this.decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt); return getStream(ctx); } } msgpack-1.4.2/ext/java/org/msgpack/jruby/Types.java0000644000004100000410000000332114021120706022222 0ustar www-datawww-datapackage org.msgpack.jruby; public interface Types { public static final byte FIXSTR = (byte) 0xa0; // This is actually not header byte, but prefix bit mask public static final byte NIL = (byte) 0xc0; public static final byte FALSE = (byte) 0xc2; public static final byte TRUE = (byte) 0xc3; public static final byte BIN8 = (byte) 0xc4; public static final byte BIN16 = (byte) 0xc5; public static final byte BIN32 = (byte) 0xc6; public static final byte VAREXT8 = (byte) 0xc7; public static final byte VAREXT16 = (byte) 0xc8; public static final byte VAREXT32 = (byte) 0xc9; public static final byte FLOAT32 = (byte) 0xca; public static final byte FLOAT64 = (byte) 0xcb; public static final byte UINT8 = (byte) 0xcc; public static final byte UINT16 = (byte) 0xcd; public static final byte UINT32 = (byte) 0xce; public static final byte UINT64 = (byte) 0xcf; public static final byte INT8 = (byte) 0xd0; public static final byte INT16 = (byte) 0xd1; public static final byte INT32 = (byte) 0xd2; public static final byte INT64 = (byte) 0xd3; public static final byte FIXEXT1 = (byte) 0xd4; public static final byte FIXEXT2 = (byte) 0xd5; public static final byte FIXEXT4 = (byte) 0xd6; public static final byte FIXEXT8 = (byte) 0xd7; public static final byte FIXEXT16 = (byte) 0xd8; public static final byte STR8 = (byte) 0xd9; public static final byte STR16 = (byte) 0xda; public static final byte STR32 = (byte) 0xdb; public static final byte ARY16 = (byte) 0xdc; public static final byte ARY32 = (byte) 0xdd; public static final byte MAP16 = (byte) 0xde; public static final byte MAP32 = (byte) 0xdf; } msgpack-1.4.2/ext/java/org/msgpack/jruby/Encoder.java0000644000004100000410000003140014021120706022474 0ustar www-datawww-datapackage org.msgpack.jruby; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; import org.jruby.Ruby; import org.jruby.RubyObject; import org.jruby.RubyModule; import org.jruby.RubyNil; import org.jruby.RubyBoolean; import org.jruby.RubyNumeric; import org.jruby.RubyBignum; import org.jruby.RubyInteger; import org.jruby.RubyFixnum; import org.jruby.RubyFloat; import org.jruby.RubyString; import org.jruby.RubySymbol; import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.RubyEncoding; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; import org.jcodings.Encoding; import org.jcodings.specific.UTF8Encoding; import static org.msgpack.jruby.Types.*; public class Encoder { private static final int CACHE_LINE_SIZE = 64; private static final int ARRAY_HEADER_SIZE = 24; private final Ruby runtime; private final Encoding binaryEncoding; private final Encoding utf8Encoding; private final boolean compatibilityMode; private final ExtensionRegistry registry; public boolean hasSymbolExtType; private ByteBuffer buffer; public Encoder(Ruby runtime, boolean compatibilityMode, ExtensionRegistry registry, boolean hasSymbolExtType) { this.runtime = runtime; this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE); this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding(); this.utf8Encoding = UTF8Encoding.INSTANCE; this.compatibilityMode = compatibilityMode; this.registry = registry; this.hasSymbolExtType = hasSymbolExtType; } public boolean isCompatibilityMode() { return compatibilityMode; } private void ensureRemainingCapacity(int c) { if (buffer.remaining() < c) { int newLength = Math.max(buffer.capacity() + (buffer.capacity() >> 1), buffer.capacity() + c); newLength += CACHE_LINE_SIZE - ((ARRAY_HEADER_SIZE + newLength) % CACHE_LINE_SIZE); buffer = ByteBuffer.allocate(newLength).put(buffer.array(), 0, buffer.position()); } } private IRubyObject readRubyString() { IRubyObject str = runtime.newString(new ByteList(buffer.array(), 0, buffer.position(), binaryEncoding, false)); buffer.clear(); return str; } public IRubyObject encode(IRubyObject object) { appendObject(object); return readRubyString(); } public IRubyObject encode(IRubyObject object, IRubyObject destination) { appendObject(object, destination); return readRubyString(); } public IRubyObject encodeArrayHeader(int size) { appendArrayHeader(size); return readRubyString(); } public IRubyObject encodeMapHeader(int size) { appendHashHeader(size); return readRubyString(); } public IRubyObject encodeBinHeader(int size) { appendStringHeader(size, true); return readRubyString(); } public IRubyObject encodeFloat32(RubyNumeric numeric) { appendFloat32(numeric); return readRubyString(); } private void appendObject(IRubyObject object) { appendObject(object, null); } private void appendObject(IRubyObject object, IRubyObject destination) { if (object == null || object instanceof RubyNil) { ensureRemainingCapacity(1); buffer.put(NIL); } else if (object instanceof RubyBoolean) { ensureRemainingCapacity(1); buffer.put(((RubyBoolean) object).isTrue() ? TRUE : FALSE); } else if (object instanceof RubyBignum) { appendBignum((RubyBignum) object); } else if (object instanceof RubyInteger) { appendInteger((RubyInteger) object); } else if (object instanceof RubyFloat) { appendFloat((RubyFloat) object); } else if (object instanceof RubyString) { appendString((RubyString) object); } else if (object instanceof RubySymbol) { if (hasSymbolExtType) { appendOther(object, destination); } else { appendString(((RubySymbol) object).asString()); } } else if (object instanceof RubyArray) { appendArray((RubyArray) object); } else if (object instanceof RubyHash) { appendHash((RubyHash) object); } else if (object instanceof ExtensionValue) { appendExtensionValue((ExtensionValue) object); } else { appendOther(object, destination); } } private void appendBignum(RubyBignum object) { BigInteger value = object.getBigIntegerValue(); if (value.compareTo(RubyBignum.LONG_MIN) < 0 || value.compareTo(RubyBignum.LONG_MAX) > 0) { if (value.bitLength() > 64 || (value.bitLength() > 63 && value.signum() < 0)) { throw runtime.newArgumentError(String.format("Cannot pack big integer: %s", value)); } ensureRemainingCapacity(9); buffer.put(value.signum() < 0 ? INT64 : UINT64); byte[] b = value.toByteArray(); buffer.put(b, b.length - 8, 8); } else { appendInteger(object); } } private void appendInteger(RubyInteger object) { long value = ((RubyInteger) object).getLongValue(); if (value < 0) { if (value < Short.MIN_VALUE) { if (value < Integer.MIN_VALUE) { ensureRemainingCapacity(9); buffer.put(INT64); buffer.putLong(value); } else { ensureRemainingCapacity(5); buffer.put(INT32); buffer.putInt((int) value); } } else if (value >= -0x20L) { ensureRemainingCapacity(1); byte b = (byte) (value | 0xe0); buffer.put(b); } else if (value < Byte.MIN_VALUE) { ensureRemainingCapacity(3); buffer.put(INT16); buffer.putShort((short) value); } else { ensureRemainingCapacity(2); buffer.put(INT8); buffer.put((byte) value); } } else { if (value < 0x10000L) { if (value < 128L) { ensureRemainingCapacity(1); buffer.put((byte) value); } else if (value < 0x100L) { ensureRemainingCapacity(2); buffer.put(UINT8); buffer.put((byte) value); } else { ensureRemainingCapacity(3); buffer.put(UINT16); buffer.putShort((short) value); } } else if (value < 0x100000000L) { ensureRemainingCapacity(5); buffer.put(UINT32); buffer.putInt((int) value); } else { ensureRemainingCapacity(9); buffer.put(INT64); buffer.putLong(value); } } } private void appendFloat(RubyFloat object) { double value = object.getDoubleValue(); //TODO: msgpack-ruby original does encode this value as Double, not float // float f = (float) value; // if (Double.compare(f, value) == 0) { // ensureRemainingCapacity(5); // buffer.put(FLOAT32); // buffer.putFloat(f); // } else { ensureRemainingCapacity(9); buffer.put(FLOAT64); buffer.putDouble(value); // } } private void appendFloat32(RubyNumeric object) { float value = (float) object.getDoubleValue(); ensureRemainingCapacity(5); buffer.put(FLOAT32); buffer.putFloat(value); } private void appendStringHeader(int length, boolean binary) { if (length < 32 && !binary) { ensureRemainingCapacity(1 + length); buffer.put((byte) (length | FIXSTR)); } else if (length <= 0xff && !compatibilityMode) { ensureRemainingCapacity(2 + length); buffer.put(binary ? BIN8 : STR8); buffer.put((byte) length); } else if (length <= 0xffff) { ensureRemainingCapacity(3 + length); buffer.put(binary ? BIN16 : STR16); buffer.putShort((short) length); } else { ensureRemainingCapacity(5 + length); buffer.put(binary ? BIN32 : STR32); buffer.putInt((int) length); } } private void appendString(RubyString object) { Encoding encoding = object.getEncoding(); boolean binary = !compatibilityMode && encoding == binaryEncoding; if (encoding != utf8Encoding && encoding != binaryEncoding) { object = (RubyString) ((RubyString) object).encode(runtime.getCurrentContext(), runtime.getEncodingService().getEncoding(utf8Encoding)); } ByteList bytes = object.getByteList(); int length = bytes.length(); appendStringHeader(length, binary); buffer.put(bytes.unsafeBytes(), bytes.begin(), length); } private void appendArray(RubyArray object) { appendArrayHeader(object); appendArrayElements(object); } private void appendArrayHeader(RubyArray object) { appendArrayHeader(object.size()); } private void appendArrayHeader(int size) { if (size < 16) { ensureRemainingCapacity(1); buffer.put((byte) (size | 0x90)); } else if (size < 0x10000) { ensureRemainingCapacity(3); buffer.put(ARY16); buffer.putShort((short) size); } else { ensureRemainingCapacity(5); buffer.put(ARY32); buffer.putInt(size); } } private void appendArrayElements(RubyArray object) { int size = object.size(); for (int i = 0; i < size; i++) { appendObject(object.eltOk(i)); } } private void appendHash(RubyHash object) { appendHashHeader(object); appendHashElements(object); } private void appendHashHeader(RubyHash object) { appendHashHeader(object.size()); } private void appendHashHeader(int size) { if (size < 16) { ensureRemainingCapacity(1); buffer.put((byte) (size | 0x80)); } else if (size < 0x10000) { ensureRemainingCapacity(3); buffer.put(MAP16); buffer.putShort((short) size); } else { ensureRemainingCapacity(5); buffer.put(MAP32); buffer.putInt(size); } } private void appendHashElements(RubyHash object) { int size = object.size(); HashVisitor visitor = new HashVisitor(size); object.visitAll(visitor); if (visitor.remain != 0) { object.getRuntime().newConcurrencyError("Hash size changed while packing"); } } private class HashVisitor extends RubyHash.Visitor { public int remain; public HashVisitor(int size) { remain = size; } public void visit(IRubyObject key, IRubyObject value) { if (remain-- > 0) { appendObject(key); appendObject(value); } } } private void appendExt(int type, ByteList payloadBytes) { int payloadSize = payloadBytes.length(); int outputSize = 0; boolean fixSize = payloadSize == 1 || payloadSize == 2 || payloadSize == 4 || payloadSize == 8 || payloadSize == 16; if (fixSize) { outputSize = 2 + payloadSize; } else if (payloadSize < 0x100) { outputSize = 3 + payloadSize; } else if (payloadSize < 0x10000) { outputSize = 4 + payloadSize; } else { outputSize = 6 + payloadSize; } ensureRemainingCapacity(outputSize); if (payloadSize == 1) { buffer.put(FIXEXT1); } else if (payloadSize == 2) { buffer.put(FIXEXT2); } else if (payloadSize == 4) { buffer.put(FIXEXT4); } else if (payloadSize == 8) { buffer.put(FIXEXT8); } else if (payloadSize == 16) { buffer.put(FIXEXT16); } else if (payloadSize < 0x100) { buffer.put(VAREXT8); buffer.put((byte) payloadSize); } else if (payloadSize < 0x10000) { buffer.put(VAREXT16); buffer.putShort((short) payloadSize); } else { buffer.put(VAREXT32); buffer.putInt(payloadSize); } buffer.put((byte) type); buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), payloadSize); } private void appendExtensionValue(ExtensionValue object) { long type = ((RubyFixnum)object.get_type()).getLongValue(); if (type < -128 || type > 127) { throw object.getRuntime().newRangeError(String.format("integer %d too big to convert to `signed char'", type)); } ByteList payloadBytes = ((RubyString)object.payload()).getByteList(); appendExt((int) type, payloadBytes); } private void appendOther(IRubyObject object, IRubyObject destination) { if (registry != null) { RubyModule lookupClass; if (object.getType() == runtime.getSymbol()) { lookupClass = object.getType(); } else { lookupClass = object.getSingletonClass(); } IRubyObject[] pair = registry.lookupPackerForObject(object); if (pair != null) { RubyString bytes = pair[0].callMethod(runtime.getCurrentContext(), "call", object).asString(); int type = (int) ((RubyFixnum) pair[1]).getLongValue(); appendExt(type, bytes.getByteList()); return; } } appendCustom(object, destination); } private void appendCustom(IRubyObject object, IRubyObject destination) { if (destination == null) { IRubyObject result = object.callMethod(runtime.getCurrentContext(), "to_msgpack"); ByteList bytes = result.asString().getByteList(); int length = bytes.length(); ensureRemainingCapacity(length); buffer.put(bytes.unsafeBytes(), bytes.begin(), length); } else { object.callMethod(runtime.getCurrentContext(), "to_msgpack", destination); } } }