ruby/lib/yarp/pack.rb
Jemma Issroff cc7f765f2c [Feature #19741] Sync all files in yarp
This commit is the initial sync of all files from ruby/yarp
into ruby/ruby. Notably, it does the following:

* Sync all ruby/yarp/lib/ files to ruby/ruby/lib/yarp
* Sync all ruby/yarp/src/ files to ruby/ruby/yarp/
* Sync all ruby/yarp/test/ files to ruby/ruby/test/yarp
2023-06-21 11:25:39 -07:00

186 lines
4.5 KiB
Ruby

# frozen_string_literal: true
module YARP
module Pack
%i[
SPACE
COMMENT
INTEGER
UTF8
BER
FLOAT
STRING_SPACE_PADDED
STRING_NULL_PADDED
STRING_NULL_TERMINATED
STRING_MSB
STRING_LSB
STRING_HEX_HIGH
STRING_HEX_LOW
STRING_UU
STRING_MIME
STRING_BASE64
STRING_FIXED
STRING_POINTER
MOVE
BACK
NULL
UNSIGNED
SIGNED
SIGNED_NA
AGNOSTIC_ENDIAN
LITTLE_ENDIAN
BIG_ENDIAN
NATIVE_ENDIAN
ENDIAN_NA
SIZE_SHORT
SIZE_INT
SIZE_LONG
SIZE_LONG_LONG
SIZE_8
SIZE_16
SIZE_32
SIZE_64
SIZE_P
SIZE_NA
LENGTH_FIXED
LENGTH_MAX
LENGTH_RELATIVE
LENGTH_NA
].each do |const|
const_set(const, const)
end
class Directive
attr_reader :version, :variant, :source, :type, :signed, :endian, :size, :length_type, :length
def initialize(version, variant, source, type, signed, endian, size, length_type, length)
@version = version
@variant = variant
@source = source
@type = type
@signed = signed
@endian = endian
@size = size
@length_type = length_type
@length = length
end
ENDIAN_DESCRIPTIONS = {
AGNOSTIC_ENDIAN: 'agnostic',
LITTLE_ENDIAN: 'little-endian (VAX)',
BIG_ENDIAN: 'big-endian (network)',
NATIVE_ENDIAN: 'native-endian',
ENDIAN_NA: 'n/a'
}
SIGNED_DESCRIPTIONS = {
UNSIGNED: 'unsigned',
SIGNED: 'signed',
SIGNED_NA: 'n/a'
}
SIZE_DESCRIPTIONS = {
SIZE_SHORT: 'short',
SIZE_INT: 'int-width',
SIZE_LONG: 'long',
SIZE_LONG_LONG: 'long long',
SIZE_8: '8-bit',
SIZE_16: '16-bit',
SIZE_32: '32-bit',
SIZE_64: '64-bit',
SIZE_P: 'pointer-width'
}
def describe
case type
when SPACE
'whitespace'
when COMMENT
'comment'
when INTEGER
if size == SIZE_8
base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} integer"
else
base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} integer"
end
case length_type
when LENGTH_FIXED
if length > 1
base + ", x#{length}"
else
base
end
when LENGTH_MAX
base + ', as many as possible'
end
when UTF8
'UTF-8 character'
when BER
'BER-compressed integer'
when FLOAT
"#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float"
when STRING_SPACE_PADDED
'arbitrary binary string (space padded)'
when STRING_NULL_PADDED
'arbitrary binary string (null padded, count is width)'
when STRING_NULL_TERMINATED
'arbitrary binary string (null padded, count is width), except that null is added with *'
when STRING_MSB
'bit string (MSB first)'
when STRING_LSB
'bit string (LSB first)'
when STRING_HEX_HIGH
'hex string (high nibble first)'
when STRING_HEX_LOW
'hex string (low nibble first)'
when STRING_UU
'UU-encoded string'
when STRING_MIME
'quoted printable, MIME encoding'
when STRING_BASE64
'base64 encoded string'
when STRING_FIXED
'pointer to a structure (fixed-length string)'
when STRING_POINTER
'pointer to a null-terminated string'
when MOVE
'move to absolute position'
when BACK
'back up a byte'
when NULL
'null byte'
else
raise
end
end
end
class Format
attr_reader :directives, :encoding
def initialize(directives, encoding)
@directives = directives
@encoding = encoding
end
def describe
source_width = directives.map { |d| d.source.inspect.length }.max
directive_lines = directives.map do |directive|
if directive.type == SPACE
source = directive.source.inspect
else
source = directive.source
end
" #{source.ljust(source_width)} #{directive.describe}"
end
(['Directives:'] + directive_lines + ['Encoding:', " #{encoding}"]).join("\n")
end
end
end
end