class TTFunk::Table::Cff::Dict
Constants
- MAX_OPERANDS
maximum number of operands allowed per operator
- OPERAND_BZERO
- OPERATOR_BZERO
for regular single-byte operators
- VALID_SCI_EXPONENT_RE
- VALID_SCI_SIGNIFICAND_RE
used to validate operands expressed in scientific notation
- WIDE_OPERATOR_ADJUSTMENT
- WIDE_OPERATOR_BZERO
for operators that are two bytes wide
Public Instance Methods
[](operator)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 30 def [](operator) @dict[operator] end
each(&block)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 34 def each(&block) @dict.each(&block) end
Also aliased as: each_pair
encode()
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 40 def encode map do |(operator, operands)| operands.map { |operand| encode_operand(operand) }.join + encode_operator(operator) end.join end
Private Instance Methods
decode_integer(b_zero)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 236 def decode_integer(b_zero) case b_zero when 32..246 # 1 byte b_zero - 139 when 247..250 # 2 bytes b_one = read(1, 'C').first (b_zero - 247) * 256 + b_one + 108 when 251..254 # 2 bytes b_one = read(1, 'C').first -(b_zero - 251) * 256 - b_one - 108 when 28 # 2 bytes in number (3 total) b_one, b_two = read(2, 'C*') BinUtils.twos_comp_to_int(b_one << 8 | b_two, bit_width: 16) when 29 # 4 bytes in number (5 total) b_one, b_two, b_three, b_four = read(4, 'C*') BinUtils.twos_comp_to_int( b_one << 24 | b_two << 16 | b_three << 8 | b_four, bit_width: 32 ) end end
decode_operand(b_zero)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 172 def decode_operand(b_zero) case b_zero when 30 decode_sci else decode_integer(b_zero) end end
decode_sci()
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 181 def decode_sci significand = ''.b exponent = ''.b loop do current = read(1, 'C').first break if current == 0xFF high_nibble = current >> 4 low_nibble = current & 0x0F # 0b00001111 [high_nibble, low_nibble].each do |nibble| case nibble when 0..9 (exponent.empty? ? significand : exponent) << nibble.to_s when 0xA significand << '.' when 0xB # take advantage of Integer#to_i not caring about whitespace exponent << ' ' when 0xC exponent << '-' when 0xE significand << '-' end end break if low_nibble == 0xF end validate_sci!(significand, exponent) SciForm.new(significand.to_f, exponent.to_i) end
decode_wide_operator()
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 168 def decode_wide_operator WIDE_OPERATOR_ADJUSTMENT + read(1, 'C').first end
encode_exponent(exp)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 106 def encode_exponent(exp) return [] if exp.zero? [exp.positive? ? 0xB : 0xC, *encode_significand(exp.abs)] end
encode_float(float)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 96 def encode_float(float) pack_decimal_nibbles(encode_significand(float)) end
encode_integer(int)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 71 def encode_integer(int) case int when -107..107 [int + 139].pack('C') when 108..1131 int -= 108 [(int >> 8) + 247, int & 0xFF].pack('C*') when -1131..-108 int = -int - 108 [(int >> 8) + 251, int & 0xFF].pack('C*') when -32_768..32_767 [28, (int >> 8) & 0xFF, int & 0xFF].pack('C*') else encode_integer32(int) end end
encode_integer32(int)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 92 def encode_integer32(int) [29, int].pack('CN') end
encode_operand(operand)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 60 def encode_operand(operand) case operand when Integer encode_integer(operand) when Float, BigDecimal encode_float(operand) when SciForm encode_sci(operand) end end
encode_operator(operator)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 49 def encode_operator(operator) if operator >= WIDE_OPERATOR_ADJUSTMENT [ WIDE_OPERATOR_BZERO, operator - WIDE_OPERATOR_ADJUSTMENT ].pack('C*') else [operator].pack('C') end end
encode_sci(sci)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 100 def encode_sci(sci) sig_bytes = encode_significand(sci.significand) exp_bytes = encode_exponent(sci.exponent) pack_decimal_nibbles(sig_bytes + exp_bytes) end
encode_significand(sig)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 112 def encode_significand(sig) sig.to_s.each_char.with_object([]) do |char, ret| case char when '0'..'9' ret << char.to_i when '.' ret << 0xA when '-' ret << 0xE else break ret end end end
pack_decimal_nibbles(nibbles)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 127 def pack_decimal_nibbles(nibbles) bytes = [30] nibbles.each_slice(2).each do |(high_nb, low_nb)| # low_nb can be nil if nibbles contains an odd number of elements low_nb ||= 0xF bytes << (high_nb << 4 | low_nb) end bytes << 0xFF if nibbles.size.even? bytes.pack('C*') end
parse!()
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 140 def parse! @dict = {} operands = [] # @length must be set via the constructor while io.pos < table_offset + length case b_zero = read(1, 'C').first when WIDE_OPERATOR_BZERO operator = decode_wide_operator @dict[operator] = operands operands = [] when OPERATOR_BZERO @dict[b_zero] = operands unless operands.empty? operands = [] when *OPERAND_BZERO operands << decode_operand(b_zero) if operands.size > MAX_OPERANDS raise TooManyOperandsError, 'found one too many operands at '\ "position #{io.pos} in dict at position #{table_offset}" end else raise Error, "dict byte value #{b_zero} is reserved" end end end
valid_exponent?(exponent)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 229 def valid_exponent?(exponent) exponent = exponent.strip return true if exponent.empty? !(exponent.strip =~ VALID_SCI_EXPONENT_RE).nil? end
valid_significand?(significand)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 225 def valid_significand?(significand) !(significand.strip =~ VALID_SCI_SIGNIFICAND_RE).nil? end
validate_sci!(significand, exponent)
click to toggle source
# File lib/ttfunk/table/cff/dict.rb, line 216 def validate_sci!(significand, exponent) unless valid_significand?(significand) && valid_exponent?(exponent) raise InvalidOperandError, 'invalid scientific notation operand with significand '\ "'#{significand}' and exponent '#{exponent}' ending at "\ "position #{io.pos} in dict at position #{table_offset}" end end