Class: HTTPI::Dime

Inherits:
Array
  • Object
show all
Defined in:
lib/httpi/dime.rb

Constant Summary collapse

BINARY =
1
XML =
2

Instance Method Summary collapse

Constructor Details

#initialize(body) ⇒ Dime

Returns a new instance of Dime.


13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/httpi/dime.rb', line 13

def initialize(body)
  bytes = body.unpack('C*')

  while bytes.length > 0
    record = DimeRecord.new
    configure_record(record, bytes)

    big_endian_lengths(bytes).each do |attribute_set|
      read_data(record, bytes, attribute_set)
    end

    self << record
  end
end

Instance Method Details

#big_endian_lengths(bytes) ⇒ Object

Fetch big-endian lengths.


41
42
43
44
45
46
47
48
# File 'lib/httpi/dime.rb', line 41

def big_endian_lengths(bytes)
  lengths = [] # we can't use a hash since the order will be screwed in Ruby 1.8
  lengths << [:options, (bytes.shift << 8) | bytes.shift]                                             # 2 bytes   Length of the "options" field
  lengths << [:id,      (bytes.shift << 8) | bytes.shift]                                             # 2 bytes   Length of the "ID" or "name" field
  lengths << [:type,    (bytes.shift << 8) | bytes.shift]                                             # 2 bytes   Length of the "type" field
  lengths << [:data,    (bytes.shift << 24) | (bytes.shift << 16) | (bytes.shift << 8) | bytes.shift] # 4 bytes   Size of the included file
  lengths
end

#binary_recordsObject


67
68
69
# File 'lib/httpi/dime.rb', line 67

def binary_records
  select { |r| r.type_format == BINARY }
end

#configure_record(record, bytes) ⇒ Object

Shift out bitfields for the first fields.


29
30
31
32
33
34
35
36
37
38
# File 'lib/httpi/dime.rb', line 29

def configure_record(record, bytes)
  byte = bytes.shift

  record.version     = (byte >> 3) & 31         # 5 bits  DIME format version (always 1)
  record.first       = (byte >> 2) & 1          # 1 bit   Set if this is the first part in the message
  record.last        = (byte >> 1) & 1          # 1 bit   Set if this is the last part in the message
  record.chunked     = byte & 1                 # 1 bit   This file is broken into chunked parts
  record.type_format = (bytes.shift >> 4) & 15  # 4 bits  Type of file in the part (1 for binary data, 2 for XML)
                                                # 4 bits  Reserved (skipped in the above command)
end

#read_data(record, bytes, attribute_set) ⇒ Object

Read in padded data.


51
52
53
54
55
56
57
58
59
60
61
# File 'lib/httpi/dime.rb', line 51

def read_data(record, bytes, attribute_set)
  attribute, length = attribute_set
  content = bytes.slice!(0, length).pack('C*')

  if attribute == :data && record.type_format == BINARY
    content = StringIO.new(content)
  end

  record.send "#{attribute.to_s}=", content
  bytes.slice!(0, 4 - (length & 3)) if (length & 3) != 0
end

#xml_recordsObject


63
64
65
# File 'lib/httpi/dime.rb', line 63

def xml_records
  select { |r| r.type_format == XML }
end