Class: BSON::Binary

Inherits:
Object
  • Object
show all
Includes:
JSON
Defined in:
lib/bson/binary.rb

Overview

Represents binary data.

See Also:

Since:

  • 2.0.0

Constant Summary collapse

BSON_TYPE =

A binary is type 0x05 in the BSON spec.

Since:

  • 2.0.0

::String.new(5.chr, encoding: BINARY).freeze
SUBTYPES =
Note:

subtype 6 (ciphertext) is used for the Client-Side Encryption feature. Data represented by this subtype is often encrypted, but may also be plaintext. All instances of this subtype necessary for Client-Side Encryption will be created internally by the Ruby driver. An application should not create new BSON::Binary objects of this subtype.

The mappings of subtypes to their single byte identifiers.

Since:

  • 2.0.0

{
  generic: 0.chr,
  function: 1.chr,
  old: 2.chr,
  uuid_old: 3.chr,
  uuid: 4.chr,
  md5: 5.chr,
  ciphertext: 6.chr,
  column: 7.chr,
  user: 128.chr,
}.freeze
USER_SUBTYPE =

The starting point of the user-defined subtype range.

Since:

  • 2.0.0

0x80
TYPES =

The mappings of single byte subtypes to their symbol counterparts.

Since:

  • 2.0.0

SUBTYPES.invert.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from JSON

#to_json

Constructor Details

#initialize(data = '', type = :generic) ⇒ Binary

Instantiate the new binary object.

This method accepts a string in any encoding; however, if a string is of a non-BINARY encoding, the encoding is set to BINARY. This does not change the bytes of the string but it means that applications referencing the data of a Binary instance cannot assume it is in a non-binary encoding, even if the string given to the constructor was in such an encoding.

Examples:

Instantiate a binary.

BSON::Binary.new(data, :md5)

Parameters:

  • data (String) (defaults to: '')

    The raw binary data.

  • type (Symbol) (defaults to: :generic)

    The binary type.

Since:

  • 2.0.0



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/bson/binary.rb', line 149

def initialize(data = '', type = :generic)
  @type = validate_type!(type)

  # The Binary class used to force encoding to BINARY when serializing to
  # BSON. Instead of doing that during serialization, perform this
  # operation during Binary construction to make it clear that once
  # the string is given to the Binary, the data is treated as a binary
  # string and not a text string in any encoding.
  data = data.dup.force_encoding('BINARY') unless data.encoding == Encoding.find('BINARY')

  @data = data
end

Instance Attribute Details

#dataString (readonly)

The string is always stored in BINARY encoding.

Returns:

  • (String)

    The raw binary data.

Since:

  • 2.0.0



67
68
69
# File 'lib/bson/binary.rb', line 67

def data
  @data
end

#raw_typeString (readonly)

Returns The raw type value, as an encoded integer.

Returns:

  • (String)

    The raw type value, as an encoded integer.

Since:

  • 2.0.0



73
74
75
# File 'lib/bson/binary.rb', line 73

def raw_type
  @raw_type
end

#typeSymbol (readonly)

Returns The binary type.

Returns:

  • (Symbol)

    The binary type.

Since:

  • 2.0.0



70
71
72
# File 'lib/bson/binary.rb', line 70

def type
  @type
end

Class Method Details

.from_bson(buffer, **_options) ⇒ Binary

Deserialize the binary data from BSON.

Parameters:

  • buffer (ByteBuffer)

    The byte buffer.

  • options (Hash)

    a customizable set of options

Returns:

  • (Binary)

    The decoded binary data.

See Also:

Since:

  • 2.0.0



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/bson/binary.rb', line 246

def self.from_bson(buffer, **_options)
  length = buffer.get_int32
  type_byte = buffer.get_byte

  if type_byte.bytes.first < USER_SUBTYPE
    type = TYPES[type_byte]

    if type.nil?
      raise Error::UnsupportedBinarySubtype,
            "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}"
    end
  else
    type = type_byte
  end

  length = buffer.get_int32 if type == :old
  data = buffer.get_bytes(length)
  new(data, type)
end

.from_csharp_legacy_uuid(uuid_binary) ⇒ BSON::Binary

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Constructs a new binary object from a csharp legacy-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



323
324
325
326
# File 'lib/bson/binary.rb', line 323

def self.from_csharp_legacy_uuid(uuid_binary)
  uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.{8})\z/, '\4\3\2\1\6\5\8\7\9')
  new(uuid_binary, :uuid_old)
end

.from_java_legacy_uuid(uuid_binary) ⇒ BSON::Binary

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Constructs a new binary object from a java legacy-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



336
337
338
339
340
341
# File 'lib/bson/binary.rb', line 336

def self.from_java_legacy_uuid(uuid_binary)
  uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\z/) do
    (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join
  end
  new(uuid_binary, :uuid_old)
end

.from_python_legacy_uuid(uuid_binary) ⇒ BSON::Binary

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Constructs a new binary object from a python legacy-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



351
352
353
# File 'lib/bson/binary.rb', line 351

def self.from_python_legacy_uuid(uuid_binary)
  new(uuid_binary, :uuid_old)
end

.from_standard_uuid(uuid_binary) ⇒ BSON::Binary

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Constructs a new binary object from a standard-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



311
312
313
# File 'lib/bson/binary.rb', line 311

def self.from_standard_uuid(uuid_binary)
  new(uuid_binary, :uuid)
end

.from_uuid(uuid, representation = nil) ⇒ Binary

Creates a BSON::Binary from a string representation of a UUID.

The UUID may be given in either 00112233-4455-6677-8899-aabbccddeeff or 00112233445566778899AABBCCDDEEFF format - specifically, any dashes in the UUID are removed and both upper and lower case letters are acceptable.

The input UUID string is always interpreted to be in the RFC 4122 format.

If representation is not provided, this method creates a BSON::Binary of subtype 4 (:uuid). If representation is provided, it must be one of :standard, :csharp_legacy, :java_legacy or :python_legacy. If representation is :standard, this method creates a subtype 4 (:uuid) binary which is the same behavior as if representation was not provided. For other representations, this method creates a Binary of subtype 3 (:uuid_old) with the UUID converted to the appropriate legacy MongoDB UUID storage format.

Parameters:

  • uuid (String)

    The string representation of the UUID.

  • representation (Symbol) (defaults to: nil)

    How to interpret the UUID.

Returns:

Raises:

  • (ArgumentError)

    If invalid representation is requested.

Since:

  • 2.0.0



291
292
293
294
295
296
297
298
299
300
301
# File 'lib/bson/binary.rb', line 291

def self.from_uuid(uuid, representation = nil)
  raise ArgumentError, "Representation must be given as a symbol: #{representation}" if representation.is_a?(String)

  uuid_binary = uuid.delete('-').scan(/../).map(&:hex).map(&:chr).join
  representation ||= :standard

  handler = :"from_#{representation}_uuid"
  raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler)

  send(handler, uuid_binary)
end

Instance Method Details

#==(other) ⇒ true, false Also known as: eql?

Determine if this binary object is equal to another object.

Examples:

Check the binary equality.

binary == other

Parameters:

  • other (Object)

    The object to compare against.

Returns:

  • (true, false)

    If the objects are equal.

Since:

  • 2.0.0



85
86
87
88
89
# File 'lib/bson/binary.rb', line 85

def ==(other)
  return false unless other.is_a?(Binary)

  type == other.type && data == other.data
end

#as_extended_json(**options) ⇒ Hash

Converts this object to a representation directly serializable to Extended JSON (github.com/mongodb/specifications/blob/master/source/extended-json.rst).

Parameters:

  • opts (Hash)

    a customizable set of options

Returns:

  • (Hash)

    The extended json representation.

Since:

  • 2.0.0



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/bson/binary.rb', line 120

def as_extended_json(**options)
  subtype = @raw_type.each_byte.map { |c| c.to_s(16) }.join
  subtype = "0#{subtype}" if subtype.length == 1

  value = Base64.encode64(data).strip

  if options[:mode] == :legacy
    { '$binary' => value, '$type' => subtype }
  else
    { '$binary' => { 'base64' => value, 'subType' => subtype } }
  end
end

#as_json(*_args) ⇒ Hash

Return a representation of the object for use in application-level JSON serialization. Since BSON::Binary is used exclusively in BSON-related contexts, this method returns the canonical Extended JSON representation.

Returns:

  • (Hash)

    The extended json representation.

Since:

  • 2.0.0



109
110
111
# File 'lib/bson/binary.rb', line 109

def as_json(*_args)
  as_extended_json
end

#hashFixnum

Generates a Fixnum hash value for this object.

Allows using Binary as hash keys.

Returns:

  • (Fixnum)

Since:

  • 2.3.1



99
100
101
# File 'lib/bson/binary.rb', line 99

def hash
  [ data, type ].hash
end

#inspectString

Get a nice string for use with object inspection.

Examples:

Inspect the binary.

object_id.inspect

Returns:

  • (String)

    The binary in form BSON::Binary:object_id

Since:

  • 2.3.0



170
171
172
# File 'lib/bson/binary.rb', line 170

def inspect
  "<BSON::Binary:0x#{object_id} type=#{type} data=0x#{data[0, 8].unpack1('H*')}...>"
end

#to_bson(buffer = ByteBuffer.new) ⇒ BSON::ByteBuffer

Encode the binary type

Examples:

Encode the binary.

binary.to_bson

Returns:

See Also:

Since:

  • 2.0.0



226
227
228
229
230
231
232
233
# File 'lib/bson/binary.rb', line 226

def to_bson(buffer = ByteBuffer.new)
  position = buffer.length
  buffer.put_int32(0)
  buffer.put_byte(@raw_type)
  buffer.put_int32(data.bytesize) if type == :old
  buffer.put_bytes(data)
  buffer.replace_int32(position, buffer.length - position - 5)
end

#to_uuid(representation = nil) ⇒ String

Returns a string representation of the UUID stored in this Binary.

If the Binary is of subtype 4 (:uuid), this method returns the UUID in RFC 4122 format. If the representation parameter is provided, it must be the value :standard as a symbol or a string.

If the Binary is of subtype 3 (:uuid_old), this method requires that the representation parameter is provided and is one of :csharp_legacy, :java_legacy or :python_legacy or the equivalent strings. In this case the method assumes the Binary stores the UUID in the specified format, transforms the stored bytes to the standard RFC 4122 representation and returns the UUID in RFC 4122 format.

If the Binary is of another subtype, this method raises TypeError.

Parameters:

  • representation (Symbol) (defaults to: nil)

    How to interpret the UUID.

Returns:

  • (String)

    The string representation of the UUID.

Raises:

  • (TypeError)

    If the subtype of Binary is not :uuid nor :uuid_old.

  • (ArgumentError)

    If the representation other than :standard is requested for Binary subtype 4 (:uuid), if :standard representation is requested for Binary subtype 3 (:uuid_old), or if an invalid representation is requested.

Since:

  • 2.0.0



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/bson/binary.rb', line 200

def to_uuid(representation = nil)
  if representation.is_a?(String)
    raise ArgumentError,
          "Representation must be given as a symbol: #{representation.inspect}"
  end

  case type
  when :uuid
    from_uuid_to_uuid(representation || :standard)
  when :uuid_old
    from_uuid_old_to_uuid(representation)
  else
    raise TypeError, "The type of Binary must be :uuid or :uuid_old, this object is: #{type.inspect}"
  end
end