Class: NIFTI::Stream

Inherits:
Object
  • Object
show all
Defined in:
lib/nifti/stream.rb

Overview

The Stream class handles string operations (encoding to and decoding from binary strings).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(binary, string_endian, options = {}) ⇒ Stream

Creates a Stream instance.

Parameters

  • binary ??? A binary string.

  • string_endian ??? Boolean. The endianness of the instance string (true for big endian, false for small endian).

  • options ??? A hash of parameters.

Options

  • :index ??? Fixnum. A position (offset) in the instance string where reading will start.



32
33
34
35
36
37
# File 'lib/nifti/stream.rb', line 32

def initialize(binary, string_endian, options={})
  @string = binary || ""
  @index = options[:index] || 0
  @errors = Array.new
  self.endian = string_endian
end

Instance Attribute Details

#equal_endianObject (readonly)

A boolean which reports the relationship between the endianness of the system and the instance string.



6
7
8
# File 'lib/nifti/stream.rb', line 6

def equal_endian
  @equal_endian
end

#errorsObject (readonly)

An array of warning/error messages that (may) have been accumulated.



14
15
16
# File 'lib/nifti/stream.rb', line 14

def errors
  @errors
end

#fileObject

A File object to write to



18
19
20
# File 'lib/nifti/stream.rb', line 18

def file
  @file
end

#formatObject (readonly)

A hash of proper strings (based on endianess) to use for unpacking binary strings.



16
17
18
# File 'lib/nifti/stream.rb', line 16

def format
  @format
end

#indexObject

Our current position in the instance string (used only for decoding).



8
9
10
# File 'lib/nifti/stream.rb', line 8

def index
  @index
end

#str_endianObject (readonly)

The endianness of the instance string.



12
13
14
# File 'lib/nifti/stream.rb', line 12

def str_endian
  @str_endian
end

#stringObject

The instance string.



10
11
12
# File 'lib/nifti/stream.rb', line 10

def string
  @string
end

Instance Method Details

#decode(length, type) ⇒ Object

Decodes a section of the instance string and returns the formatted data. The instance index is offset in accordance with the length read.

Notes

  • If multiple numbers are decoded, these are returned in an array.

Parameters

  • length ??? Fixnum. The string length which will be decoded.

  • type ??? String. The type (vr) of data to decode.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/nifti/stream.rb', line 53

def decode(length, type)
  # Check if values are valid:
  if (@index + length) > @string.length
    # The index number is bigger then the length of the binary string.
    # We have reached the end and will return nil.
    value = nil
  else
    if type == "AT"
      value = decode_tag
    else
      # Decode the binary string and return value:
      value = @string.slice(@index, length).unpack(vr_to_str(type))
      # If the result is an array of one element, return the element instead of the array.
      # If result is contained in a multi-element array, the original array is returned.
      if value.length == 1
        value = value[0]
        # If value is a string, strip away possible trailing whitespace:
        # Do this using gsub instead of ruby-core #strip to keep trailing carriage
        # returns, etc., because that is valid whitespace that we want to have included
        # (i.e. in extended header data, AFNI writes a \n at the end of it's xml info, 
        # and that must be kept in order to not change the file on writing back out).
        value.gsub!(/\000*$/, "") if value.respond_to? :gsub!
      end
      # Update our position in the string:
      skip(length)
    end
  end
  return value
end

#encode(value, type) ⇒ Object

Encodes a value and returns the resulting binary string.

Parameters

  • value ??? A custom value (String, Fixnum, etc..) or an array of numbers.

  • type ??? String. The type (vr) of data to encode.



200
201
202
203
# File 'lib/nifti/stream.rb', line 200

def encode(value, type)
  value = [value] unless value.is_a?(Array)
  return value.pack(vr_to_str(type))
end

#encode_string_to_length(string, target_length, pad = :null) ⇒ Object

Appends a string with trailling spaces to achieve a target length, and encodes it to a binary string. Returns the binary string. Raises an error if pad option is different than :null or :spaces

Parameters

  • string ??? A string to be processed.

  • target_length ??? Fixnum. The target length of the string that is created.

  • pad ??? Type of desired padding, either :null or :spaces



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/nifti/stream.rb', line 214

def encode_string_to_length(string, target_length, pad = :null)
  if pad == :spaces
    template = "A#{target_length}"
  elsif pad == :null
    template = "a#{target_length}"
  else
    raise StandardError, "Could not identify padding type #{pad}"
  end
  
  length = string.length
  if length < target_length
    return [string].pack(template)
  elsif length == target_length
    return [string].pack(@str)
  else
    raise "The specified string is longer than the allowed maximum length (String: #{string}, Target length: #{target_length})."
  end
end

#lengthObject

Returns the length of the binary instance string.



85
86
87
# File 'lib/nifti/stream.rb', line 85

def length
  return @string.length
end

#resetObject

Resets the instance string and index.



105
106
107
108
# File 'lib/nifti/stream.rb', line 105

def reset
  @string = ""
  @index = 0
end

#reset_indexObject

Resets the instance index.



112
113
114
# File 'lib/nifti/stream.rb', line 112

def reset_index
  @index = 0
end

#rest_lengthObject

Calculates and returns the remaining length of the instance string (from the index position).



91
92
93
94
# File 'lib/nifti/stream.rb', line 91

def rest_length
  length = @string.length - @index
  return length
end

#rest_stringObject

Extracts and returns the remaining part of the instance string (from the index position to the end of the string).



98
99
100
101
# File 'lib/nifti/stream.rb', line 98

def rest_string
  str = @string[@index..(@string.length-1)]
  return str
end

#set_file(file) ⇒ Object

Sets an instance file variable.

Notes

For performance reasons, we enable the Stream instance to write directly to file, to avoid expensive string operations which will otherwise slow down the write performance.

Parameters

  • file ??? A File instance.



127
128
129
# File 'lib/nifti/stream.rb', line 127

def set_file(file)
  @file = file
end

#set_string(binary) ⇒ Object

Sets a new instance string, and resets the index variable.

Parameters

  • binary ??? A binary string.



137
138
139
140
141
# File 'lib/nifti/stream.rb', line 137

def set_string(binary)
  binary = binary[0] if binary.is_a?(Array)
  @string = binary
  @index = 0
end

#skip(offset) ⇒ Object

Applies an offset (positive or negative) to the instance index.

Parameters

  • offset ??? Fixnum. The length to skip (positive) or rewind (negative).



149
150
151
# File 'lib/nifti/stream.rb', line 149

def skip(offset)
  @index += offset
end

#vr_to_str(vr) ⇒ Object

Converts a data type/vr to an encode/decode string used by the pack/unpack methods, which is returned.

Parameters

  • vr ??? String. A data type (value representation).



159
160
161
162
163
164
165
166
# File 'lib/nifti/stream.rb', line 159

def vr_to_str(vr)
  unless @format[vr]
    errors << "Warning: Element type #{vr} does not have a reading method assigned to it. Something is not implemented correctly or the DICOM data analyzed is invalid."
    return @hex
  else
    return @format[vr]
  end
end

#write(binary) ⇒ Object

Writes a binary string to the File instance.

Parameters

  • binary ??? A binary string.



189
190
191
# File 'lib/nifti/stream.rb', line 189

def write(binary)
  @file.write(binary)
end