kaitai-struct 0.8 → 0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE +21 -0
- data/README.md +7 -27
- data/lib/kaitai/struct/struct.rb +185 -28
- metadata +11 -10
- data/.gitignore +0 -1
- data/kaitai-struct.gemspec +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cbdd2b873476556b609d64f78e10c3ef35ea5ede048ac5ee57a03a24f523bfac
|
4
|
+
data.tar.gz: db41f46711b11efcf12a982e282181ae20d25831f408b7a3e7e668791f14701b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea4b2780d4efa7c645175957059073f6506ee5e39d2525b62f7a5de41816d0115dde2980948ab47e8994b1a7fc97cb94e8fab7692882244fc7d9b58b18b3e8b3
|
7
|
+
data.tar.gz: 99cec16629be56c07b1df24f4a091fbffdd6240341dc0130ef6a5d04195a91c37d6238c4991ba3782667514cf25ae7746aa2fdd3aa307c34352c0dd0698ea4c9
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2015-2022 Kaitai Project
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Kaitai Struct: runtime library for Ruby
|
2
2
|
|
3
|
+
[![Gem version](https://img.shields.io/gem/v/kaitai-struct)](https://rubygems.org/gems/kaitai-struct/)
|
4
|
+
[![Gem downloads](https://img.shields.io/gem/dt/kaitai-struct)](https://rubygems.org/gems/kaitai-struct/#:~:text=TOTAL%20DOWNLOADS)
|
5
|
+
|
3
6
|
This library implements Kaitai Struct API for Ruby.
|
4
7
|
|
5
8
|
Kaitai Struct is a declarative language used for describe various binary
|
@@ -35,30 +38,7 @@ to install this runtime library.
|
|
35
38
|
|
36
39
|
### Manually
|
37
40
|
|
38
|
-
This library is intentionally kept as very simple, one
|
39
|
-
|
40
|
-
|
41
|
-
by Ruby source code
|
42
|
-
|
43
|
-
## Licensing
|
44
|
-
|
45
|
-
Copyright 2015-2017 Kaitai Project: MIT license
|
46
|
-
|
47
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
-
a copy of this software and associated documentation files (the
|
49
|
-
"Software"), to deal in the Software without restriction, including
|
50
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
-
permit persons to whom the Software is furnished to do so, subject to
|
53
|
-
the following conditions:
|
54
|
-
|
55
|
-
The above copyright notice and this permission notice shall be
|
56
|
-
included in all copies or substantial portions of the Software.
|
57
|
-
|
58
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
59
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
61
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
62
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
63
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
64
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
41
|
+
This library is intentionally kept as very simple, one `.rb` file.
|
42
|
+
You can just copy it to your project from [this repository](https://github.com/kaitai-io/kaitai_struct_ruby_runtime).
|
43
|
+
Usually you won't `require` it directly, it will be loaded
|
44
|
+
by Ruby source code generated by Kaitai Struct compiler.
|
data/lib/kaitai/struct/struct.rb
CHANGED
@@ -3,7 +3,7 @@ require 'stringio'
|
|
3
3
|
module Kaitai
|
4
4
|
module Struct
|
5
5
|
|
6
|
-
VERSION = '0.
|
6
|
+
VERSION = '0.10'
|
7
7
|
|
8
8
|
##
|
9
9
|
# Common base class for all structured generated by Kaitai Struct.
|
@@ -60,9 +60,8 @@ end
|
|
60
60
|
|
61
61
|
##
|
62
62
|
# Kaitai::Struct::Stream is an implementation of
|
63
|
-
# {https://
|
64
|
-
#
|
65
|
-
# for generic IO objects.
|
63
|
+
# {Kaitai Stream API}[https://doc.kaitai.io/stream_api.html] for Ruby.
|
64
|
+
# It's implemented as a wrapper for generic IO objects.
|
66
65
|
#
|
67
66
|
# It provides a wide variety of simple methods to read (parse) binary
|
68
67
|
# representations of primitive types, such as integer and floating
|
@@ -77,6 +76,9 @@ end
|
|
77
76
|
# and API to do the actual parsing job.
|
78
77
|
class Stream
|
79
78
|
##
|
79
|
+
# Unused since Kaitai Struct Compiler v0.9+ - compatibility with
|
80
|
+
# older versions.
|
81
|
+
#
|
80
82
|
# Exception class for an error that occurs when some fixed content
|
81
83
|
# was expected to appear, but actual data read was different.
|
82
84
|
class UnexpectedDataError < Exception
|
@@ -87,12 +89,6 @@ class Stream
|
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
90
|
-
##
|
91
|
-
# Error that occurs when default endianness should be decided with
|
92
|
-
# a switch, but nothing matches (although using endianness expression
|
93
|
-
# implies that there should be some positive result).
|
94
|
-
class UndecidedEndiannessError < Exception
|
95
|
-
end
|
96
92
|
|
97
93
|
##
|
98
94
|
# Constructs new Kaitai Stream object.
|
@@ -117,6 +113,12 @@ class Stream
|
|
117
113
|
self.new(File.open(filename, 'rb:ASCII-8BIT'))
|
118
114
|
end
|
119
115
|
|
116
|
+
##
|
117
|
+
# Closes underlying IO object.
|
118
|
+
def close
|
119
|
+
@_io.close
|
120
|
+
end
|
121
|
+
|
120
122
|
# Test endianness of the platform
|
121
123
|
@@big_endian = [0x0102].pack('s') == [0x0102].pack('n')
|
122
124
|
|
@@ -125,7 +127,7 @@ class Stream
|
|
125
127
|
##
|
126
128
|
# Check if stream pointer is at the end of stream.
|
127
129
|
# @return [true, false] true if we are located at the end of the stream
|
128
|
-
def eof?; @_io.eof
|
130
|
+
def eof?; @_io.eof? and @bits_left == 0; end
|
129
131
|
|
130
132
|
##
|
131
133
|
# Set stream pointer to designated position.
|
@@ -289,36 +291,72 @@ class Stream
|
|
289
291
|
@bits = 0
|
290
292
|
end
|
291
293
|
|
292
|
-
def
|
294
|
+
def read_bits_int_be(n)
|
295
|
+
res = 0
|
296
|
+
|
293
297
|
bits_needed = n - @bits_left
|
298
|
+
@bits_left = -bits_needed % 8
|
299
|
+
|
294
300
|
if bits_needed > 0
|
295
301
|
# 1 bit => 1 byte
|
296
302
|
# 8 bits => 1 byte
|
297
303
|
# 9 bits => 2 bytes
|
298
|
-
bytes_needed = ((bits_needed - 1) / 8) + 1
|
304
|
+
bytes_needed = ((bits_needed - 1) / 8) + 1 # `ceil(bits_needed / 8)`
|
299
305
|
buf = read_bytes(bytes_needed)
|
300
306
|
buf.each_byte { |byte|
|
301
|
-
|
302
|
-
@bits |= byte
|
303
|
-
@bits_left += 8
|
307
|
+
res = res << 8 | byte
|
304
308
|
}
|
309
|
+
|
310
|
+
new_bits = res
|
311
|
+
res = res >> @bits_left | @bits << bits_needed
|
312
|
+
@bits = new_bits # will be masked at the end of the function
|
313
|
+
else
|
314
|
+
res = @bits >> -bits_needed # shift unneeded bits out
|
305
315
|
end
|
306
316
|
|
307
|
-
|
308
|
-
mask = (1 << n) - 1
|
309
|
-
# shift mask to align with highest bits available in @bits
|
310
|
-
shift_bits = @bits_left - n
|
311
|
-
mask <<= shift_bits
|
312
|
-
# derive reading result
|
313
|
-
res = (@bits & mask) >> shift_bits
|
314
|
-
# clear top bits that we've just read => AND with 1s
|
315
|
-
@bits_left -= n
|
316
|
-
mask = (1 << @bits_left) - 1
|
317
|
+
mask = (1 << @bits_left) - 1 # `@bits_left` is in range 0..7
|
317
318
|
@bits &= mask
|
318
319
|
|
319
320
|
res
|
320
321
|
end
|
321
322
|
|
323
|
+
# Unused since Kaitai Struct Compiler v0.9+ - compatibility with
|
324
|
+
# older versions.
|
325
|
+
def read_bits_int(n)
|
326
|
+
read_bits_int_be(n)
|
327
|
+
end
|
328
|
+
|
329
|
+
def read_bits_int_le(n)
|
330
|
+
res = 0
|
331
|
+
bits_needed = n - @bits_left
|
332
|
+
|
333
|
+
if bits_needed > 0 then
|
334
|
+
# 1 bit => 1 byte
|
335
|
+
# 8 bits => 1 byte
|
336
|
+
# 9 bits => 2 bytes
|
337
|
+
bytes_needed = ((bits_needed - 1) / 8) + 1 # `ceil(bits_needed / 8)`
|
338
|
+
buf = read_bytes(bytes_needed)
|
339
|
+
i = 0
|
340
|
+
buf.each_byte { |byte|
|
341
|
+
res |= byte << (i * 8)
|
342
|
+
i += 1
|
343
|
+
}
|
344
|
+
|
345
|
+
new_bits = res >> bits_needed
|
346
|
+
res = res << @bits_left | @bits
|
347
|
+
@bits = new_bits
|
348
|
+
else
|
349
|
+
res = @bits
|
350
|
+
@bits >>= n
|
351
|
+
end
|
352
|
+
|
353
|
+
@bits_left = -bits_needed % 8
|
354
|
+
|
355
|
+
mask = (1 << n) - 1 # no problem with this in Ruby (arbitrary precision integers)
|
356
|
+
res &= mask
|
357
|
+
return res
|
358
|
+
end
|
359
|
+
|
322
360
|
# @!endgroup
|
323
361
|
|
324
362
|
# @!group Byte arrays
|
@@ -368,6 +406,9 @@ class Stream
|
|
368
406
|
end
|
369
407
|
|
370
408
|
##
|
409
|
+
# Unused since Kaitai Struct Compiler v0.9+ - compatibility with
|
410
|
+
# older versions.
|
411
|
+
#
|
371
412
|
# Reads next len bytes from the stream and ensures that they match
|
372
413
|
# expected fixed byte array. If they differ, throws a
|
373
414
|
# {UnexpectedDataError} runtime exception.
|
@@ -493,8 +534,124 @@ class Stream
|
|
493
534
|
(x & ~mask) - (x & mask)
|
494
535
|
end
|
495
536
|
|
496
|
-
def self.format_hex(
|
497
|
-
|
537
|
+
def self.format_hex(bytes)
|
538
|
+
bytes.unpack('H*')[0].gsub(/(..)/, '\1 ').chop
|
539
|
+
end
|
540
|
+
|
541
|
+
###
|
542
|
+
# Guess if the given args are most likely byte arrays.
|
543
|
+
# <p>
|
544
|
+
# There's no way to know for sure, but {@code Encoding::ASCII_8BIT} is a special encoding that is
|
545
|
+
# usually used for a byte array(/string), not a character string. For those reasons, that encoding
|
546
|
+
# is NOT planned to be allowed for human readable texts by KS in general as well.
|
547
|
+
# </p>
|
548
|
+
# @param args [...] Something to check.
|
549
|
+
# @see <a href="https://ruby-doc.org/core-3.0.0/Encoding.html">Encoding</a>
|
550
|
+
# @see <a href="https://github.com/kaitai-io/kaitai_struct/issues/116">List of supported encodings</a>
|
551
|
+
#
|
552
|
+
def self.is_byte_array?(*args)
|
553
|
+
args.all? { |arg| arg.is_a?(String) and (arg.encoding == Encoding::ASCII_8BIT) }
|
554
|
+
end
|
555
|
+
|
556
|
+
def self.inspect_values(*args)
|
557
|
+
reprs = args.map { |arg|
|
558
|
+
if Stream.is_byte_array?(arg)
|
559
|
+
"[#{Stream.format_hex(arg)}]"
|
560
|
+
else
|
561
|
+
arg.inspect
|
562
|
+
end
|
563
|
+
}
|
564
|
+
reprs.length == 1 ? reprs[0] : reprs
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
##
|
569
|
+
# Common ancestor for all error originating from Kaitai Struct usage.
|
570
|
+
# Stores KSY source path, pointing to an element supposedly guilty of
|
571
|
+
# an error.
|
572
|
+
class KaitaiStructError < Exception
|
573
|
+
def initialize(msg, src_path)
|
574
|
+
super("#{src_path}: #{msg}")
|
575
|
+
@src_path = src_path
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
##
|
580
|
+
# Error that occurs when default endianness should be decided with
|
581
|
+
# a switch, but nothing matches (although using endianness expression
|
582
|
+
# implies that there should be some positive result).
|
583
|
+
class UndecidedEndiannessError < KaitaiStructError
|
584
|
+
def initialize(src_path)
|
585
|
+
super("unable to decide on endianness for a type", src_path)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
##
|
590
|
+
# Common ancestor for all validation failures. Stores pointer to
|
591
|
+
# KaitaiStream IO object which was involved in an error.
|
592
|
+
class ValidationFailedError < KaitaiStructError
|
593
|
+
def initialize(msg, io, src_path)
|
594
|
+
super("at pos #{io.pos}: validation failed: #{msg}", src_path)
|
595
|
+
@io = io
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
##
|
600
|
+
# Signals validation failure: we required "actual" value to be equal to
|
601
|
+
# "expected", but it turned out that it's not.
|
602
|
+
class ValidationNotEqualError < ValidationFailedError
|
603
|
+
def initialize(expected, actual, io, src_path)
|
604
|
+
expected_repr, actual_repr = Stream.inspect_values(expected, actual)
|
605
|
+
super("not equal, expected #{expected_repr}, but got #{actual_repr}", io, src_path)
|
606
|
+
|
607
|
+
@expected = expected
|
608
|
+
@actual = actual
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
##
|
613
|
+
# Signals validation failure: we required "actual" value to be greater
|
614
|
+
# than or equal to "min", but it turned out that it's not.
|
615
|
+
class ValidationLessThanError < ValidationFailedError
|
616
|
+
def initialize(min, actual, io, src_path)
|
617
|
+
min_repr, actual_repr = Stream.inspect_values(min, actual)
|
618
|
+
super("not in range, min #{min_repr}, but got #{actual_repr}", io, src_path)
|
619
|
+
@min = min
|
620
|
+
@actual = actual
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
##
|
625
|
+
# Signals validation failure: we required "actual" value to be less
|
626
|
+
# than or equal to "max", but it turned out that it's not.
|
627
|
+
class ValidationGreaterThanError < ValidationFailedError
|
628
|
+
def initialize(max, actual, io, src_path)
|
629
|
+
max_repr, actual_repr = Stream.inspect_values(max, actual)
|
630
|
+
super("not in range, max #{max_repr}, but got #{actual_repr}", io, src_path)
|
631
|
+
@max = max
|
632
|
+
@actual = actual
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
##
|
637
|
+
# Signals validation failure: we required "actual" value to be any of
|
638
|
+
# the given list, but it turned out that it's not.
|
639
|
+
class ValidationNotAnyOfError < ValidationFailedError
|
640
|
+
def initialize(actual, io, src_path)
|
641
|
+
actual_repr = Stream.inspect_values(actual)
|
642
|
+
super("not any of the list, got #{actual_repr}", io, src_path)
|
643
|
+
@actual = actual
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
##
|
648
|
+
# Signals validation failure: we required "actual" value to match
|
649
|
+
# the expression, but it turned out that it doesn't.
|
650
|
+
class ValidationExprError < ValidationFailedError
|
651
|
+
def initialize(actual, io, src_path)
|
652
|
+
actual_repr = Stream.inspect_values(actual)
|
653
|
+
super("not matching the expression, got #{actual_repr}", io, src_path)
|
654
|
+
@actual = actual
|
498
655
|
end
|
499
656
|
end
|
500
657
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kaitai-struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.10'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikhail Yakshin
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
Kaitai Struct is a declarative language used for describe various binary data structures, laid out in files or in memory: i.e. binary file formats, network stream packet formats, etc.
|
@@ -21,15 +21,17 @@ executables: []
|
|
21
21
|
extensions: []
|
22
22
|
extra_rdoc_files: []
|
23
23
|
files:
|
24
|
-
-
|
24
|
+
- LICENSE
|
25
25
|
- README.md
|
26
|
-
- kaitai-struct.gemspec
|
27
26
|
- lib/kaitai/struct/struct.rb
|
28
27
|
homepage: http://kaitai.io
|
29
28
|
licenses:
|
30
29
|
- MIT
|
31
|
-
metadata:
|
32
|
-
|
30
|
+
metadata:
|
31
|
+
bug_tracker_uri: https://github.com/kaitai-io/kaitai_struct_ruby_runtime/issues
|
32
|
+
homepage_uri: http://kaitai.io
|
33
|
+
source_code_uri: https://github.com/kaitai-io/kaitai_struct_ruby_runtime
|
34
|
+
post_install_message:
|
33
35
|
rdoc_options: []
|
34
36
|
require_paths:
|
35
37
|
- lib
|
@@ -44,9 +46,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
46
|
- !ruby/object:Gem::Version
|
45
47
|
version: '0'
|
46
48
|
requirements: []
|
47
|
-
|
48
|
-
|
49
|
-
signing_key:
|
49
|
+
rubygems_version: 3.3.17
|
50
|
+
signing_key:
|
50
51
|
specification_version: 4
|
51
52
|
summary: 'Kaitai Struct: runtime library for Ruby'
|
52
53
|
test_files: []
|
data/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
*.gem
|
data/kaitai-struct.gemspec
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require File.expand_path("../lib/kaitai/struct/struct", __FILE__)
|
4
|
-
require 'date'
|
5
|
-
|
6
|
-
Gem::Specification.new { |s|
|
7
|
-
s.name = 'kaitai-struct'
|
8
|
-
s.version = Kaitai::Struct::VERSION
|
9
|
-
s.date = Date.today.to_s
|
10
|
-
|
11
|
-
s.authors = ['Mikhail Yakshin']
|
12
|
-
s.email = 'greycat@kaitai.io'
|
13
|
-
|
14
|
-
s.homepage = 'http://kaitai.io'
|
15
|
-
s.summary = 'Kaitai Struct: runtime library for Ruby'
|
16
|
-
s.license = 'MIT'
|
17
|
-
s.description = <<-EOF
|
18
|
-
Kaitai Struct is a declarative language used for describe various binary data structures, laid out in files or in memory: i.e. binary file formats, network stream packet formats, etc.
|
19
|
-
|
20
|
-
The main idea is that a particular format is described in Kaitai Struct language (.ksy file) and then can be compiled with ksc into source files in one of the supported programming languages. These modules will include a generated code for a parser that can read described data structure from a file / stream and give access to it in a nice, easy-to-comprehend API.
|
21
|
-
|
22
|
-
This package provides small runtime library used by code generated by Kaitai Struct compiler.
|
23
|
-
EOF
|
24
|
-
|
25
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
26
|
-
s.require_paths = ['lib']
|
27
|
-
|
28
|
-
s.files = `git ls-files`.split("\n")
|
29
|
-
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
30
|
-
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
31
|
-
}
|