Module: Id3Taginator::Extensions::Encodable

Included in:
Frames::Id3v2Frame, Id3v1Tag
Defined in:
lib/id3taginator/extensions/encodable.rb

Constant Summary collapse

ZERO =
"\x00"
UNICODE_ZERO =
"\x00\x00"
ISO8859_1 =
0x00
UTF_16 =
0x01
UTF_16BE =
0x02
UTF_8 =
0x03

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



6
7
8
# File 'lib/id3taginator/extensions/encodable.rb', line 6

def self.included(base)
  base.extend(self)
end

Instance Method Details

#decode(str, source_encoding = @options.default_encode_dest) ⇒ String

decodes the given String from the default destination decoding to the given source encoding

Parameters:

  • str (String)

    the String to decode

  • source_encoding (Encoding) (defaults to: @options.default_encode_dest)

    the result encoding

Returns:

  • (String)

    the decoded String



141
142
143
144
# File 'lib/id3taginator/extensions/encodable.rb', line 141

def decode(str, source_encoding = @options.default_encode_dest)
  result = encode_string(str, source_encoding, @options.default_decode_dest)
  remove_trailing_zeros(result)
end

#decode_using_encoding_byte(str) ⇒ String

decodes the given string using the encoding byte (first byte of the string)

Parameters:

  • str (String)

    String to decode using the first byte to determine the encoding

Returns:

  • (String)

    the decoded String

Raises:



106
107
108
109
110
111
112
113
114
# File 'lib/id3taginator/extensions/encodable.rb', line 106

def decode_using_encoding_byte(str)
  encoding_byte = str[0]&.bytes&.first
  raise Errors::Id3TagError, "Could not find encoding byte for String: #{str}" if encoding_byte.nil?

  encoding = find_encoding(encoding_byte)

  # noinspection RubyMismatchedParameterType
  decode(str[1..-1], encoding)
end

#default_encoding_destination_byteString

returns the default destination encoding byte

Returns:

  • (String)

    the String representation of the default destination encoding byte



70
71
72
# File 'lib/id3taginator/extensions/encodable.rb', line 70

def default_encoding_destination_byte
  [find_encoding_byte(@options.default_encode_dest)].pack('C*')
end

#encode(str, source_encoding = @options.default_decode_dest, null_terminated: false) ⇒ String

encodes the given String from the default destination encoding to the given source encoding

Parameters:

  • str (String)

    the String to decode

  • source_encoding (Encoding) (defaults to: @options.default_decode_dest)

    the result encoding

Returns:

  • (String)

    the encoded String



152
153
154
# File 'lib/id3taginator/extensions/encodable.rb', line 152

def encode(str, source_encoding = @options.default_decode_dest, null_terminated: false)
  encode_string(str, source_encoding, @options.default_encode_dest, null_terminated: null_terminated)
end

#encode_and_add_encoding_byte(str, source_encoding = @options.default_decode_dest, dest_encoding = @options.default_encode_dest) ⇒ String

encode the given String from source encoding to destination encoding and adds the destination encoding byte as the first byte

Parameters:

  • str (String)

    the String to encode

  • source_encoding (Encoding) (defaults to: @options.default_decode_dest)

    the source encoding

  • dest_encoding (Encoding) (defaults to: @options.default_encode_dest)

    the destination encoding

Returns:

  • (String)

    the encoded String with the encoding byte as first byte



124
125
126
127
128
129
130
131
132
133
# File 'lib/id3taginator/extensions/encodable.rb', line 124

def encode_and_add_encoding_byte(str, source_encoding = @options.default_decode_dest,
                                 dest_encoding = @options.default_encode_dest)
  encoding_byte = find_encoding_byte(dest_encoding)
  result = encode_string(str, source_encoding, dest_encoding)
  result = remove_trailing_zeros(result)
  bytes = result.bytes
  bytes.unshift(encoding_byte)

  bytes.flatten.pack('C*')
end

#encode_string(str, source_encoding, dest_encoding, null_terminated: false) ⇒ String

encodes the given String from source to destination encoding and optionally adds a null termination byte(s)

Parameters:

  • str (String)

    the String to encode

  • source_encoding (Encoding)

    source encoding

  • dest_encoding (Encoding)

    destination encoding

  • null_terminated (Boolean) (defaults to: false)

    true, if null termination byte(s) should be added

Returns:

  • (String)

    the encoded String and if requested, added null termination byte(s)



164
165
166
167
168
169
170
171
# File 'lib/id3taginator/extensions/encodable.rb', line 164

def encode_string(str, source_encoding, dest_encoding, null_terminated: false)
  if str.empty? && null_terminated && dest_encoding != Encoding::ISO8859_1
    return [0xFE, 0xFF, 0x00, 0x00].pack('C*')
  end

  res = str.encode(dest_encoding, source_encoding)
  null_terminated ? merge(res, zero_byte(dest_encoding)) : res
end

#find_encoding(encoding_byte) ⇒ Encoding

finds the encoding for the given encoding Byte

Parameters:

  • encoding_byte (Integer)

    the encoding byte

Returns:

  • (Encoding)

    the encoding for this encoding byte



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/id3taginator/extensions/encodable.rb', line 52

def find_encoding(encoding_byte)
  case encoding_byte
  when ISO8859_1
    Encoding::ISO8859_1
  when UTF_8
    Encoding::UTF_8
  when UTF_16
    Encoding::UTF_16
  when UTF_16BE
    Encoding::UTF_16BE
  else
    raise Errors::Id3TagError, "#{encoding_byte} is not a valid encoding bit."
  end
end

#find_encoding_byte(encoding) ⇒ Integer

finds the encoding byte for the given encoding

Parameters:

  • encoding (Encoding)

    the encoding

Returns:

  • (Integer)

    the encoding byte for this encoding



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/id3taginator/extensions/encodable.rb', line 32

def find_encoding_byte(encoding)
  case encoding
  when Encoding::ISO8859_1
    ISO8859_1
  when Encoding::UTF_8
    UTF_8
  when Encoding::UTF_16
    UTF_16
  when Encoding::UTF_16BE
    UTF_16BE
  else
    raise Errors::Id3TagError, "#{encoding} is not a valid encoding."
  end
end

#merge(*str) ⇒ String

merges the given string representing a byte array to a String representation of the merged byte arrays

Parameters:

  • str (Array<String>)

    byte arrays represented as a String to merge

Returns:

  • (String)

    String representation of the merged byte arrays (str.bytes)



97
98
99
# File 'lib/id3taginator/extensions/encodable.rb', line 97

def merge(*str)
  str.inject([]) { |sum, x| sum + x.bytes }.pack('C*')
end

#pad_left(str, padding_to, char = 0.chr) ⇒ String

pads the given String with X chars to the left

Parameters:

  • str (String)

    the String to pad

  • padding_to (Integer)

    pad until length of

  • char (String) (defaults to: 0.chr)

    the char to use to pad

Returns:

  • (String)

    the padded String



197
198
199
200
# File 'lib/id3taginator/extensions/encodable.rb', line 197

def pad_left(str, padding_to, char = 0.chr)
  str ||= ''
  str.ljust(padding_to, char)
end

#pad_right(str, padding_to, char = 0.chr) ⇒ String

pads the given String with X chars to the right

Parameters:

  • str (String)

    the String to pad

  • padding_to (Integer)

    pad until length of

  • char (String) (defaults to: 0.chr)

    the char to use to pad

Returns:

  • (String)

    the padded String



209
210
211
212
# File 'lib/id3taginator/extensions/encodable.rb', line 209

def pad_right(str, padding_to, char = 0.chr)
  str ||= ''
  str.rjust(padding_to, char)
end

#read_stream_until(stream, until_bytes) ⇒ String

reads the given stream until the byte combination is found

Parameters:

  • stream (StringIO, IO, File)

    the stream

  • until_bytes (String)

    read stream until this combination is found

Returns:

  • (String)

    String representation of the bytes array that is read



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/id3taginator/extensions/encodable.rb', line 80

def read_stream_until(stream, until_bytes)
  result = []
  size = until_bytes.length
  until (read = stream.read(size)).nil?
    break if read == until_bytes

    result << read&.bytes
  end

  result.flatten.pack('C*')
end

#remove_trailing_zeros(str) ⇒ String

removes trailing zero bytes if present

Parameters:

  • str (String)

    the string to remove the trailing zeros if present

Returns:

  • (String)

    the String without trailing zeros



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/id3taginator/extensions/encodable.rb', line 178

def remove_trailing_zeros(str)
  return str if str.empty?

  last = str.bytes.last
  while last&.zero?
    str.chop!
    last = str.bytes.last
  end

  str
end

#zero_byte(encoding = @options.default_encode_dest) ⇒ String

returns the ZERO byte depending of the given encoding, so 0x00 0x00 for Unicode, else 0x00

Parameters:

  • encoding (Encoding) (defaults to: @options.default_encode_dest)

    the encoding to determine the zero byte(s)

Returns:

  • (String)

    the zero byte(s) String



23
24
25
# File 'lib/id3taginator/extensions/encodable.rb', line 23

def zero_byte(encoding = @options.default_encode_dest)
  encoding == Encoding::ISO8859_1 ? ZERO : UNICODE_ZERO
end