Module: Fontisan::Woff2::UInt255

Defined in:
lib/fontisan/woff2/uint255.rb

Overview

255UInt16 variable-length encoding per WOFF2 spec section 3.1.

Single source of truth for encoding and decoding this data type. All other WOFF2 code MUST delegate to this module — the previous inline copies had the code-byte mapping inverted for values ≥ 253.

Encoding table (per W3C spec pseudocode):

value range     | encoding              | bytes
----------------|-----------------------|------
0 .. 252        | literal              | 1
253 .. 505      | code 255 + (v - 253) | 2
506 .. 761      | code 254 + (v - 506) | 2
762 .. 65535    | code 253 + uint16    | 3

Decoding (inverse):

code byte | meaning
----------|--------------------------------
0 .. 252  | literal value
253       | read uint16 → value
254       | read 1 byte → value + 506
255       | read 1 byte → value + 253

Constant Summary collapse

WORD_CODE =
253
ONE_MORE_BYTE_CODE1 =

adds 253

255
ONE_MORE_BYTE_CODE2 =

adds 506

254
MAX_VALUE =
65_535

Class Method Summary collapse

Class Method Details

.decode(io) ⇒ Integer?

Decode a 255UInt16 value from an IO stream. Reads 1-3 bytes.

Parameters:

  • io (IO, StringIO)

    input stream positioned at the code byte

Returns:

  • (Integer, nil)

    decoded value, or nil if the stream is empty



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/fontisan/woff2/uint255.rb', line 62

def self.decode(io)
  code = io.read(1)&.unpack1("C")
  return nil unless code

  case code
  when 0..252
    code
  when WORD_CODE
    io.read(2)&.unpack1("n")
  when ONE_MORE_BYTE_CODE2
    506 + (io.read(1)&.unpack1("C") || 0)
  when ONE_MORE_BYTE_CODE1
    253 + (io.read(1)&.unpack1("C") || 0)
  end
end

.decode_at(data, pos) ⇒ Array(Integer, Integer)

Decode from a binary String at a given position. Returns the value and the new cursor position. Used by callers that index into a flat String rather than wrapping it in a StringIO.

Parameters:

  • data (String)

    binary data

  • pos (Integer)

    byte offset of the code byte

Returns:

  • (Array(Integer, Integer))

    [value, new_pos]



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/fontisan/woff2/uint255.rb', line 85

def self.decode_at(data, pos)
  code = data.getbyte(pos)
  pos += 1
  case code
  when 0..252
    [code, pos]
  when WORD_CODE
    [data[pos, 2].unpack1("n"), pos + 2]
  when ONE_MORE_BYTE_CODE2
    [506 + data.getbyte(pos), pos + 1]
  when ONE_MORE_BYTE_CODE1
    [253 + data.getbyte(pos), pos + 1]
  end
end

.encode(value) ⇒ String

Encode a value (0..65535) into a 1-3 byte binary string.

Parameters:

  • value (Integer)

Returns:

  • (String)

    binary-encoded bytes

Raises:

  • (ArgumentError)

    if value is out of range



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/fontisan/woff2/uint255.rb', line 42

def self.encode(value)
  case value
  when 0..252
    [value].pack("C")
  when 253..505
    [ONE_MORE_BYTE_CODE1, value - 253].pack("C*")
  when 506..761
    [ONE_MORE_BYTE_CODE2, value - 506].pack("C*")
  when 762..MAX_VALUE
    [WORD_CODE].pack("C") + [value].pack("n")
  else
    raise ArgumentError,
          "255UInt16 requires 0 <= value <= #{MAX_VALUE}, got #{value}"
  end
end